public inbox for [email protected]
help / color / mirror / Atom feedFrom: Khushboo Vashi <[email protected]>
To: Dave Page <[email protected]>
Cc: pgadmin-hackers <[email protected]>
Subject: Re: pgAdmin4 PATCH: Domain Module
Date: Wed, 23 Mar 2016 12:48:12 +0530
Message-ID: <CAFOhELc=PzdATON2Eo0sipm7AC9dtz33YZm-CqTfHUNesuUpwA@mail.gmail.com> (raw)
In-Reply-To: <CA+OCxoyRLYFv_SxNNGdsGN=Up7d3WT_EQz0-h9P+S+0oRtjaYg@mail.gmail.com>
References: <CAFOhELf-n8mM4h8RZuqxUs-Z+f97N6Ux5KT6aoAdWFiHVVURyw@mail.gmail.com>
<CAFOhELf-QTMAgNkTT8AsRwJ38Jn_1BSFRV_G5ZmcHnrKmPsTog@mail.gmail.com>
<CACCA4P1caumXOrpEXrrETMuNGj3G3ctY-PN9=V6GUPF=dTBnWg@mail.gmail.com>
<CAFOhELdgb566u+4XXOOP4pDCF4GGzK8JZzLrrTuPt=OprsqG5Q@mail.gmail.com>
<CACCA4P06PrJ2-VodT133sheH1i+7zc_M_y_me6KfRHkLqrQ7gg@mail.gmail.com>
<CAFOhELc1OAz3BDWkKC0e0xA8sPBKiO-4vWJQ7ipMYmKC-C6YzA@mail.gmail.com>
<CACCA4P1uFijfEV6vvETXX=qjafhGZsOacdi7Og+7edaBb4erxA@mail.gmail.com>
<CAFOhELePQ_m8zmbORLmO3PUY5yTA5o_9suQKk0Tox8A7Fb8ovw@mail.gmail.com>
<CAFOhELcq3oiXAC3LVCvxVA5i8qjCh=Sk77MsVUnZB2VhwzmLKw@mail.gmail.com>
<CA+OCxozpzStRAm=rm3s2ZdtehMt6WfQTVEFT3fssorNc5M2UHQ@mail.gmail.com>
<CA+OCxoxkows1UUgaddq3+R2VcTW9Vmc3QCKdrtd1sNP+fDsHTg@mail.gmail.com>
<CAFOhELfzRV1WoA7A87=g5Nb9uvU3rLL2jPUCEid66pqzFdrfRQ@mail.gmail.com>
<CA+OCxoxWUGqp5P_KSUbKBXH-i2AD4E8STWcfxsy01iVAymU-Og@mail.gmail.com>
<CAFOhELfA8rTWKJr_P9=Z6--oeE0m7E40nZFr=WFSs2g8=3RmAg@mail.gmail.com>
<CAFOhELewp6_jT35CkG8u8-+K+H9AhFS_QpiwXfMcCib6vJyJBg@mail.gmail.com>
<CA+OCxoyRLYFv_SxNNGdsGN=Up7d3WT_EQz0-h9P+S+0oRtjaYg@mail.gmail.com>
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi,
Please find attached updated patch for the Domains module.
On Wed, Mar 16, 2016 at 9:40 PM, Dave Page <[email protected]> wrote:
> Hi
>
> On Wed, Mar 16, 2016 at 2:03 PM, Khushboo Vashi
> <[email protected]> wrote:
> > Hi,
> >
> > Please find the updated Domain Module Patch.
> >
> > To test this patch, please apply Backgrid Textarea Cell Patch before
> this.
>
> Thanks. I believe with the following fixes, we'll be done :-)
>
> - Default values should be auto-quoted when necessary (ie. strings, on
> a text-based domain).
>
As per our discussion, this should leave unquoted.
> - "System Domain?" should be in the General section, between owner and
> comment.
>
Done
> - The switches should use the same colouring/styling as other objects, e.g.
>
> options: {
> 'onText': 'Yes', 'offText': 'No',
> 'onColor': 'success', 'offColor': 'primary',
> 'size': 'small'
> }
>
Done
> - Please remove the Schema property from the main properties tab (not
> the properties dialogue).
>
Done
> - No icon is show for Checks on the Dependents tab for a domain.
>
Done
> - The add button on the Security Labels tab is spelt "Add". Why is
> that? Other instances of this grid use "ADD" which is the default in
> backform.pgadmin.js.
>
Done
> - Dependencies on domain check constraints are listed as being on a
> "Type" not a "Domain".
>
Done
> - If adding a domain constraint using the grid on the Domain dialogue,
> I cannot specify "NOT VALID". We need a checkbox for that in a narrow
> columns at the end. Unchecking it for an existing constraint should be
> the equivalent of doing "ALTER DOMAIN ... VALIDATE CONSTRAINT"
>
Done
> - If I switch the "Don't Validate" switch on a constraint, there are
> leading blank lines in the generated SQL. The same occurs when adding
> a comment to a constraint.
>
Done
> - I think we need to reverse the meaning of "Don't Validate" and
> rename to match the "Valid?" field that's on the properties list.
> Otherwise it's not clear they're the same thing.
>
Done
> - s/Not Null/Not Null?/
>
Done
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
--
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] Domains_ver_6.patch (102.7K, 3-Domains_ver_6.patch)
download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py
new file mode 100644
index 0000000..2df600f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py
@@ -0,0 +1,810 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements the Domain Node."""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+ make_response as ajax_response, internal_server_error, gone
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases.schemas as schemas
+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.databases.schemas.utils import \
+ SchemaChildModule, DataTypeReader
+from pgadmin.browser.server_groups.servers.databases.utils import \
+ parse_sec_labels_from_db
+from functools import wraps
+
+
+class DomainModule(SchemaChildModule):
+ """
+ class DomainModule(SchemaChildModule):
+
+ This class represents The Domain Module.
+
+ Methods:
+ -------
+ * __init__(*args, **kwargs)
+ - Initialize the Domain Module.
+
+ * get_nodes(gid, sid, did, scid)
+ - Generate the domain collection node.
+
+ * script_load()
+ - Load the module script for domain, when schema node is
+ initialized.
+ """
+
+ NODE_TYPE = 'domain'
+ COLLECTION_LABEL = gettext("Domains")
+
+ def __init__(self, *args, **kwargs):
+ super(DomainModule, self).__init__(*args, **kwargs)
+ self.min_ver = None
+ self.max_ver = None
+
+ def get_nodes(self, gid, sid, did, scid):
+ """
+ Generate the domain collection node.
+ """
+ yield self.generate_browser_collection_node(scid)
+
+ @property
+ def script_load(self):
+ """
+ Load the module script for domain, when schema node is
+ initialized.
+ """
+ return schemas.SchemaModule.NODE_TYPE
+
+
+blueprint = DomainModule(__name__)
+
+
+class DomainView(PGChildNodeView, DataTypeReader):
+ """
+ class DomainView
+
+ This class inherits PGChildNodeView to get the different routes for
+ the module. Also, inherits DataTypeReader to get data types.
+
+ The class is responsible to Create, Read, Update and Delete operations for
+ the Domain.
+
+ Methods:
+ -------
+ * validate_request(f):
+ - Works as a decorator.
+ Validating request on the request of create, update and modified SQL.
+
+ * module_js():
+ - Load JS file (domains.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 Domains.
+
+ * nodes(gid, sid, did, scid):
+ - Returns all the Domains to generate Nodes in the browser.
+
+ * properties(gid, sid, did, scid, doid):
+ - Returns the Domain properties.
+
+ * get_collations(gid, sid, did, scid, doid=None):
+ - Returns Collations.
+
+ * create(gid, sid, did, scid):
+ - Creates a new Domain object.
+
+ * update(gid, sid, did, scid, doid):
+ - Updates the Domain object.
+
+ * delete(gid, sid, did, scid, doid):
+ - Drops the Domain object.
+
+ * sql(gid, sid, did, scid, doid=None):
+ - Returns the SQL for the Domain object.
+
+ * msql(gid, sid, did, scid, doid=None):
+ - Returns the modified SQL.
+
+ * get_sql(gid, sid, data, scid, doid=None):
+ - Generates the SQL statements to create/update the Domain object.
+
+ * dependents(gid, sid, did, scid, doid):
+ - Returns the dependents for the Domain object.
+
+ * dependencies(gid, sid, did, scid, doid):
+ - Returns the dependencies for the Domain object.
+
+ * types(gid, sid, did, scid, fnid=None):
+ - Returns Data Types.
+ """
+
+ node_type = blueprint.node_type
+
+ parent_ids = [
+ {'type': 'int', 'id': 'gid'},
+ {'type': 'int', 'id': 'sid'},
+ {'type': 'int', 'id': 'did'},
+ {'type': 'int', 'id': 'scid'}
+ ]
+ ids = [
+ {'type': 'int', 'id': 'doid'}
+ ]
+
+ operations = dict({
+ 'obj': [
+ {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+ {'get': 'list', 'post': 'create'}
+ ],
+ 'delete': [{'delete': 'delete'}],
+ 'children': [{'get': 'children'}],
+ 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+ 'sql': [{'get': 'sql'}],
+ 'msql': [{'get': 'msql'}, {'get': 'msql'}],
+ 'stats': [{'get': 'statistics'}],
+ 'dependency': [{'get': 'dependencies'}],
+ 'dependent': [{'get': 'dependents'}],
+ 'module.js': [{}, {}, {'get': 'module_js'}],
+ 'get_types': [{'get': 'types'}, {'get': 'types'}],
+ 'get_collations': [
+ {'get': 'get_collations'},
+ {'get': 'get_collations'}
+ ]
+ })
+
+ def validate_request(f):
+ """
+ Works as a decorator.
+ Validating request on the request of create, update and modified SQL.
+
+ Required Args:
+ name: Name of the Domain
+ owner: Domain Owner
+ basensp: Schema Name
+ basetype: Data Type of the Domain
+
+ Above both the arguments will not be validated in the update action.
+ """
+
+ @wraps(f)
+ def wrap(self, **kwargs):
+
+ data = {}
+ if request.data:
+ req = json.loads(request.data.decode())
+ else:
+ req = request.args or request.form
+
+ if 'doid' not in kwargs:
+ required_args = [
+ 'name',
+ 'basetype'
+ ]
+
+ for arg in required_args:
+ if arg not in req or req[arg] == '':
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ "Couldn't find the required parameter \
+ (%s)." % arg
+ )
+ )
+
+ try:
+ list_params = []
+ if request.method == 'GET':
+ list_params = ['constraints', 'seclabels']
+
+ for key in req:
+ if key in list_params and req[key] != '' \
+ and req[key] is not None:
+ # Coverts string into python list as expected.
+ data[key] = json.loads(req[key])
+ elif key == 'typnotnull':
+ data[key] = True if req[key] == 'true' or req[key] is\
+ True else\
+ (False if req[key] == 'false' or req[key] is
+ False else '')
+ else:
+ data[key] = req[key]
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ self.request = data
+ return f(self, **kwargs)
+
+ return wrap
+
+ def module_js(self):
+ """
+ Load JS file (domains.js) for this module.
+ """
+ return make_response(
+ render_template(
+ "domains/js/domains.js",
+ _=gettext
+ ),
+ 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'])
+ # Get database connection
+ self.conn = self.manager.connection(did=kwargs['did'])
+ self.qtIdent = driver.qtIdent
+
+ if not self.conn.connected():
+ return precondition_required(
+ gettext("Connection to the server has been lost!")
+ )
+
+ ver = self.manager.version
+ server_type = self.manager.server_type
+
+ # we will set template path for sql scripts
+ if ver >= 90200:
+ self.template_path = 'domains/sql/9.2_plus'
+ elif ver >= 90100:
+ self.template_path = 'domains/sql/9.1_plus'
+
+ return f(*args, **kwargs)
+
+ return wrap
+
+ @check_precondition
+ def list(self, gid, sid, did, scid):
+ """
+ List the Domains.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ """
+
+ SQL = render_template("/".join([self.template_path, 'node.sql']),
+ scid=scid)
+ status, res = self.conn.execute_dict(SQL)
+
+ if not status:
+ return internal_server_error(errormsg=res)
+ return ajax_response(
+ response=res['rows'],
+ status=200
+ )
+
+ @check_precondition
+ def nodes(self, gid, sid, did, scid):
+ """
+ Returns all the Domains to generate Nodes in the browser.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ """
+
+ res = []
+ SQL = render_template("/".join([self.template_path, 'node.sql']),
+ scid=scid)
+ status, rset = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=rset)
+
+ for row in rset['rows']:
+ res.append(
+ self.blueprint.generate_browser_node(
+ row['oid'],
+ scid,
+ row['name'],
+ icon="icon-domain"
+ ))
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ @check_precondition
+ def properties(self, gid, sid, did, scid, doid):
+ """
+ Returns the Domain properties.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+
+ SQL = render_template("/".join([self.template_path, 'properties.sql']),
+ scid=scid, doid=doid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ if len(res['rows']) == 0:
+ return gone(gettext("""
+Could not find the domain in the database.
+It may have been removed by another user or
+shifted to the another schema.
+"""))
+
+ data = res['rows'][0]
+
+ # Get Type Length and Precision
+ data.update(self._parse_type(data['fulltype']))
+
+ # Get Domain Constraints
+ SQL = render_template("/".join([self.template_path,
+ 'get_constraints.sql']),
+ doid=doid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ data['constraints'] = res['rows']
+
+ # Get formatted Security Labels
+ if 'seclabels' in data:
+ data.update(parse_sec_labels_from_db(data['seclabels']))
+
+ # Set System Domain Status
+ data['sysdomain'] = False
+ if doid <= self.manager.db_info[did]['datlastsysoid']:
+ data['sysdomain'] = True
+
+ return ajax_response(
+ response=data,
+ status=200
+ )
+
+ def _parse_type(self, basetype):
+ """
+ Returns Type and Data Type from the basetype.
+ """
+ typ_len = ''
+ typ_precision = ''
+
+ # The Length and the precision of the Datatype should be separate.
+ # The Format we getting from database is: numeric(1,1)
+ # So, we need to separate Length: 1, Precision: 1
+
+ if basetype != '' and basetype.find("(") > 0:
+ substr = basetype[basetype.find("(") + 1:len(
+ basetype) - 1]
+ typlen = substr.split(",")
+ if len(typlen) > 1:
+ typ_len = typlen[0]
+ typ_precision = typlen[1]
+ else:
+ typ_len = typlen
+ typ_precision = ''
+
+ return {'typlen': typ_len, 'precision': typ_precision}
+
+ @check_precondition
+ def get_collations(self, gid, sid, did, scid, doid=None):
+ """
+ Returns Collations.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+
+ res = [{'label': '', 'value': ''}]
+ try:
+ SQL = render_template("/".join([self.template_path,
+ 'get_collations.sql']))
+ status, rset = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ for row in rset['rows']:
+ res.append({'label': row['copy_collation'],
+ 'value': row['copy_collation']}
+ )
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def types(self, gid, sid, did, scid, doid=None):
+ """
+ Returns the Data Types.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ fnid: Function Id
+ """
+
+ condition = """typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r')
+AND NOT EXISTS (SELECT 1 FROM pg_class WHERE relnamespace=typnamespace
+AND relname = typname AND relkind != 'c') AND
+(typname NOT LIKE '_%' OR NOT EXISTS (SELECT 1 FROM pg_class WHERE
+relnamespace=typnamespace AND relname = substring(typname FROM 2)::name
+AND relkind != 'c'))"""
+
+ if self.blueprint.show_system_objects:
+ condition += " AND nsp.nspname != 'information_schema'"
+
+ # Get Types
+ status, types = self.get_types(self.conn, condition)
+
+ if not status:
+ return internal_server_error(errormsg=types)
+
+ return make_json_response(
+ data=types,
+ status=200
+ )
+
+ @check_precondition
+ @validate_request
+ def create(self, gid, sid, did, scid):
+ """
+ Creates a new Domain object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+
+ Required Args:
+ name: Domain Name
+ owner: Owner Name
+ basensp: Schema Name
+ basetype: Domain Base Type
+
+ Returns:
+ Domain object in json format.
+ """
+
+ data = self.request
+ try:
+ status, SQL = self.get_sql(gid, sid, data, scid)
+
+ if not status:
+ return internal_server_error(errormsg=SQL)
+
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # We need oid to to add object in tree at browser, below sql will
+ # gives the same
+ SQL = render_template("/".join([self.template_path,
+ 'get_oid.sql']),
+ basensp=data['basensp'],
+ name=data['name'])
+ status, res = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ doid, scid = res['rows'][0]
+
+ return jsonify(
+ node=self.blueprint.generate_browser_node(
+ doid,
+ scid,
+ data['name'],
+ icon="icon-domain"
+ )
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def delete(self, gid, sid, did, scid, doid):
+ """
+ Drops the Domain object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+
+ if self.cmd == 'delete':
+ # This is a cascade operation
+ cascade = True
+ else:
+ cascade = False
+
+ try:
+ SQL = render_template("/".join([self.template_path,
+ 'delete.sql']),
+ scid=scid, doid=doid)
+ status, res = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ name, basensp = res['rows'][0]
+
+ SQL = render_template("/".join([self.template_path,
+ 'delete.sql']),
+ name=name, basensp=basensp, cascade=cascade)
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ return make_json_response(
+ success=1,
+ info=gettext("Domain dropped"),
+ data={
+ 'id': doid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ @validate_request
+ def update(self, gid, sid, did, scid, doid):
+ """
+ Updates the Domain object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+
+ status, SQL = self.get_sql(gid, sid, self.request, scid, doid)
+
+ if not status:
+ return internal_server_error(errormsg=SQL)
+
+ try:
+ if SQL:
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # Get Schema Id
+ SQL = render_template("/".join([self.template_path,
+ 'get_oid.sql']),
+ doid=doid)
+ status, res = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ scid = res['rows'][0]['scid']
+
+ return make_json_response(
+ success=1,
+ info="Domain updated",
+ data={
+ 'id': doid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+ else:
+ return make_json_response(
+ success=1,
+ info="Nothing to update",
+ data={
+ 'id': doid,
+ '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, doid=None):
+ """
+ Returns the SQL for the Domain object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ scid=scid, doid=doid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return False, internal_server_error(errormsg=res)
+ data = res['rows'][0]
+
+ # Get Type Length and Precision
+ data.update(self._parse_type(data['fulltype']))
+
+ # Get Domain Constraints
+ SQL = render_template("/".join([self.template_path,
+ 'get_constraints.sql']),
+ doid=doid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ data['constraints'] = res['rows']
+
+ SQL = render_template("/".join([self.template_path,
+ 'create.sql']), data=data)
+
+ sql_header = """-- DOMAIN: {0}
+
+-- DROP DOMAIN {0};
+
+""".format(data['basensp'] + '.' + data['name'])
+
+ SQL = sql_header + SQL
+
+ return ajax_response(response=SQL.strip('\n'))
+
+ @check_precondition
+ @validate_request
+ def msql(self, gid, sid, did, scid, doid=None):
+ """
+ Returns the modified SQL.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+
+ Required Args:
+ name: Domain Name
+ owner: Owner Name
+ basensp: Schema Name
+ basetype: Domain Base Type
+
+ Returns:
+ SQL statements to create/update the Domain.
+ """
+
+ status, SQL = self.get_sql(gid, sid, self.request, scid, doid)
+
+ if SQL:
+ return make_json_response(
+ data=SQL,
+ status=200
+ )
+ else:
+ return SQL
+
+ def get_sql(self, gid, sid, data, scid, doid=None):
+ """
+ Generates the SQL statements to create/update the Domain.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+
+ try:
+ if doid is not None:
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ scid=scid, doid=doid)
+ 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)
+ else:
+ SQL = render_template("/".join([self.template_path,
+ 'create.sql']),
+ data=data)
+ return True, SQL.strip('\n')
+
+ except Exception as e:
+ return False, e
+
+ @check_precondition
+ def dependents(self, gid, sid, did, scid, doid):
+ """
+ This function get the dependents and return ajax response
+ for the Domain node.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+ dependents_result = self.get_dependents(self.conn, doid)
+ return ajax_response(
+ response=dependents_result,
+ status=200
+ )
+
+ @check_precondition
+ def dependencies(self, gid, sid, did, scid, doid):
+ """
+ This function get the dependencies and return ajax response
+ for the Domain node.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+ dependencies_result = self.get_dependencies(self.conn, doid)
+ return ajax_response(
+ response=dependencies_result,
+ status=200
+ )
+
+DomainView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/__init__.py
new file mode 100644
index 0000000..d217e69
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/__init__.py
@@ -0,0 +1,687 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements the Domain Constraint Module."""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+ make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases.schemas.domains \
+ as domains
+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 DomainConstraintModule(CollectionNodeModule):
+ """
+ class DomainConstraintModule(CollectionNodeModule):
+
+ This class represents The Domain Constraint Module.
+
+ Methods:
+ -------
+ * __init__(*args, **kwargs)
+ - Initialize the Domain Constraint Module.
+
+ * get_nodes(gid, sid, did, scid)
+ - Generate the Domain Constraint collection node.
+
+ * node_inode(gid, sid, did, scid)
+ - Returns Domain Constraint node as leaf node.
+
+ * script_load()
+ - Load the module script for the Domain Constraint, when any of the
+ Domain node is initialized.
+ """
+ NODE_TYPE = 'domain-constraints'
+ COLLECTION_LABEL = gettext("Domain Constraints")
+
+ def __init__(self, *args, **kwargs):
+ super(DomainConstraintModule, self).__init__(*args, **kwargs)
+ self.min_ver = None
+ self.max_ver = None
+
+ def get_nodes(self, gid, sid, did, scid, doid):
+ """
+ Generate the Domain Constraint collection node.
+ """
+ yield self.generate_browser_collection_node(doid)
+
+ @property
+ def node_inode(self):
+ """
+ Returns Domain Constraint node as leaf node.
+ """
+ return False
+
+ @property
+ def script_load(self):
+ """
+ Load the module script for the Domain Constraint, when any of the
+ Domain node is initialized.
+ """
+ return domains.DomainModule.NODE_TYPE
+
+ @property
+ def csssnippets(self):
+ """
+ Returns a snippet of css to include in the page
+ """
+ return [
+ render_template(
+ "domain-constraints/css/domain-constraints.css",
+ node_type=self.node_type
+ )
+ ]
+
+
+
+blueprint = DomainConstraintModule(__name__)
+
+
+class DomainConstraintView(PGChildNodeView):
+ """
+ class DomainConstraintView(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 Domain Constraint.
+
+ Methods:
+ -------
+
+ * module_js():
+ - Load JS file (domain-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 Domain Constraints.
+
+ * nodes(gid, sid, did, scid):
+ - Returns all the Domain Constraints to generate Nodes in the browser.
+
+ * properties(gid, sid, did, scid, doid):
+ - Returns the Domain Constraint properties.
+
+ * create(gid, sid, did, scid):
+ - Creates a new Domain Constraint object.
+
+ * update(gid, sid, did, scid, doid):
+ - Updates the Domain Constraint object.
+
+ * delete(gid, sid, did, scid, doid):
+ - Drops the Domain Constraint object.
+
+ * sql(gid, sid, did, scid, doid=None):
+ - Returns the SQL for the Domain Constraint object.
+
+ * msql(gid, sid, did, scid, doid=None):
+ - Returns the modified SQL.
+
+ * get_sql(gid, sid, data, scid, doid=None):
+ - Generates the SQL statements to create/update the Domain Constraint.
+ object.
+
+ * dependents(gid, sid, did, scid, doid, coid):
+ - Returns the dependents for the Domain Constraint object.
+
+ * dependencies(gid, sid, did, scid, doid, coid):
+ - Returns the dependencies for the Domain Constraint object.
+ """
+ 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': 'doid'}
+ ]
+ ids = [
+ {'type': 'int', 'id': 'coid'}
+ ]
+
+ operations = dict({
+ 'obj': [
+ {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+ {'get': 'list', 'post': 'create'}
+ ],
+ 'delete': [{'delete': 'delete'}],
+ 'children': [{'get': 'children'}],
+ 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+ 'sql': [{'get': 'sql'}],
+ 'msql': [{'get': 'msql'}, {'get': 'msql'}],
+ 'stats': [{'get': 'statistics'}],
+ 'dependency': [{'get': 'dependencies'}],
+ 'dependent': [{'get': 'dependents'}],
+ 'module.js': [{}, {}, {'get': 'module_js'}]
+ })
+
+ def validate_request(f):
+ """
+ Works as a decorator.
+ Validating request on the request of create, update and modified SQL.
+
+ Required Args:
+ name: Name of the Domain Constraint
+ consrc: Check Constraint Definition
+
+ Above both the arguments will not be validated in the update action.
+ """
+
+ @wraps(f)
+ def wrap(self, **kwargs):
+
+ data = {}
+ if request.data:
+ req = json.loads(request.data.decode())
+ else:
+ req = request.args or request.form
+
+ if 'coid' not in kwargs:
+ required_args = [
+ 'name',
+ 'consrc'
+ ]
+
+ for arg in required_args:
+ if arg not in req or req[arg] == '':
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ "Couldn't find the required parameter \
+ (%s)." % arg
+ )
+ )
+
+ try:
+ for key in req:
+ if key == 'convalidated':
+ data[key] = True if (req[key] == 'true' or req[key] is
+ True) else False
+ else:
+ data[key] = req[key]
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ self.request = data
+ return f(self, **kwargs)
+
+ return wrap
+
+ def module_js(self):
+ """
+ Load JS file (domain-constraints.js) for this module.
+ """
+ return make_response(
+ render_template(
+ "domain-constraints/js/domain-constraints.js",
+ _=gettext
+ ),
+ 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(
+ gettext("Connection to the server has been lost!")
+ )
+
+ ver = self.manager.version
+
+ # we will set template path for sql scripts
+ if ver >= 90200:
+ self.template_path = 'domain-constraints/sql/9.2_plus'
+ elif ver >= 90100:
+ self.template_path = 'domain-constraints/sql/9.1_plus'
+
+ return f(*args, **kwargs)
+
+ return wrap
+
+ @check_precondition
+ def list(self, gid, sid, did, scid, doid):
+ """
+ List the Domain Constraints.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ doid=doid)
+ status, res = self.conn.execute_dict(SQL)
+
+ if not status:
+ return internal_server_error(errormsg=res)
+ return ajax_response(
+ response=res['rows'],
+ status=200
+ )
+
+ @check_precondition
+ def nodes(self, gid, sid, did, scid, doid):
+ """
+ Returns all the Domain Constraints.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ """
+ res = []
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ doid=doid)
+ status, rset = self.conn.execute_2darray(SQL)
+
+ if not status:
+ return internal_server_error(errormsg=rset)
+
+ for row in rset['rows']:
+ if row['convalidated']:
+ icon = 'icon-domain-constraints'
+ else:
+ icon = 'icon-domain-constraints-bad'
+ res.append(
+ self.blueprint.generate_browser_node(
+ row['oid'],
+ doid,
+ row['name'],
+ icon=icon
+ ))
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ @check_precondition
+ def properties(self, gid, sid, did, scid, doid, coid):
+ """
+ Returns the Domain Constraints property.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ doid=doid, coid=coid)
+ 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
+ @validate_request
+ def create(self, gid, sid, did, scid, doid):
+ """
+ Creates a new Domain Constraint object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+
+ Returns:
+ Domain Constraint object in json format.
+ """
+ data = self.request
+ try:
+ status, SQL = self.get_sql(gid, sid, data, scid, doid)
+ if not status:
+ return internal_server_error(errormsg=SQL)
+
+ status, res = self.conn.execute_scalar(SQL)
+
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # Get the recently added constraints oid
+ SQL = render_template("/".join([self.template_path,
+ 'get_oid.sql']),
+ doid=doid, name=data['name'])
+ status, coid = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=coid)
+
+ if 'convalidated' in data and data['convalidated']:
+ icon = 'icon-domain-constraints'
+ else:
+ icon = 'icon-domain-constraints-bad'
+
+ return jsonify(
+ node=self.blueprint.generate_browser_node(
+ coid,
+ doid,
+ data['name'],
+ icon=icon
+ )
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def delete(self, gid, sid, did, scid, doid, coid):
+ """
+ Drops the Domain Constraint object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+ try:
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ doid=doid, coid=coid)
+ 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=gettext("Domain Constraint dropped"),
+ data={
+ 'id': doid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ @validate_request
+ def update(self, gid, sid, did, scid, doid, coid):
+ """
+ Updates the Domain Constraint object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+ data = self.request
+ status, SQL = self.get_sql(gid, sid, data, scid, doid, coid)
+
+ try:
+ if SQL and status:
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ if 'convalidated' in data and data['convalidated']:
+ icon = 'icon-domain-constraints'
+ elif 'convalidated' in data and not data['convalidated']:
+ icon = 'icon-domain-constraints-bad'
+ else:
+ icon = ''
+
+ return make_json_response(
+ success=1,
+ info="Domain Constraint updated",
+ data={
+ 'id': coid,
+ 'doid': doid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did,
+ 'icon': icon
+ }
+ )
+ else:
+ return make_json_response(
+ success=1,
+ info="Nothing to update",
+ data={
+ 'id': coid,
+ 'doid': doid,
+ '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, doid, coid=None):
+ """
+ Returns the SQL for the Domain Constraint object.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+
+ # Get Schema and Domain.
+ domain, schema = self._get_domain(doid)
+
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ doid=doid, coid=coid)
+ 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,
+ 'create.sql']),
+ data=data, domain=domain, schema=schema)
+
+ sql_header = """-- CHECK: {0}
+
+-- ALTER DOMAIN {1} DROP CONSTRAINT {0};
+
+""".format(data['name'],schema + '.' + domain)
+
+ SQL = sql_header + SQL
+
+ return ajax_response(response=SQL)
+
+ @check_precondition
+ @validate_request
+ def msql(self, gid, sid, did, scid, doid, coid=None):
+ """
+ Returns the modified SQL.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+
+ Returns:
+ Domain Constraint object in json format.
+ """
+ data = self.request
+
+ status, SQL = self.get_sql(gid, sid, data, scid, doid, coid)
+ if status and SQL:
+ return make_json_response(
+ data=SQL,
+ status=200
+ )
+ else:
+ return SQL
+
+ def get_sql(self, gid, sid, data, scid, doid, coid=None):
+ """
+ Generates the SQL statements to create/update the Domain Constraint.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+ try:
+ if coid is not None:
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ doid=doid, coid=coid)
+ 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:
+ domain, schema = self._get_domain(doid)
+
+ SQL = render_template("/".join([self.template_path,
+ 'create.sql']),
+ data=data, domain=domain, schema=schema)
+ return True, SQL.strip('\n')
+ except Exception as e:
+ return False, internal_server_error(errormsg=str(e))
+
+ def _get_domain(self, doid):
+ """
+ Returns Domain and Schema name.
+
+ Args:
+ doid: Domain Id
+
+ """
+ SQL = render_template("/".join([self.template_path,
+ 'get_domain.sql']),
+ doid=doid)
+ status, res = self.conn.execute_2darray(SQL)
+
+ if not status:
+ return False, internal_server_error(errormsg=res)
+
+ return res['rows'][0]
+
+ @check_precondition
+ def dependents(self, gid, sid, did, scid, doid, coid):
+ """
+ This function get the dependents and return ajax response
+ for the Domain Constraint node.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+ dependents_result = self.get_dependents(self.conn, coid)
+ return ajax_response(
+ response=dependents_result,
+ status=200
+ )
+
+ @check_precondition
+ def dependencies(self, gid, sid, did, scid, doid, coid):
+ """
+ This function get the dependencies and return ajax response
+ for the Domain Constraint node.
+
+ Args:
+ gid: Server Group Id
+ sid: Server Id
+ did: Database Id
+ scid: Schema Id
+ doid: Domain Id
+ coid: Domain Constraint Id
+ """
+ dependencies_result = self.get_dependencies(self.conn, coid)
+ return ajax_response(
+ response=dependencies_result,
+ status=200
+ )
+
+DomainConstraintView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/static/img/coll-domain-constraints.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/static/img/coll-domain-constraints.png
new file mode 100644
index 0000000000000000000000000000000000000000..d62e13705c50e6c0cf8f19d680053e8643e28751
GIT binary patch
literal 314
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv3GfMV1=2TrO847{Jl`|t`Qpas
zn<hS+l=rMY>RGPqvlydizRJ&>B`Om#V}R-yOM?7@862M7NCR>>3p^r=fwTu0yPeFo
z12TL)T^vI=t|uoPU||ZF<tgaHG*QsQ!?m&Tq=?3mCu}J#Dx3x@mM}}^iE=5NIWXnk
zkpnC4ai%a>@;Gg7=uums=9bIK=Egd~(us-3g@Iv02gfsK^JP^)gH=mhBT7;dOH!?p
zi&B9UgOP!ufv%yEu7P2Qk%5(ov6YF5wt=aYfq}(LRXG$5x%nxXX_XKS29{tAAk|g|
XW)KahriZQpYGCkm^>bP0l+XkKyyRU}
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/static/img/domain-constraints-bad.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/static/img/domain-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/domains/domain-constraints/static/img/domain-constraints.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/static/img/domain-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/domains/domain-constraints/templates/domain-constraints/css/domain-constraints.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/css/domain-constraints.css
new file mode 100644
index 0000000..4691c60
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/css/domain-constraints.css
@@ -0,0 +1,23 @@
+.icon-coll-domain-constraints {
+ background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/coll-domain-constraints.png' )}}') !important;
+ background-repeat: no-repeat;
+ align-content: center;
+ vertical-align: middle;
+ height: 1.3em;
+}
+
+.icon-check-bad, .icon-domain-constraints-bad {
+ background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/domain-constraints-bad.png' )}}') !important;
+ background-repeat: no-repeat;
+ align-content: center;
+ vertical-align: middle;
+ height: 1.3em;
+}
+
+.icon-check, .icon-domain-constraints {
+ background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/domain-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/domains/domain-constraints/templates/domain-constraints/js/domain-constraints.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/js/domain-constraints.js
new file mode 100644
index 0000000..c9f1a97
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/js/domain-constraints.js
@@ -0,0 +1,150 @@
+// Domain Constraint Module: Collection and Node
+define(
+ ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+ // Define Domain Constraint Collection Node
+ if (!pgBrowser.Nodes['coll-domain-constraints']) {
+ var domain_constraints = pgAdmin.Browser.Nodes['coll-domain-constraints'] =
+ pgAdmin.Browser.Collection.extend({
+ node: 'domain-constraints',
+ label: '{{ _('Domain Constraints') }}',
+ type: 'coll-domain-constraints',
+ columns: ['name', 'description']
+ });
+ };
+
+ // Domain Constraint Node
+ if (!pgBrowser.Nodes['domain-constraints']) {
+ pgAdmin.Browser.Nodes['domain-constraints'] = pgBrowser.Node.extend({
+ type: 'domain-constraints',
+ label: '{{ _('Domain Constraints') }}',
+ collection_type: 'coll-domain-constraints',
+ hasSQL: true,
+ hasDepends: true,
+ parent_type: ['domain'],
+ Init: function() {
+ // Avoid mulitple registration of menus
+ if (this.initialized)
+ return;
+
+ this.initialized = true;
+
+ pgBrowser.add_menus([{
+ name: 'create_domain_on_coll', node: 'coll-domain-constraints', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Domain Constraint...') }}',
+ icon: 'wcTabIcon icon-domain-constraints', data: {action: 'create', check: true},
+ enable: 'canCreate'
+ },{
+ name: 'create_domain-constraints', node: 'domain-constraints', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Domain Constraint...') }}',
+ icon: 'wcTabIcon icon-domain-constraints', data: {action: 'create', check: true},
+ enable: 'canCreate'
+ },{
+ name: 'create_domain-constraints', node: 'domain', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Domain Constraint...') }}',
+ icon: 'wcTabIcon icon-domain-constraints', data: {action: 'create', check: false},
+ enable: 'canCreate'
+ }
+ ]);
+
+ },
+ canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+ model: pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ name: undefined,
+ oid: undefined,
+ description: undefined,
+ consrc: undefined,
+ connoinherit: undefined,
+ convalidated: undefined
+ },
+ // Domain Constraint Schema
+ schema: [{
+ id: 'name', label: '{{ _('Name') }}', type:'text', cell:'string',
+ disabled: 'isDisabled'
+ },{
+ id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+ type: 'text' , mode: ['properties']
+ },{
+ id: 'description', label: '{{ _('Comment') }}', type: 'multiline', cell:
+ 'string', mode: ['properties', 'create', 'edit'], min_version: 90500,
+ },{
+ id: 'consrc', label: '{{ _('Check') }}', type: 'multiline', cel:
+ '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'], disabled: 'isDisabled',
+ visible: false
+ },{
+ id: 'convalidated', label: "{{ _("Validate?") }}", type: 'switch', cell:
+ 'boolean', group: '{{ _('Definition') }}',
+ options: {
+ 'onText': 'Yes', 'offText': 'No',
+ 'onColor': 'success', 'offColor': 'primary',
+ 'size': 'small'
+ },
+ disabled: function(m) {
+ if (!m.isNew()) {
+ var server = this.node_info.server;
+ if (server.version < 90200)
+ {
+ return true;
+ }
+ else if(m.get('convalidated'))
+ {
+ return true;
+ }
+ return false;
+ }
+ return false;
+ },
+ mode: ['properties', 'create', 'edit']
+ }],
+ // Client Side Validation
+ validate: function() {
+ var err = {},
+ errmsg;
+
+ if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
+ err['name'] = '{{ _('Name can not be empty!') }}';
+ errmsg = errmsg || err['name'];
+ }
+
+ 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;
+ }
+ }),
+ });
+
+ }
+
+ return pgBrowser.Nodes['domain'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..be943d2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/create.sql
@@ -0,0 +1,3 @@
+{% if data and schema and domain %}
+ALTER DOMAIN {{ conn|qtIdent(schema, domain) }}
+ ADD CONSTRAINT {{ conn|qtIdent(data.name) }} CHECK ({{ data.consrc }});{% endif -%}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..260c3c0
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/delete.sql
@@ -0,0 +1,4 @@
+{% if data %}
+ALTER DOMAIN {{ conn|qtIdent(data.nspname, data.relname) }}
+ DROP CONSTRAINT {{ conn|qtIdent(data.name) }};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/get_domain.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/get_domain.sql
new file mode 100644
index 0000000..1040c0e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/get_domain.sql
@@ -0,0 +1,8 @@
+SELECT
+ d.typname as domain, bn.nspname as schema
+FROM
+ pg_type d
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ d.oid = {{doid}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..f59e08c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,7 @@
+SELECT
+ oid, conname as name
+FROM
+ pg_constraint
+WHERE
+ contypid = {{doid}}::oid
+ AND conname={{ name|qtLiteral }};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..043f011
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/properties.sql
@@ -0,0 +1,14 @@
+SELECT
+ c.oid, conname AS name, typname AS relname, nspname,
+ regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') AS consrc
+FROM
+ pg_constraint c
+JOIN
+ pg_type t ON t.oid=contypid
+JOIN
+ pg_namespace nl ON nl.oid=typnamespace
+WHERE
+ contype = 'c' AND contypid = {{doid}}::oid
+{% if coid %}
+ AND c.oid = {{ coid }}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..299ba6b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.1_plus/update.sql
@@ -0,0 +1,3 @@
+{% if data.name %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+ RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/create.sql
new file mode 100644
index 0000000..ad993f7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/create.sql
@@ -0,0 +1,10 @@
+{% if data and schema and domain %}
+ALTER DOMAIN {{ conn|qtIdent(schema, domain) }}
+ ADD CONSTRAINT {{ conn|qtIdent(data.name) }} CHECK ({{ data.consrc }}){% if not data.convalidated %}
+
+ NOT VALID{% endif %};{% if data.description %}
+
+
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON DOMAIN {{ conn|qtIdent(schema, domain) }}
+ IS '{{ data.description }}';{% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/delete.sql
new file mode 100644
index 0000000..260c3c0
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/delete.sql
@@ -0,0 +1,4 @@
+{% if data %}
+ALTER DOMAIN {{ conn|qtIdent(data.nspname, data.relname) }}
+ DROP CONSTRAINT {{ conn|qtIdent(data.name) }};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_domain.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_domain.sql
new file mode 100644
index 0000000..1040c0e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_domain.sql
@@ -0,0 +1,8 @@
+SELECT
+ d.typname as domain, bn.nspname as schema
+FROM
+ pg_type d
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ d.oid = {{doid}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_oid.sql
new file mode 100644
index 0000000..f59e08c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_oid.sql
@@ -0,0 +1,7 @@
+SELECT
+ oid, conname as name
+FROM
+ pg_constraint
+WHERE
+ contypid = {{doid}}::oid
+ AND conname={{ name|qtLiteral }};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_type_category.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_type_category.sql
new file mode 100644
index 0000000..3e3b244
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/get_type_category.sql
@@ -0,0 +1,5 @@
+SELECT
+ typcategory
+FROM
+ pg_type
+WHERE typname = {{datatype}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/properties.sql
new file mode 100644
index 0000000..34d8b34
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/properties.sql
@@ -0,0 +1,17 @@
+SELECT
+ c.oid, conname AS name, typname AS relname, nspname, description,
+ regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') AS consrc,
+ connoinherit, convalidated, convalidated AS convalidated_p
+FROM
+ pg_constraint c
+JOIN
+ pg_type t ON t.oid=contypid
+JOIN
+ pg_namespace nl ON nl.oid=typnamespace
+LEFT OUTER JOIN
+ pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass)
+WHERE
+ contype = 'c' AND contypid = {{doid}}::oid
+{% if coid %}
+ AND c.oid = {{ coid }}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/update.sql
new file mode 100644
index 0000000..628eb6e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/sql/9.2_plus/update.sql
@@ -0,0 +1,13 @@
+{% set name = o_data.name %}
+{% if data.name %}
+{% set name = data.name %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+ RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};{% endif -%}{% if data.convalidated %}
+
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+ VALIDATE CONSTRAINT {{ conn|qtIdent(name) }};{% endif -%}{% if data.description %}
+
+
+COMMENT ON CONSTRAINT {{ conn|qtIdent(name) }} ON DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+ IS '{{ data.description }}';{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/static/img/coll-domain.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/static/img/coll-domain.png
new file mode 100644
index 0000000000000000000000000000000000000000..55621528a1dba4928538fe5557b9b988ed78d6ab
GIT binary patch
literal 462
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}U4T!BE0BJeoqfW=;gF{0PD8_o
zi&pN_(K)B7`FPi%2ix`@v9LU(tNUQ*!K1czXOxuggoGT_(#p@zf4Jw!!zHV)`3F7T
zd-Um}H}`iRIijcc@Wq#>&ptkR`SszG54Uz6zW4mg?MLsgZ9jbb>E~y!zTSB9`Re1(
zjS1S99(_9h@YC4`A5Y)^_^>@J3+MvIk|4ie28U-i(tsS!0*}aIAngIhZYQ(tfQ)ue
z7sn8Z%b|U@#hMgESUvs4wKoSxO>~{O=-Yq$8_!r)-^e%4-l6f-Jox1%8}FIVx>FCW
zPMVwluQGbkP1bcSwVV0d_?PZbZVis%HeYTWyU*$OvYp$uTc3QLbD?2trOnDuhZa>f
z=3d_{(zER9xt(<n3UsBI4SNC?Y!rBW<m2`n>yDRyg$uoE8Qx}bo1D0qw;t#u)e_f;
zl9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!XjU}|MxU@=ow4n;$5eoAIqB}9XP
eC0GMUwUvPxM8m1+p=*E|7(8A5T-G@yGywoRCC2Lj
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/static/img/domain-sm.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/static/img/domain-sm.png
new file mode 100644
index 0000000000000000000000000000000000000000..7521cddeaaaf0ee4e3c60e948078d70e17e06893
GIT binary patch
literal 401
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}T7XZ8E0Deu9eu*V;gF{0K`pIg
zc6K`r4IeIAc}Q3HxV`=3y+@xudUJpGkt2F~PoI5!^78A$Cm(L@JbcYR=;4bm_nv>b
z{pkI*?T7D#gyiSvKYR7{_S4Tdo_xOg_;X`|_N7Ok&OiKg_QA)~_dlLo85{w$iLoTe
zFPOpM*^M+HhqJ&VvKUBvfU(=jY&#$$$<xI#MB;Mq`IABp20RT9wUXkaL(1R(pOn?c
z>38<+e>KaN2{%0Jd@sMbY$+13Z&%Z<%!P+*SNu+#({Rr={_KxUhswHdID0QWTCBvD
z)^ky;@gu`E#RAC#l`JcnelS0rxkKN7b1B>H56gX)0&P<*ag8WRNi0dVN-jzTQVd20
zh6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTdHGouG8JIydoSGiG
Q2B?9-)78&qol`;+03_q3ga7~l
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/static/img/domain.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/static/img/domain.png
new file mode 100644
index 0000000000000000000000000000000000000000..42ca929325854b8f34787425e8094d08c75983bc
GIT binary patch
literal 424
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}PJmB{E0BJeoqfW=;gF{0PD8^7
zi&s6`bL8oxH}`iRdHU?*lb2r~J^6Th=ix^$zTSWS<?f>oH+CHUa^}pVf`aWvMt7fm
zx&8F>jfd~AY(HF`mUiRG=W9<sUwQB@KR>@QLHo+%PZuA3I{)y~*$1D_JotF({zvHt
zo%ulf7)yfuf*Bm1-ADs+I14-?i-EKU7`vU!wgWPXJzX3_Brcbpe=XFcAmSFNeC3q&
zl!Z+(RsYN12&-NW{P*^#<rx82_2-+ii&SqfGgO`Jcj@;01@HTH{&&7#v?j}I)=J6m
ze`~hppZn7?WA|%z!}T6pf>z0IjbZrS5ICD*275*_bAo)r8t#Vg4A*Lz);xc4JKq03
zXXC}zd)YwiRZCnWN>UO_QmvAUQh^kMk%6IsuAz~xfnkV|ft87|m5GVAfvJ^&fyGQ!
qITQ`K`6-!cl@JXEmS7Da)m8>(5DllMhpqu?VDNPHb6Mw<&;$VOR=Fqu
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/js/domains.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/js/domains.js
new file mode 100644
index 0000000..1c6da2a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/js/domains.js
@@ -0,0 +1,345 @@
+// Domain Module: Collection and Node.
+define(
+ ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+ 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+ // Define Domain Collection Node
+ if (!pgBrowser.Nodes['coll-domain']) {
+ var domains = pgAdmin.Browser.Nodes['coll-domain'] =
+ pgAdmin.Browser.Collection.extend({
+ node: 'domain',
+ label: '{{ _('Domains') }}',
+ type: 'coll-domain',
+ columns: ['name', 'owner', 'description']
+ });
+ };
+
+ // Security Model
+ var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ provider: null,
+ security_label: null
+ },
+ schema: [{
+ id: 'provider', label: '{{ _('Provider') }}',
+ type: 'text', editable: true, cellHeaderClasses:'width_percent_50'
+ },{
+ id: 'security_label', label: '{{ _('Security Label') }}',
+ type: 'text', editable: true, cellHeaderClasses:'width_percent_50'
+ }],
+ validate: function() {
+ var err = {},
+ errmsg = null;
+
+ if (_.isUndefined(this.get('security_label')) ||
+ _.isNull(this.get('security_label')) ||
+ String(this.get('security_label')).replace(/^\s+|\s+$/g, '') == '') {
+ errmsg = '{{ _('Please specify the value for all the security providers.')}}';
+ this.errorModel.set('security_label', errmsg);
+ return errmsg;
+ } else {
+ this.errorModel.unset('security_label');
+ }
+ return null;
+ }
+ });
+
+ // Constraint Model
+ var ConstraintModel = pgAdmin.Browser.Node.Model.extend({
+ idAttribute: 'conoid',
+ defaults: {
+ conoid: undefined,
+ conname: undefined,
+ consrc: undefined,
+ convalidated: undefined
+ },
+ schema: [{
+ id: 'conname', label: '{{ _('Name') }}', type: 'text', cell: 'string',
+ cellHeaderClasses: 'width_percent_40', editable: 'isEditable'
+ },{
+ id: 'consrc', label: '{{ _('Check') }}', type: 'multiline',
+ cell: Backgrid.Extension.TextareaCell, group: '{{ _('Definition') }}',
+ cellHeaderClasses: 'width_percent_60', editable: 'isEditable'
+ },{
+ id: 'convalidated', label: '{{ _('Validate?') }}', type: 'switch', cell:
+ 'boolean', group: '{{ _('Definition') }}', min_version: 90200,
+ editable: 'isEditable',
+ options: {
+ 'onText': 'Yes', 'offText': 'No',
+ 'onColor': 'success', 'offColor': 'primary',
+ 'size': 'small'
+ }
+ }],
+ isEditable: function(m) {
+ return _.isUndefined(m.isNew) ? true : m.isNew();
+ },
+ toJSON: Backbone.Model.prototype.toJSON
+ });
+
+ // Domain Node
+ if (!pgBrowser.Nodes['domain']) {
+ pgAdmin.Browser.Nodes['domain'] = pgBrowser.Node.extend({
+ type: 'domain',
+ label: '{{ _('Domain') }}',
+ collection_type: 'coll-domain',
+ hasSQL: true,
+ hasDepends: true,
+ parent_type: ['schema'],
+ Init: function() {
+ // Avoid mulitple registration of menus
+ if (this.initialized)
+ return;
+
+ this.initialized = true;
+
+ pgBrowser.add_menus([{
+ name: 'create_domain_on_coll', node: 'coll-domain', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Domain...') }}',
+ icon: 'wcTabIcon icon-domain', data: {action: 'create', check: true},
+ enable: 'canCreate'
+ },{
+ name: 'create_domain', node: 'domain', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Domain...') }}',
+ icon: 'wcTabIcon icon-domain', data: {action: 'create', check: true},
+ enable: 'canCreate'
+ },{
+ name: 'create_domain', node: 'schema', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Domain...') }}',
+ icon: 'wcTabIcon icon-domain', data: {action: 'create', check: false},
+ enable: 'canCreate'
+ }
+ ]);
+
+ },
+ canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+ canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
+ // Domain Node Model
+ model: pgAdmin.Browser.Node.Model.extend({
+ initialize: function(attrs, args) {
+ var isNew = (_.size(attrs) === 0);
+ if (isNew) {
+ // Set Selected Schema
+ schema = args.node_info.schema.label
+ this.set({'basensp': schema}, {silent: true});
+
+ // Set Current User
+ var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
+ this.set({'owner': userInfo.name}, {silent: true});
+ }
+ pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
+ },
+ defaults: {
+ name: undefined,
+ oid: undefined,
+ owner: undefined,
+ basensp: undefined,
+ description: undefined,
+ basetype: undefined,
+ typlen: undefined,
+ precision: undefined,
+ typdefault: undefined,
+ typnotnull: undefined,
+ sysdomain: undefined,
+ collname: undefined,
+ constraints: [],
+ seclabels: []
+ },
+ type_options: undefined,
+ // Domain Schema
+ schema: [{
+ id: 'name', label: '{{ _('Name') }}', cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit']
+ },{
+ id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+ type: 'text' , mode: ['properties']
+ },{
+ id: 'owner', label:'{{ _('Owner') }}', cell: 'string', control: Backform.NodeListByNameControl,
+ node: 'role', type: 'text', mode: ['edit', 'create', 'properties']
+ },{
+ id: 'basensp', label:'{{ _('Schema') }}', cell: 'node-list-by-name',
+ control: 'node-list-by-name', cache_level: 'database', type: 'text',
+ node: 'schema', mode: ['create', 'edit']
+ },{
+ id: 'sysdomain', label:'{{ _('System Domain?') }}', cell: 'boolean',
+ type: 'switch', mode: ['properties'],
+ options: {
+ 'onText': 'Yes', 'offText': 'No',
+ 'onColor': 'success', 'offColor': 'primary',
+ 'size': 'small'
+ }
+ },{
+ id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+ type: 'multiline'
+ },{
+ id: 'basetype', label:'{{ _('Base Type') }}', cell: 'string', control: 'node-ajax-options',
+ type: 'text', mode:['properties', 'create', 'edit'], group: '{{ _('Definition') }}', url: 'get_types',
+ disabled: function(m) { return !m.isNew(); }, first_empty: true,
+ transform: function(d){
+ this.model.type_options = d;
+ return d;
+ }
+ },{
+ id: 'typlen', label:'{{ _('Length') }}', cell: 'string',
+ type: 'text', group: '{{ _('Definition') }}', deps: ['basetype'],
+ disabled: function(m) {
+ // We will store type from selected from combobox
+ if (!m.isNew()) {
+ return true;
+ }
+ var of_type = m.get('basetype');
+ if(m.type_options) {
+ // iterating over all the types
+ _.each(m.type_options, function(o) {
+ // if type from selected from combobox matches in options
+ if ( of_type == o.value ) {
+ // if length is allowed for selected type
+ if(o.length)
+ {
+ // set the values in model
+ m.set('is_tlength', true, {silent: true});
+ m.set('min_val', o.min_val, {silent: true});
+ m.set('max_val', o.max_val, {silent: true});
+ }
+ }
+ });
+ }
+ return !m.get('is_tlength');
+ }
+ },{
+ id: 'precision', label:'{{ _('Precision') }}', cell: 'string',
+ type: 'text', group: '{{ _('Definition') }}', deps: ['basetype'],
+ disabled: function(m) {
+ // We will store type from selected from combobox
+ if (!m.isNew()) {
+ return true;
+ }
+ var of_type = m.get('basetype');
+ if(m.type_options) {
+ // iterating over all the types
+ _.each(m.type_options, function(o) {
+ // if type from selected from combobox matches in options
+ if ( of_type == o.value ) {
+ // if precession is allowed for selected type
+ if(o.precision)
+ {
+ // set the values in model
+ m.set('is_precision', true, {silent: true});
+ m.set('min_val', o.min_val, {silent: true});
+ m.set('max_val', o.max_val, {silent: true});
+ }
+ }
+ });
+ }
+ return !m.get('is_precision');
+ }
+ },{
+ id: 'typdefault', label:'{{ _('Default') }}', cell: 'string',
+ type: 'text', group: '{{ _('Definition') }}',
+ helpMessage: "Enter an expression or a value."
+ },{
+ id: 'typnotnull', label:'{{ _('Not Null?') }}', cell: 'boolean',
+ type: 'switch', group: '{{ _('Definition') }}',
+ options: {
+ 'onText': 'Yes', 'offText': 'No',
+ 'onColor': 'success', 'offColor': 'primary',
+ 'size': 'small'
+ }
+ },{
+ id: 'collname', label:'{{ _('Collation') }}', cell: 'string', control: 'node-ajax-options',
+ type: 'text', group: '{{ _('Definition') }}', url: 'get_collations', disabled: function(m) {
+ return !m.isNew();
+ }
+ },{
+ id: 'constraints', label:'{{ _('Constraints') }}', cell: 'string',
+ type: 'collection', group: '{{ _('Constraints') }}', mode: ['edit', 'create'],
+ model: ConstraintModel, canAdd: true, canDelete: true,
+ canEdit: false
+ },{
+ id: 'seclabels', label: '{{ _('Security Labels') }}',
+ model: SecurityModel, type: 'collection',
+ group: '{{ _('Security') }}', mode: ['edit', 'create'],
+ min_version: 90100, canAdd: true,
+ canEdit: false, canDelete: true,
+ control: 'unique-col-collection', uniqueCol : ['provider']
+ }
+ ],
+ validate: function() // Client Side Validation
+ {
+ var err = {},
+ errmsg,
+ seclabels = this.get('seclabels');
+
+ if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
+ err['name'] = '{{ _('Name can not be empty!') }}';
+ errmsg = errmsg || err['name'];
+ }
+
+ if (_.isUndefined(this.get('basetype')) || String(this.get('basetype')).replace(/^\s+|\s+$/g, '') == '') {
+ err['basetype'] = '{{ _('Base Type can not be empty!') }}';
+ errmsg = errmsg || err['basetype'];
+ }
+
+ if (seclabels) {
+ var secLabelsErr;
+ for (var i = 0; i < seclabels.models.length && !secLabelsErr; i++) {
+ secLabelsErr = (seclabels.models[i]).validate.apply(seclabels.models[i]);
+ if (secLabelsErr) {
+ err['seclabels'] = secLabelsErr;
+ errmsg = errmsg || secLabelsErr;
+ }
+ }
+ }
+
+ this.errorModel.clear().set(err);
+
+ return null;
+ }
+ }),
+ canCreate: function(itemData, item, data) {
+ //If check is false then , we will allow create menu
+ if (data && data.check == false)
+ return true;
+
+ var t = pgBrowser.tree, i = item, d = itemData;
+ // To iterate over tree to check parent node
+ while (i) {
+ // If it is schema then allow user to create domain
+ if (_.indexOf(['schema'], d._type) > -1)
+ return true;
+
+ if ('coll-domain' == d._type) {
+ //Check if we are not child of catalog
+ prev_i = t.hasParent(i) ? t.parent(i) : null;
+ prev_d = prev_i ? t.itemData(prev_i) : null;
+ if( prev_d._type == 'catalog') {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ i = t.hasParent(i) ? t.parent(i) : null;
+ d = i ? t.itemData(i) : null;
+ }
+ // by default we do not want to allow create menu
+ return true;
+ },
+ isDisabled: function(m){
+ if (!m.isNew()) {
+ var server = this.node_info.server;
+ if (server.version < 90200)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+
+ }
+
+ return pgBrowser.Nodes['domain'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..f8b0b75
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/create.sql
@@ -0,0 +1,30 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% if data %}
+CREATE DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
+ AS {{ conn|qtTypeIdent(data.basetype) }}{% if data.typlen %}({{data.typlen}}{% if data.precision %},{{data.precision}}{% endif %}){% endif %}{% if data.collname %}
+
+ COLLATE {{ data.collname }}{% endif %}{% if data.typdefault %}
+
+ DEFAULT {{ data.typdefault }}{% endif %}{% if data.typnotnull %}
+
+ NOT NULL{% endif %}{% if data.constraints %}{% for c in data.constraints %}{% if c.conname and c.consrc %}
+
+ CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% endif -%}
+{% endfor -%}
+{% endif -%};
+
+{% if data.owner %}
+ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }};{% endif %}{% if data.description %}
+
+
+COMMENT ON DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
+ IS '{{ data.description }}';{% endif -%}{% if data.seclabels %}
+{% for r in data.seclabels %}
+{% if r.security_label and r.provider %}
+
+
+{{ SECLABLE.SET(conn, 'DOMAIN', data.name, r.provider, r.security_label, data.basensp) }}{% endif -%}
+{% endfor -%}
+{% endif -%}
+
+{% endif -%}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..7a12b50
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/delete.sql
@@ -0,0 +1,16 @@
+{% if scid and doid %}
+SELECT
+ d.typname as name, bn.nspname as basensp
+FROM
+ pg_type d
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ d.typnamespace = {{scid}}::oid
+AND
+ d.oid={{doid}}::int;
+{% endif %}
+
+{% if name %}
+DROP DOMAIN {{ conn|qtIdent(basensp, name) }}{% if cascade %} CASCADE{% endif %};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_collations.sql
new file mode 100644
index 0000000..819fdbb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_collations.sql
@@ -0,0 +1,10 @@
+SELECT --nspname, collname,
+ CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
+ concat(nspname, '."', collname,'"')
+ ELSE '' END AS copy_collation
+FROM
+ pg_collation c, pg_namespace n
+WHERE
+ c.collnamespace=n.oid
+ORDER BY
+ nspname, collname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_constraints.sql
new file mode 100644
index 0000000..897fb24
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_constraints.sql
@@ -0,0 +1,15 @@
+SELECT
+ 'DOMAIN' AS objectkind, c.oid as conoid, conname, typname as relname, nspname, description,
+ regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') as cons
+FROM
+ pg_constraint c
+JOIN
+ pg_type t ON t.oid=contypid
+JOIN
+ pg_namespace nl ON nl.oid=typnamespace
+LEFT OUTER JOIN
+ pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)
+WHERE
+ contype = 'c'
+ AND contypid = {{doid}}::oid
+ORDER BY conname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..8b5c891
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,18 @@
+{% if doid %}
+SELECT
+ d.typnamespace as scid
+FROM
+ pg_type d
+WHERE
+ d.oid={{ doid }}::oid;
+{% else %}
+SELECT
+ d.oid, d.typnamespace
+FROM
+ pg_type d
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ bn.nspname = {{ basensp|qtLiteral }}
+ AND d.typname={{ name|qtLiteral }};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/node.sql
new file mode 100644
index 0000000..7bd3e5b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/node.sql
@@ -0,0 +1,13 @@
+SELECT
+ d.oid, d.typname as name, pg_get_userbyid(d.typowner) as owner,
+ bn.nspname as basensp
+FROM
+ pg_type d
+JOIN
+ pg_type b ON b.oid = d.typbasetype
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ d.typnamespace = {{scid}}::oid
+ORDER BY
+ d.typname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..42af39d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/properties.sql
@@ -0,0 +1,35 @@
+SELECT
+ d.oid, d.typname as name, d.typbasetype, format_type(b.oid,NULL) as basetype,
+ pg_get_userbyid(d.typowner) as owner,
+ c.oid AS colloid, format_type(b.oid, d.typtypmod) AS fulltype,
+ CASE WHEN length(cn.nspname) > 0 AND length(c.collname) > 0 THEN
+ concat(cn.nspname, '."', c.collname,'"')
+ ELSE '' END AS collname,
+ d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,
+ description, (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname=d.typname) > 1 AS domisdup,
+ (SELECT COUNT(1) FROM pg_type t3 WHERE t3.typname=b.typname) > 1 AS baseisdup,
+ (SELECT
+ array_agg(provider || '=' || label)
+ FROM
+ pg_seclabel sl1
+ WHERE
+ sl1.objoid=d.oid) AS seclabels
+FROM
+ pg_type d
+JOIN
+ pg_type b ON b.oid = d.typbasetype
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+LEFT OUTER JOIN
+ pg_description des ON (des.objoid=d.oid AND des.classoid='pg_type'::regclass)
+LEFT OUTER JOIN
+ pg_collation c ON d.typcollation=c.oid
+LEFT OUTER JOIN
+ pg_namespace cn ON c.collnamespace=cn.oid
+WHERE
+ d.typnamespace = {{scid}}::oid
+ {% if doid %}
+ AND d.oid={{doid}}::int
+ {% endif %}
+ORDER BY
+ d.typname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..6ff4052
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/update.sql
@@ -0,0 +1,64 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% if data %}
+{% set name = o_data.name %}
+{% if data.name %}
+{% if data.name != o_data.name %}
+ALTER TYPE {{ conn|qtIdent(o_data.basensp, o_data.name) }}
+ RENAME TO {{ conn|qtIdent(data.name) }};
+{% set name = data.name %}
+{% endif %}
+
+{% endif -%}
+{% if data.typnotnull and not o_data.typnotnull %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ SET NOT NULL;
+{% elif 'typnotnull' in data and not data.typnotnull and o_data.typnotnull%}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ DROP NOT NULL;
+{% endif -%}{% if data.typdefault %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ SET DEFAULT {{ data.typdefault }};
+{% elif not data.typdefault and o_data.typdefault %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ DROP DEFAULT;
+{% endif -%}{% if data.owner %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ OWNER TO {{ conn|qtIdent(data.owner) }};{% endif %}{% if data.constraints %}
+{% for c in data.constraints.deleted %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ DROP CONSTRAINT {{ conn|qtIdent(c.conname) }};
+{% endfor -%}
+{% for c in data.constraints.added %}
+{% if c.conname and c.consrc %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }} );{% endif -%}
+{% endfor -%}{% endif -%}
+{% set seclabels = data.seclabels %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABLE.UNSET(conn, 'DOMAIN', name, r.provider, o_data.basensp) }}
+
+{% endfor -%}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
+
+{% endfor -%}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
+
+{% endfor -%}
+{% endif -%}{% if data.description %}
+COMMENT ON DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ IS {{ data.description|qtLiteral }};{% endif %}{% if data.basensp %}
+
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ SET SCHEMA {{ conn|qtIdent(data.basensp) }};{% endif -%}
+{% endif -%}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/create.sql
new file mode 100644
index 0000000..f71e5a3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/create.sql
@@ -0,0 +1,36 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% if data %}
+CREATE DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
+ AS {{ conn|qtTypeIdent(data.basetype) }}{% if data.typlen %}({{data.typlen}}{% if data.precision %},{{data.precision}}{% endif %}){% endif %}{% if data.collname and data.collname != "pg_catalog.\"default\"" %}
+
+ COLLATE {{ data.collname }}{% endif %}{% if data.typdefault %}
+
+ DEFAULT {{ data.typdefault }}{% endif %}{% if data.typnotnull %}
+
+ NOT NULL{% endif %};
+
+{% if data.owner %}
+ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }};{% endif %}
+
+{% if data.constraints %}
+{% for c in data.constraints %}{% if c.conname and c.consrc %}
+
+ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
+ ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if not c.convalidated %} NOT VALID{% endif %}{% endif -%};
+{% endfor -%}
+{% endif %}
+
+{% if data.description %}
+COMMENT ON DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
+ IS '{{ data.description }}';{% endif -%}
+
+{% if data.seclabels %}
+{% for r in data.seclabels %}
+{% if r.security_label and r.provider %}
+
+
+{{ SECLABLE.SET(conn, 'DOMAIN', data.name, r.provider, r.security_label, data.basensp) }}{% endif -%}
+{% endfor -%}
+{% endif -%}
+
+{% endif -%}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/delete.sql
new file mode 100644
index 0000000..7a12b50
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/delete.sql
@@ -0,0 +1,16 @@
+{% if scid and doid %}
+SELECT
+ d.typname as name, bn.nspname as basensp
+FROM
+ pg_type d
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ d.typnamespace = {{scid}}::oid
+AND
+ d.oid={{doid}}::int;
+{% endif %}
+
+{% if name %}
+DROP DOMAIN {{ conn|qtIdent(basensp, name) }}{% if cascade %} CASCADE{% endif %};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_collations.sql
new file mode 100644
index 0000000..e59c17d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_collations.sql
@@ -0,0 +1,10 @@
+SELECT --nspname, collname,
+ CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
+ concat(nspname, '."', collname,'"')
+ ELSE '' END AS copy_collation
+FROM
+ pg_collation c, pg_namespace n
+WHERE
+ c.collnamespace=n.oid
+ORDER BY
+ nspname, collname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql
new file mode 100644
index 0000000..df956bf
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql
@@ -0,0 +1,15 @@
+SELECT
+ 'DOMAIN' AS objectkind, c.oid as conoid, conname, typname as relname, nspname, description,
+ regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') as consrc, connoinherit, convalidated
+FROM
+ pg_constraint c
+JOIN
+ pg_type t ON t.oid=contypid
+JOIN
+ pg_namespace nl ON nl.oid=typnamespace
+LEFT OUTER JOIN
+ pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)
+WHERE
+ contype = 'c' AND contypid = {{doid}}::oid
+ORDER BY
+ conname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_oid.sql
new file mode 100644
index 0000000..8b5c891
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_oid.sql
@@ -0,0 +1,18 @@
+{% if doid %}
+SELECT
+ d.typnamespace as scid
+FROM
+ pg_type d
+WHERE
+ d.oid={{ doid }}::oid;
+{% else %}
+SELECT
+ d.oid, d.typnamespace
+FROM
+ pg_type d
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ bn.nspname = {{ basensp|qtLiteral }}
+ AND d.typname={{ name|qtLiteral }};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/node.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/node.sql
new file mode 100644
index 0000000..7bd3e5b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/node.sql
@@ -0,0 +1,13 @@
+SELECT
+ d.oid, d.typname as name, pg_get_userbyid(d.typowner) as owner,
+ bn.nspname as basensp
+FROM
+ pg_type d
+JOIN
+ pg_type b ON b.oid = d.typbasetype
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+WHERE
+ d.typnamespace = {{scid}}::oid
+ORDER BY
+ d.typname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/properties.sql
new file mode 100644
index 0000000..2892988
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/properties.sql
@@ -0,0 +1,34 @@
+SELECT
+ d.oid, d.typname as name, d.typbasetype, format_type(b.oid,NULL) as basetype, pg_get_userbyid(d.typowner) as owner,
+ c.oid AS colloid, format_type(b.oid, d.typtypmod) AS fulltype,
+ CASE WHEN length(cn.nspname) > 0 AND length(c.collname) > 0 THEN
+ concat(cn.nspname, '."', c.collname,'"')
+ ELSE '' END AS collname,
+ d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,
+ description, (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname=d.typname) > 1 AS domisdup,
+ (SELECT COUNT(1) FROM pg_type t3 WHERE t3.typname=b.typname) > 1 AS baseisdup,
+ (SELECT
+ array_agg(provider || '=' || label)
+ FROM
+ pg_shseclabel sl1
+ WHERE
+ sl1.objoid=d.oid) AS seclabels
+FROM
+ pg_type d
+JOIN
+ pg_type b ON b.oid = d.typbasetype
+JOIN
+ pg_namespace bn ON bn.oid=d.typnamespace
+LEFT OUTER JOIN
+ pg_description des ON (des.objoid=d.oid AND des.classoid='pg_type'::regclass)
+LEFT OUTER JOIN
+ pg_collation c ON d.typcollation=c.oid
+LEFT OUTER JOIN
+ pg_namespace cn ON c.collnamespace=cn.oid
+WHERE
+ d.typnamespace = {{scid}}::oid
+{% if doid %}
+ AND d.oid={{doid}}::int
+{% endif %}
+ORDER BY
+ d.typname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/update.sql
new file mode 100644
index 0000000..ecc7e9a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/update.sql
@@ -0,0 +1,64 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% if data %}
+{% set name = o_data.name %}
+{% if data.name %}
+{% if data.name != o_data.name %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }}
+ RENAME TO {{ conn|qtIdent(data.name) }};
+{% set name = data.name %}
+{% endif %}
+
+{% endif -%}
+{% if data.typnotnull and not o_data.typnotnull %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ SET NOT NULL;
+{% elif 'typnotnull' in data and not data.typnotnull and o_data.typnotnull%}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ DROP NOT NULL;
+{% endif -%}{% if data.typdefault %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ SET DEFAULT {{ data.typdefault }};
+{% elif not data.typdefault and o_data.typdefault %}
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ DROP DEFAULT;
+{% endif -%}{% if data.owner %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ OWNER TO {{ conn|qtIdent(data.owner) }};{% endif %}{% if data.constraints %}
+{% for c in data.constraints.deleted %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ DROP CONSTRAINT {{ conn|qtIdent(c.conname) }};
+{% endfor -%}
+{% for c in data.constraints.added %}
+{% if c.conname and c.consrc %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if c.convalidated %}
+ NOT VALID{% endif %}{% if c.connoinherit %} NO INHERIT{% endif -%};{% endif -%}
+{% endfor -%}{% endif -%}
+{% set seclabels = data.seclabels %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABLE.UNSET(conn, 'DOMAIN', name, r.provider, o_data.basensp) }}
+
+{% endfor %}
+{% endif -%}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+
+{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
+{% endfor %}
+{% endif -%}{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+
+{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
+{% endfor %}
+{% endif -%}{% if data.description %}
+
+COMMENT ON DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ IS {{ data.description|qtLiteral }};{% endif -%}{% if data.basensp %}
+
+ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
+ SET SCHEMA {{ conn|qtIdent(data.basensp) }};{% endif -%}
+{% endif -%}
view thread (29+ messages) latest in thread
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], [email protected]
Subject: Re: pgAdmin4 PATCH: Domain Module
In-Reply-To: <CAFOhELc=PzdATON2Eo0sipm7AC9dtz33YZm-CqTfHUNesuUpwA@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