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..4b419bb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py @@ -0,0 +1,778 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""The Domain 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 as schemas +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 DomainModule(CollectionNodeModule): + """ + class DomainModule(CollectionNodeModule): + + 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): + """ + class DomainView + + 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. + + Methods: + ------- + * validate_request(f): + - Works as a decorator. + Validating request on the request of create, update and modified SQL. + + * module_js(): + - Overrides this property to define javascript for Domain node. + + * 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. + + * get_types(gid, sid, did, scid, doid=None): + - Returns Data Types. + + * 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. + """ + + 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_collations': [ + {'get': 'get_collations'}, + {'get': 'get_collations'} + ], + 'get_types': [{'get': 'get_types'}, {'get': 'get_types'}] + }) + + 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 + basttype: 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) + else: + req = request.args or request.form + + if 'doid' not in kwargs: + required_args = [ + 'name', + 'owner', + 'basensp', + '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): + """ + Overrides this property to define javascript for Domain node. + """ + 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] + + # 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 data['fulltype'] != '' and data['fulltype'].find("(") > 0: + substr = data['fulltype'][data['fulltype'].find("(") + 1:len( + data['fulltype']) - 1] + typlen = substr.split(",") + if len(typlen) > 1: + data['typlen'] = typlen[0] + data['precision'] = typlen[1] + else: + data['typlen'] = typlen + data['precision'] = '' + + # 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'] + + # 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 + ) + + @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 get_types(self, gid, sid, did, scid, doid=None): + """ + Returns Types. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + doid: Domain Id + """ + + # TODO: This function should be removed once + # Types module will be completed. + + res = [{'label': '', 'value': ''}] + try: + SQL = render_template("/".join([self.template_path, + 'get_types.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['typname'], + 'value': row['typname']} + ) + + return make_json_response( + data=res, + status=200 + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @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 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']: + c['convalidated'] = False if c['convalidated'] else True + c['connoinherit'] = False if c['connoinherit'] else True + + SQL = render_template("/".join([self.template_path, + 'create.sql']), data=data) + + 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..370e585 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/__init__.py @@ -0,0 +1,640 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""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) + - Override this property to make the 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): + """ + Override this property to make the 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(): + - Overrides this property to define javascript for Domain Constraint node. + + * 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): + """ + Overrides this property to define javascript for Domain Constraint node. + """ + 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) + + return ajax_response( + response=res['rows'][0], + 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] + data['convalidated'] = False if data['convalidated'] else True + data['connoinherit'] = False if data['connoinherit'] else True + + SQL = render_template("/".join([self.template_path, + 'create.sql']), + data=data, domain=domain, schema=schema) + + 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 znRGPqvlydizRJ&>B`Om#V}R-yOM?7@862M7NCR>>3p^r=fwTu0yPeFo z12TL)T^vI=t|uoPU||ZF@;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)Px$AW%$HMR1Z9#Q*@REHmdHAm<<;=p`lTDl6$LE15$|nM6yxJ3#6&F}^)Qx|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`($_HuH3pdDu=8uhpjJ) zvN4agH<6_L$tcPam4X*+~mi`^K{Glc|xhhkN@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(Kax(GBB{1sVaw}AvZrIGp!P$!N3x%0i@c>zzm|{ T)b!9bKn)C@u6{1-oD!M<=4O^k literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/css/domain-constraints.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/css/domain-constraints.css new file mode 100644 index 0000000..57b6612 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/css/domain-constraints.css @@ -0,0 +1,8 @@ +.pg-icon-domain-constraints { + background-image: url('{{ url_for('NODE-domain-constraints.static', filename='img/domain-constraints.png') }}') !important; + border-radius: 10px; + background-repeat: no-repeat; + align-content: center; + vertical-align: middle; + height: 1.3em; +} 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..d9e23a8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain-constraints/templates/domain-constraints/js/domain-constraints.js @@ -0,0 +1,129 @@ +// 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' + }); + }; + + // 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, + description: undefined, + consrc: undefined, + connoinherit: undefined, + convalidated: undefined + }, + // Domain Constraint Schema + schema: [{ + id: 'name', label: '{{ _('Name') }}', type:'text', cell:'string', + disabled: 'isDisabled' + },{ + id: 'description', label: '{{ _('Comment') }}', type: 'multiline', cell: + 'string', mode: ['properties', 'create', 'edit'], disabled: function + (m) { return !m.isNew(); } + },{ + 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' + },{ + id: 'convalidated', label: "Don't Validate", type: 'switch', cell: + 'boolean', group: '{{ _('Definition') }}', disabled: 'isDisabled', + mode: ['create', 'edit'] + },{ + id: 'convalidated', 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..22bad72 --- /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,4 @@ +{% 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..95b7310 --- /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,30 @@ +SELECT + 'TABLE' AS objectkind, c.oid, conname as name, relname, nspname, description, + pg_get_expr(conbin, conrelid, true) as consrc +FROM + pg_constraint c +JOIN + pg_class cl ON cl.oid=conrelid +JOIN + pg_namespace nl ON nl.oid=relnamespace +LEFT OUTER JOIN + pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass) +WHERE + contype = 'c' AND conrelid = {{doid}}::oid +UNION +SELECT + 'DOMAIN' AS objectkind, c.oid, conname as name, typname as relname, nspname, description, + 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 +LEFT OUTER JOIN + pg_description des ON (des.objoid=t.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.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..d574430 --- /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,4 @@ +{% 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..c50e486 --- /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,8 @@ +{% 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.connoinherit %} + + NO INHERIT{% 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..80b7ced --- /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,29 @@ +SELECT + 'TABLE' AS objectkind, c.oid, conname as name, relname, nspname, description, + pg_get_expr(conbin, conrelid, true) as consrc, connoinherit, convalidated +FROM + pg_constraint c +JOIN + pg_class cl ON cl.oid=conrelid +JOIN + pg_namespace nl ON nl.oid=relnamespace +LEFT OUTER JOIN + pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass) +WHERE + contype = 'c' AND conrelid = {{doid}}::oid +UNION +SELECT + 'DOMAIN' AS objectkind, 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 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 +{% 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..d574430 --- /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,4 @@ +{% 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/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(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&#$$$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^$zTSWSoH+CHUa^}pVf`aWvMt7fm zx&8F>jfd~AY(HF`mUiRG=W9@QLHo+%PZuA3I{)y~*$1D_JotF({zvHt zo%ulf7)yfuf*Bm1-ADs+I14-?i-EKU7`vU!wgWPXJzX3_Brcbpe=XFcAmSFNeC3q& zl!Z+(RsYN12&-NW{P*^#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/css/domains.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/css/domains.css new file mode 100644 index 0000000..ab9e776 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/css/domains.css @@ -0,0 +1,8 @@ +.pg-icon-domain { + background-image: url('{{ url_for('NODE-domain.static', filename='img/domain.png') }}') !important; + border-radius: 10px; + background-repeat: no-repeat; + align-content: center; + vertical-align: middle; + height: 1.3em; +} 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..50440fc --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/js/domains.js @@ -0,0 +1,290 @@ +// 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', 'oid', 'owner', 'basensp', 'description', 'basetype', + 'typdefault', 'typnotnull', 'sysdomain'] + }); + }; + + // 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 ConstraintsModel = 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' + },{ + id: 'description', label: '{{ _('Comment') }}', type: 'multiline', cell: 'string' + },{ + id: 'consrc', label: '{{ _('Check') }}', type: 'multiline', + cell: 'string', group: '{{ _('Definition') }}' + },{ + id: 'connoinherit', label: '{{ _('No Inherit') }}', type: 'switch', + cell:'boolean', group: '{{ _('Definition') }}' + },{ + id: 'convalidated', label: '{{ _('Valid?') }}', type: + 'switch', cell: 'boolean', group: '{{ _('Definition') }}', mode: + ['properties'] + },{ + id: 'convalidated', label: "Don't Validate", type: + 'switch', cell: 'boolean', group: '{{ _('Definition') }}', mode: + ['create', 'edit'] + }], + validate: function() { + // TODO: Add validation here + }, + 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({ + 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: [] + }, + // 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: '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(); } + },{ + id: 'typlen', label:'{{ _('Length') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: function(m) { return !m.isNew(); } + },{ + id: 'precision', label:'{{ _('Precision') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}', disabled: function(m) { return !m.isNew(); } + },{ + id: 'typdefault', label:'{{ _('Default') }}', cell: 'string', + type: 'text', group: '{{ _('Definition') }}' + },{ + id: 'typnotnull', label:'{{ _('Not Null') }}', cell: 'boolean', + type: 'switch', group: '{{ _('Definition') }}' + },{ + id: 'sysdomain', label:'{{ _('System Domain?') }}', cell: 'boolean', + type: 'switch', group: '{{ _('Definition') }}', mode: ['properties'] + },{ + 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') }}', visible: false, mode: ['edit', 'create'], + model: ConstraintsModel, canAdd: true, canDelete: true, canEdit: function(o) { + if (o instanceof Backbone.Model) { + if (o instanceof ConstraintsModel) { + 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('owner')) || String(this.get('owner')) + .replace(/^\s+|\s+$/g, '') == '') { + err['owner'] = '{{ _('Owner can not be empty!') }}'; + errmsg = errmsg || err['owner']; + } + + if (_.isUndefined(this.get('basensp')) || String(this.get('basensp')) + .replace(/^\s+|\s+$/g, '') == '') { + err['basensp'] = '{{ _('Schema can not be empty!') }}'; + errmsg = errmsg || err['basensp']; + } + + 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); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + 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/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/backend_support.sql new file mode 100644 index 0000000..8f3db8e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/backend_support.sql @@ -0,0 +1,20 @@ +SELECT + CASE WHEN nsp.nspname IN ('sys', 'dbo', 'information_schema') THEN true ELSE false END AS dbSupport +FROM + pg_namespace nsp +WHERE + nsp.oid={{scid}}::int + AND ( + (nspname = 'pg_catalog' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1)) + OR (nspname = 'pgagent' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1)) + OR (nspname = 'information_schema' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1)) + OR (nspname LIKE '_%' AND EXISTS + (SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1)) + ) + AND + nspname NOT LIKE E'pg\\temp\\%' + AND + nspname NOT LIKE E'pg\\toast_temp\\%' 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..1fe1585 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/create.sql @@ -0,0 +1,37 @@ +{% 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 and data.collname != "pg_catalog.\"default\"" }}{% 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 %}ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} + ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}); +{% endif %} +{% endfor %} +{% endif -%} + +ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }}; + +{% 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..4b1e49f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/delete.sql @@ -0,0 +1,15 @@ +{% 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..c448844 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_constraints.sql @@ -0,0 +1,29 @@ +SELECT + 'TABLE' AS objectkind, c.oid, conname, relname, nspname, description, + pg_get_expr(conbin, conrelid, true) as consrc +FROM + pg_constraint c +JOIN + pg_class cl ON cl.oid=conrelid +JOIN + pg_namespace nl ON nl.oid=relnamespace +LEFT OUTER JOIN + pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass) +WHERE + contype = 'c' AND conrelid = {{doid}}::oid +UNION +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..427b583 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_oid.sql @@ -0,0 +1,19 @@ +{% 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/get_schemas.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_schemas.sql new file mode 100644 index 0000000..adb3338 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_schemas.sql @@ -0,0 +1,24 @@ +SELECT + nsp.nspname +FROM + pg_namespace nsp +LEFT OUTER JOIN + pg_description des ON (des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass) +LEFT OUTER JOIN + pg_catalog.pg_default_acl dacl ON (dacl.defaclnamespace = nsp.oid) +WHERE + NOT ((nspname = 'pg_catalog' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1)) OR + (nspname = 'pgagent' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1)) OR + (nspname = 'information_schema' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1)) OR + (nspname LIKE '_%' AND EXISTS + (SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1)) + )AND + nspname NOT LIKE E'pg\\temp\\%' AND + nspname NOT LIKE E'pg\\toast_temp\\%' AND + -- ADDED: Because We need to omit system schema except the one on which we are trying to create collation + ( nsp.oid = {{ scid }} OR nspname NOT LIKE E'pg\\_%' ) +ORDER BY + nspname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_types.sql new file mode 100644 index 0000000..97621b0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/get_types.sql @@ -0,0 +1,22 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, + typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND typisdefined AND typtype IN ('b', 'c', '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')) + ) AS dummy +ORDER BY + nspname <> 'pg_catalog', nspname <> 'public', nspname, 1 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..216fafe --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/properties.sql @@ -0,0 +1,28 @@ +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 +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..81a210b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.1_plus/update.sql @@ -0,0 +1,84 @@ +{% 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|qtLiteral }}; +{% 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/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/backend_support.sql new file mode 100644 index 0000000..8f3db8e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/backend_support.sql @@ -0,0 +1,20 @@ +SELECT + CASE WHEN nsp.nspname IN ('sys', 'dbo', 'information_schema') THEN true ELSE false END AS dbSupport +FROM + pg_namespace nsp +WHERE + nsp.oid={{scid}}::int + AND ( + (nspname = 'pg_catalog' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1)) + OR (nspname = 'pgagent' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1)) + OR (nspname = 'information_schema' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1)) + OR (nspname LIKE '_%' AND EXISTS + (SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1)) + ) + AND + nspname NOT LIKE E'pg\\temp\\%' + AND + nspname NOT LIKE E'pg\\toast_temp\\%' 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..84819e3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/create.sql @@ -0,0 +1,40 @@ +{% 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 %}ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} + ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if c.convalidated %} + + NOT VALID {% endif %}{% if c.connoinherit %} NO INHERIT{% endif %}; +{% endif -%} +{% endfor %} +{% endif -%} + +ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }}; + +{% 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..7f437ef --- /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..01c8475 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql @@ -0,0 +1,29 @@ +SELECT + 'TABLE' AS objectkind, c.oid, conname, relname, nspname, description, + pg_get_expr(conbin, conrelid, true) as consrc, connoinherit, convalidated +FROM + pg_constraint c +JOIN + pg_class cl ON cl.oid=conrelid +JOIN + pg_namespace nl ON nl.oid=relnamespace +LEFT OUTER JOIN + pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass) +WHERE + contype = 'c' AND conrelid = {{doid}}::oid +UNION +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..427b583 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_oid.sql @@ -0,0 +1,19 @@ +{% 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/get_schemas.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_schemas.sql new file mode 100644 index 0000000..ec62dd6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_schemas.sql @@ -0,0 +1,24 @@ +SELECT + nsp.nspname +FROM + pg_namespace nsp +LEFT OUTER JOIN + pg_description des ON (des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass) + LEFT OUTER JOIN + pg_catalog.pg_default_acl dacl ON (dacl.defaclnamespace = nsp.oid) +WHERE + NOT ((nspname = 'pg_catalog' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1)) OR + (nspname = 'pgagent' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1)) OR + (nspname = 'information_schema' AND EXISTS + (SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1)) OR + (nspname LIKE '_%' AND EXISTS + (SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1)) + )AND + nspname NOT LIKE E'pg\\temp\\%' AND + nspname NOT LIKE E'pg\\toast_temp\\%' AND + -- ADDED: Because We need to omit system schema except the one on which we are trying to create collation + ( nsp.oid = {{ scid }} OR nspname NOT LIKE E'pg\\_%' ) +ORDER BY + nspname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_types.sql new file mode 100644 index 0000000..c4d46f7 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_types.sql @@ -0,0 +1,22 @@ +SELECT + * +FROM + (SELECT + format_type(t.oid,NULL) AS typname, + CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid, + typlen, typtype, t.oid, nspname, + (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup + FROM + pg_type t + JOIN + pg_namespace nsp ON typnamespace=nsp.oid + WHERE + (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) + AND typisdefined AND typtype IN ('b', 'c', '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')) + ) AS dummy +ORDER BY + nspname <> 'pg_catalog', nspname <> 'public', nspname, 1 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..5dd2d01 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/properties.sql @@ -0,0 +1,29 @@ +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..657859c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/update.sql @@ -0,0 +1,82 @@ +{% 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|qtLiteral }}; +{% 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 %} diff --git a/web/pgadmin/browser/static/js/datamodel.js b/web/pgadmin/browser/static/js/datamodel.js index 9385adf..61e81ed 100644 --- a/web/pgadmin/browser/static/js/datamodel.js +++ b/web/pgadmin/browser/static/js/datamodel.js @@ -340,7 +340,13 @@ function(_, pgAdmin, $, Backbone) { delete res[k]; } } else { - res[k] = (obj && obj.toJSON()); + if (obj && (obj instanceof Array)) { + res[k] = obj; + } + else + { + res[k] = obj && obj.toJSON(); + } } }); return res; diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index 4346156..ae807cb 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -1058,11 +1058,13 @@ if (data.disabled == false && data.canEdit) { var editCell = Backgrid.Extension.ObjectCell.extend({ schema: gridSchema.schema - }); + }), + canEdit = self.field.has('canEdit') && + self.field.get('canEdit') || true; gridSchema.columns.unshift({ name: "pg-backform-edit", label: "", cell : editCell, - cell_priority: -2 + cell_priority: -2, editable: canEdit }); } @@ -1101,7 +1103,7 @@ grid.insertRow({}); var newRow = $(grid.body.rows[collection.length - 1].$el); newRow.attr("class", "new").click(function(e) { - $(this).attr("class", ""); + $(this).attr("class", "editable"); }); $(newRow).pgMakeVisible('backform-tab'); return false; @@ -1528,8 +1530,15 @@ /* * Add empty option as Select2 requires any empty '')).select2(col.select2); + var s = this.$el.find("select"); + if (!col.select2.multiple) { + s.prepend($('')); + } + s.select2(col.select2); + return this; } });