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, 16 Mar 2016 14:48:10 +0530
Message-ID: <CAFOhELfzRV1WoA7A87=g5Nb9uvU3rLL2jPUCEid66pqzFdrfRQ@mail.gmail.com> (raw)
In-Reply-To: <CA+OCxoxkows1UUgaddq3+R2VcTW9Vmc3QCKdrtd1sNP+fDsHTg@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>
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi,
Please find the updated patch for the Domain Module.
To test this, the Data-type Reader patch needs to be applied first.
Also, please find in-line comments below.
Thanks,
Khushboo
On Thu, Feb 25, 2016 at 7:00 PM, Dave Page <[email protected]> wrote:
> Per discussion with Khushboo, the patch at
> http://www.postgresql.org/message-id/attachment/41939/schemas_macros_10_Feb_2.patch
> is a pre-req for this. Updated comments below...
>
> On Thu, Feb 25, 2016 at 12:13 PM, Dave Page <[email protected]> wrote:
>
>> Hi
>>
>> On Wed, Feb 24, 2016 at 9:24 AM, Khushboo Vashi <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> I have updated the Domain module as below:
>>>
>>> - Used 'NodeByListControl' to get schemas, in domains.js file as
>>> suggested by Ashesh to avoid code redundancy.
>>>
>>> - Applied *'Security Label Macro'* Patch (Implemented by Harshal) and
>>> removed same changes from the Domain Patch.
>>> To test Domain patch, 'Security Label Macro' patch must be applied
>>> first as that is not committed yet.
>>>
>>> Please find attached Domain Module Patch.
>>>
>>
>> Initial feedback:
>>
>> - Owner and schema should be allowed to be left blank (and then default
>> to the current user/schema)
>>
> Done
> - Length and Precision fields should only be enabled if appropriate for
>> the data type.
>>
> Done
> The above still apply.
>
>
>>
>> - SQL generation for new Domains doesn't work:
>>
>
> This now works.
>
>
>>
>> - When adding constraints, I should be able to type directly into the
>> grid. Expanding the row should be optional.
>>
> I have made the grid non-editable explicitly as the Check constraint
control is multi-line control and right now there is no support in the grid
for the multi-line control.
> - The comment column on the constraints grid expands when the text reaches
>> ~50% of the width. It should be a fixed size (and use 100% of the space
>> available, less appropriate margins)
>>
> I have applied the size for the each header of the grid, but if the given
input will be without space in the grid then it will expand. For this, we
can make table layout fixed. So, please suggest, should I do that or not?
> - Backend support checks should not special-case Slony schemas.
>>
>> Done
> - 4 character indentation not used consistently in SQL templates.
>>
> Done
> These still apply.
>
>
>>
>> - Error seen when saving a domain: "macros/schemas/security.macros"
>>
>> 016-02-25 11:55:10,728: INFO werkzeug: 127.0.0.1 - - [25/Feb/2016
>> 11:55:10] "GET
>> /browser/domain/msql/1/1/24587/2200/?name=email&owner=postgres&basensp=public&description=This+is+an+email+data+type&basetype=text&typlen=&precision=&typdefault=&typnotnull=true&collname=&constraints=%5B%5D&seclabels=%5B%5D&_=1456401124386
>> HTTP/1.1" 500 -
>> Traceback (most recent call last):
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1836, in __call__
>> return self.wsgi_app(environ, start_response)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1820, in wsgi_app
>> response = self.make_response(self.handle_exception(e))
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1403, in handle_exception
>> reraise(exc_type, exc_value, tb)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1817, in wsgi_app
>> response = self.full_dispatch_request()
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1477, in full_dispatch_request
>> rv = self.handle_user_exception(e)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1381, in handle_user_exception
>> reraise(exc_type, exc_value, tb)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1475, in full_dispatch_request
>> rv = self.dispatch_request()
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/app.py",
>> line 1461, in dispatch_request
>> return self.view_functions[rule.endpoint](**req.view_args)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/flask/views.py",
>> line 84, in view
>> return self.dispatch_request(*args, **kwargs)
>> File "/Users/dpage/git/pgadmin4/web/pgadmin/browser/utils.py", line
>> 248, in dispatch_request
>> return method(*args, **kwargs)
>> File
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py",
>> line 277, in wrap
>> return f(*args, **kwargs)
>> File
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py",
>> line 232, in wrap
>> return f(self, **kwargs)
>> File
>> "/Users/dpage/git/pgadmin4/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py",
>> line 700, in msql
>> status=200
>> File "/Users/dpage/git/pgadmin4/web/pgadmin/utils/ajax.py", line 41, in
>> make_json_response
>> response=json.dumps(doc, cls=DataTypeJSONEncoder),
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/simplejson/__init__.py",
>> line 386, in dumps
>> **kw).encode(obj)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/simplejson/encoder.py",
>> line 269, in encode
>> chunks = self.iterencode(o, _one_shot=True)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/simplejson/encoder.py",
>> line 348, in iterencode
>> return _iterencode(o, 0)
>> File "/Users/dpage/git/pgadmin4/web/pgadmin/utils/ajax.py", line 26, in
>> default
>> return json.JSONEncoder.default(self, obj)
>> File
>> "/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/simplejson/encoder.py",
>> line 246, in default
>> raise TypeError(repr(o) + " is not JSON serializable")
>> TypeError: TemplateNotFound() is not JSON serializable
>>
>
> This issue is resolved.
>
> Additional issues:
>
> - We can add a comment to constraints (and view them), however they are
> not saved.
>
> Done
> - The domain is not created as a single SQL statement, but by creating a
> domain over the base type, then adding constraints. Can this be done in one
> query?
>
Done
> - Reverse engineered SQL doesn't include the normal header and
> commented-out drop statement.
>
Done
> Thanks.
>
> --
> 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_4.patch (99.2K, 3-domains_ver_4.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..2c273e4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py
@@ -0,0 +1,806 @@
+##########################################################################
+#
+# 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
+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)
+
+ 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:
+ SQL = render_template("/".join([self.template_path, 'create.sql']),
+ data=data)
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # 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=name)
+
+ 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']
+
+ # Toggle Validate and inherit options for 'CREATE Query'
+ for c in data['constraints']:
+ if 'convalidated' in c:
+ c['convalidated'] = False if c['convalidated'] else True
+ if 'connoinherit' in c:
+ c['connoinherit'] = False if c['connoinherit'] else True
+
+ 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)
+
+ @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
+
+ 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..d16bb60
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/__init__.py
@@ -0,0 +1,653 @@
+##########################################################################
+#
+# 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
+
+
+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 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']:
+ res.append(
+ self.blueprint.generate_browser_node(
+ row['oid'],
+ doid,
+ row['name'],
+ icon="icon-domain-constraints"
+ ))
+
+ 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]
+ if 'convalidated' in data:
+ data['convalidated'] = not data['convalidated']
+ return ajax_response(
+ response=data,
+ status=200
+ )
+
+ @check_precondition
+ 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
+
+ Required Args:
+ name: Constraints Name
+ consrc: Constraints Check
+
+ Returns:
+ Domain Constraint object in json format.
+ """
+
+ data = request.form if request.form else \
+ json.loads(request.data.decode())
+ required_args = [
+ 'name',
+ 'consrc'
+ ]
+
+ for arg in required_args:
+ if arg not in data:
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ "Couldn't find the required parameter (%s)." % arg
+ )
+ )
+
+ try:
+ # Get Schema and Domain.
+ SQL = render_template("/".join([self.template_path,
+ 'get_domain.sql']),
+ doid=doid)
+ status, res = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ domain, schema = res['rows'][0]
+
+ SQL = render_template("/".join([self.template_path,
+ 'create.sql']),
+ data=data, domain=domain, schema=schema)
+ 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=doid)
+
+ return jsonify(
+ node=self.blueprint.generate_browser_node(
+ coid,
+ doid,
+ data['name'],
+ icon="icon-domain-constraints"
+ )
+ )
+ 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
+ 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 = request.form if request.form else \
+ json.loads(request.data.decode())
+
+ 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)
+
+ return make_json_response(
+ success=1,
+ info="Domain Constraint updated",
+ data={
+ 'id': coid,
+ 'doid': doid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+ 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.
+ SQL = render_template("/".join([self.template_path,
+ 'get_domain.sql']),
+ doid=doid)
+ status, res = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=name)
+
+ domain, schema = res['rows'][0]
+
+ 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]
+ if 'convalidated' in data:
+ data['convalidated'] = False if data['convalidated'] else True
+ if 'connoinherit' in data:
+ data['connoinherit'] = False if data['connoinherit'] else True
+
+ 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
+ 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
+
+ Required Args:
+ name: Constraints Name
+ consrc: Constraints Check
+
+ Returns:
+ Domain Constraint object in json format.
+ """
+ data = request.args
+
+ if coid is None:
+ required_args = [
+ 'name',
+ 'consrc'
+ ]
+
+ for arg in required_args:
+ if arg not in data:
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ "Couldn't find the required parameter (%s)." % arg
+ )
+ )
+ 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:
+ 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=name)
+
+ domain, schema = res['rows'][0]
+
+ SQL = render_template("/".join([self.template_path,
+ 'create.sql']),
+ data=data, domain=domain, schema=schema)
+ return True, SQL
+ except Exception as e:
+ return False, internal_server_error(errormsg=str(e))
+
+ @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/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..166cabc
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/js/domain-constraints.js
@@ -0,0 +1,149 @@
+// 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,
+ convalidated_p: 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: "{{ _("Don't Validate") }}", type: 'switch', cell:
+ 'boolean', group: '{{ _('Definition') }}', 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 true;
+ },
+ mode: ['create', 'edit'], visible: function(m) { return !m.isNew() }
+ },{
+ id: 'convalidated_p', label: '{{ _('Valid?') }}', type: 'switch', cell:
+ 'boolean', group: '{{ _('Definition') }}', disabled: 'isDisabled',
+ mode: ['properties']
+ }],
+ // 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..513c38d
--- /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,9 @@
+{% if data and schema and domain %}
+ALTER DOMAIN {{ conn|qtIdent(schema, domain) }}
+ ADD CONSTRAINT {{ conn|qtIdent(data.name) }} CHECK ({{ data.consrc }}){% if 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/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..b436f3a
--- /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..5037fcf
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/js/domains.js
@@ -0,0 +1,330 @@
+// 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'
+ },{
+ id: 'security_label', label: '{{ _('Security Label') }}',
+ type: 'text'
+ }],
+ validate: function() {
+ var err = {},
+ errmsg = null,
+ data = this.toJSON();
+
+ if (_.isUndefined(data.label) ||
+ _.isNull(data.label) ||
+ String(data.label).replace(/^\s+|\s+$/g, '') == '') {
+ return _("Please specify the value for all the security providers.");
+ }
+ return null;
+ }
+ });
+
+ // Constraint Model
+ var ConstraintModel = pgAdmin.Browser.Node.Model.extend({
+ idAttribute: 'conname',
+ defaults: {
+ conname: undefined,
+ description: undefined,
+ consrc: undefined,
+ connoinherit: undefined,
+ convalidated: undefined
+ },
+ schema: [{
+ id: 'conname', label: '{{ _('Name') }}', type: 'text', cell: 'string',
+ cellHeaderClasses: 'width_percent_40'
+ },{
+ id: 'consrc', label: '{{ _('Check') }}', type: 'multiline',
+ cell: 'string', group: '{{ _('Definition') }}',
+ cellHeaderClasses: 'width_percent_60'
+ }],
+ isEditable: function(m) {
+ return true
+ //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'
+ },{
+ id: 'sysdomain', label:'{{ _('System Domain?') }}', cell: 'boolean',
+ type: 'switch', mode: ['properties']
+ },{
+ 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') }}'
+ },{
+ id: 'typnotnull', label:'{{ _('Not Null') }}', cell: 'boolean',
+ type: 'switch', group: '{{ _('Definition') }}'
+ },{
+ 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: function(o){
+ if (o instanceof Backbone.Model) {
+ if (o instanceof ConstraintModel) {
+ return o.isNew();
+ }
+ }
+ return true;
+ }
+ },{
+ id: 'seclabels', label: '{{ _('Security Labels') }}',
+ model: SecurityModel, type: 'collection',
+ group: '{{ _('Security') }}', mode: ['edit', 'create'],
+ min_version: 90100, canAdd: true,
+ canEdit: true, canDelete: true
+ }
+ ],
+ 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..f17f0c5
--- /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, 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..858ae91
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/update.sql
@@ -0,0 +1,65 @@
+{% 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..e89369f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_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 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.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.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..29a203c
--- /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, 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..a09cef5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/update.sql
@@ -0,0 +1,66 @@
+{% 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 %}
+
+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 -%};
+{% 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: <CAFOhELfzRV1WoA7A87=g5Nb9uvU3rLL2jPUCEid66pqzFdrfRQ@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