public inbox for [email protected]
help / color / mirror / Atom feedFrom: Murtuza Zabuawala <[email protected]>
To: pgadmin-hackers <[email protected]>
Subject: PATCH: Added Node Type & Catalog objects [pgAdmin4]
Date: Tue, 8 Mar 2016 19:08:34 +0530
Message-ID: <CAKKotZSda6+wgyzckDJPXKK3dc8U-UXho9hmaaBp+LwZzdnhaQ@mail.gmail.com> (raw)
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi,
PFA patch to add new nodes in pgAdmin4.
1) Type node
2) Catalog objects
*Note:* Both above nodes depended on schema/catalog node, Please apply them
after latest patch of schema/catalog from Ashesh.
- Type node also depends on parse_priv_function_templates.patch (which I
sent in separate email today)
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[application/octet-stream] type_node_v1.patch (129.9K, 3-type_node_v1.patch)
download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
new file mode 100644
index 0000000..f9f962b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
@@ -0,0 +1,1170 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Type Node """
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+ make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.server_groups.servers.databases.schemas.utils \
+ import SchemaChildModule
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+ parse_priv_to_db
+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 TypeModule(SchemaChildModule):
+ """
+ class TypeModule(SchemaChildModule)
+
+ A module class for Type node derived from SchemaChildModule
+
+ Methods:
+ -------
+ * __init__(*args, **kwargs)
+ - Method is used to initialize the Type and it's base module.
+
+ * get_nodes(gid, sid, did, scid, tid)
+ - Method is used to generate the browser collection node.
+
+ * node_inode()
+ - Method is overridden from its base class to make the node as leaf node.
+
+ * script_load()
+ - Load the module script for schema, when any of the server node is
+ initialized.
+ """
+
+ NODE_TYPE = 'type'
+ COLLECTION_LABEL = gettext("Types")
+
+ def __init__(self, *args, **kwargs):
+ """
+ Method is used to initialize the TypeModule and it's base module.
+
+ Args:
+ *args:
+ **kwargs:
+ """
+ super(TypeModule, self).__init__(*args, **kwargs)
+ self.min_ver = None
+ self.max_ver = None
+
+ def get_nodes(self, gid, sid, did, scid):
+ """
+ Generate the collection node
+ """
+ yield self.generate_browser_collection_node(scid)
+
+ @property
+ def script_load(self):
+ """
+ Load the module script for database, when any of the database node is
+ initialized.
+ """
+ return database.DatabaseModule.NODE_TYPE
+
+ @property
+ def node_inode(self):
+ """
+ Load the module node as a leaf node
+ """
+ return False
+
+ @property
+ def show_system_objects(self):
+ """
+ Flag to set show system Type
+ """
+ return True
+
+blueprint = TypeModule(__name__)
+
+
+class TypeView(PGChildNodeView):
+ """
+ This class is responsible for generating routes for Type node
+
+ Methods:
+ -------
+ * __init__(**kwargs)
+ - Method is used to initialize the TypeView and it's base view.
+
+ * check_precondition()
+ - This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+
+ * list()
+ - This function is used to list all the Type nodes within that
+ collection.
+
+ * nodes()
+ - This function will used to create all the child node within that
+ collection, Here it will create all the Type node.
+
+ * properties(gid, sid, did, scid, tid)
+ - This function will show the properties of the selected Type node
+
+ * create(gid, sid, did, scid)
+ - This function will create the new Type object
+
+ * update(gid, sid, did, scid, tid)
+ - This function will update the data for the selected Type node
+
+ * delete(self, gid, sid, scid, tid):
+ - This function will drop the Type object
+
+ * msql(gid, sid, did, scid, tid)
+ - This function is used to return modified SQL for the selected
+ Type node
+
+ * get_sql(data, scid, tid)
+ - This function will generate sql from model data
+
+ * sql(gid, sid, did, scid):
+ - This function will generate sql to show it in sql pane for the
+ selected Type node.
+
+ * dependency(gid, sid, did, scid, tid):
+ - This function will generate dependency list show it in dependency
+ pane for the selected Type node.
+
+ * dependent(gid, sid, did, scid, tid):
+ - This function will generate dependent list to show it in dependent
+ pane for the selected Type node.
+
+ * additional_properties(copy_dict, tid):
+ - This function will add additional properties in response
+
+ * get_collations(gid, sid, did, scid, tid):
+ - This function will return list of collation in ajax response
+
+ * get_types(gid, sid, did, scid, tid):
+ - This function will return list of types in ajax response
+
+ * get_subtypes(gid, sid, did, scid, tid):
+ - This function will return list of subtypes in ajax response
+
+ * get_subtype_opclass(gid, sid, did, scid, tid):
+ - This function will return list of subtype opclass in ajax response
+
+ * get_subtype_diff(gid, sid, did, scid, tid):
+ - This function will return list of subtype diff functions
+ in ajax response
+
+ * get_canonical(gid, sid, did, scid, tid):
+ - This function will return list of canonical functions
+ in ajax response
+
+ * get_external_functions_list(gid, sid, did, scid, tid):
+ - This function will return list of external functions
+ in ajax response
+ """
+
+ 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': 'tid'}
+ ]
+
+ operations = dict({
+ 'obj': [
+ {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+ {'get': 'list', 'post': 'create'}
+ ],
+ 'delete': [{'delete': 'delete'}],
+ 'children': [{'get': 'children'}],
+ 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+ 'sql': [{'get': 'sql'}],
+ 'msql': [{'get': 'msql'}, {'get': 'msql'}],
+ 'stats': [{'get': 'statistics'}],
+ 'dependency': [{'get': 'dependencies'}],
+ 'dependent': [{'get': 'dependents'}],
+ 'module.js': [{}, {}, {'get': 'module_js'}],
+ 'get_types': [{'get': 'get_types'}, {'get': 'get_types'}],
+ 'get_stypes': [{'get': 'get_subtypes'}, {'get': 'get_subtypes'}],
+ 'get_subopclass': [{'get': 'get_subtype_opclass'},
+ {'get': 'get_subtype_opclass'}],
+ 'get_stypediff': [{'get': 'get_subtype_diff'}, {'get': 'get_subtype_diff'}],
+ 'get_canonical': [{'get': 'get_canonical'}, {'get': 'get_canonical'}],
+ 'get_collations': [{'get': 'get_collations'}, {'get': 'get_collations'}],
+ 'get_external_functions': [{'get': 'get_external_functions_list'},
+ {'get': 'get_external_functions_list'}]
+ })
+
+ def check_precondition(f):
+ """
+ This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+ """
+ @wraps(f)
+ def wrap(*args, **kwargs):
+ # Here args[0] will hold self & kwargs will hold gid,sid,did
+ self = args[0]
+ self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
+ self.conn = self.manager.connection(did=kwargs['did'])
+
+ # We need datlastsysoid to check if current type is system type
+ self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid']
+
+ # 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!"
+ )
+ )
+
+ # Declare allows acl on type
+ self.acl = ['U']
+
+ # we will set template path for sql scripts
+ ver = self.manager.version
+ if 90000 >= ver < 90100:
+ self.template_path = 'type/sql/pre_9.1'
+ else:
+ self.template_path = 'type/sql/9.1_plus'
+ return f(*args, **kwargs)
+
+ return wrap
+
+ @check_precondition
+ def list(self, gid, sid, did, scid):
+ """
+ This function is used to list all the schema nodes within that collection.
+
+ Args:
+ gid: Server group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+
+ Returns:
+ JSON of available schema nodes
+ """
+
+ SQL = render_template("/".join([self.template_path, 'properties.sql']), scid=scid,
+ datlastsysoid=self.datlastsysoid)
+ 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):
+ """
+ This function will used to create all the child node within that collection.
+ Here it will create all the schema node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+
+ Returns:
+ JSON of available type child nodes
+ """
+
+ res = []
+ SQL = render_template("/".join([self.template_path,
+ 'nodes.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-type"
+ ))
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ def additional_properties(self, copy_dict, tid):
+ """
+ We will use this function to add additional properties according to type
+
+ Returns:
+ additional properties for type like range/composite/enum
+
+ """
+ # Fetching type of type
+ of_type = copy_dict['typtype']
+ res = dict()
+ # If type is of Composite then we need to add members list in our output
+ if of_type == 'c':
+ SQL = render_template("/".join([self.template_path,
+ 'additional_properties.sql']),
+ type='c',
+ typrelid=copy_dict['typrelid'])
+ status, rset = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # To display in properties
+ properties_list = []
+ # To display in composite collection grid
+ composite_lst = []
+
+ for row in rset['rows']:
+ typelist = ' '.join([row['attname'], row['typname']])
+ if not row['collname'] or (row['collname'] == 'default'
+ and row['collnspname'] == 'pg_catalog'):
+ full_collate = ''
+ collate = ''
+ else:
+ full_collate = get_driver(PG_DEFAULT_DRIVER).qtIdent(
+ self.conn, row['collnspname'], row['collname'])
+ collate = ' COLLATE ' + full_collate
+ typelist += collate
+ properties_list.append(typelist)
+
+ # Below logic will allow us to split length, precision from type name for grid
+ import re
+ matchObj = re.match( r'(.*)\((.*?),(.*?)\)', row['typname'])
+ if matchObj:
+ t_name = matchObj.group(1)
+ t_len = matchObj.group(2)
+ t_prec = matchObj.group(3)
+ else:
+ t_name = row['typname']
+ t_len = None
+ t_prec = None
+
+ composite_lst.append({
+ 'member_name': row['attname'], 'type': t_name, 'collation': full_collate,
+ 'tlength': t_len, 'precision': t_prec })
+
+ # Adding both results
+ res['member_list'] = ','.join(properties_list)
+ res['composite'] = composite_lst
+
+ # If type is of ENUM then we need to add labels in our output
+ if of_type == 'e':
+ SQL = render_template("/".join([self.template_path,
+ 'additional_properties.sql']),
+ type='e', tid=tid)
+ status, rset = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+ # To display in properties
+ properties_list = []
+ # To display in enum grid
+ enum_list = []
+ for row in rset['rows']:
+ properties_list.append(row['enumlabel'])
+ enum_list.append({'label': row['enumlabel']})
+
+ # Adding both results in ouput
+ res['enum_list'] = ','.join(properties_list)
+ res['enum'] = enum_list
+
+ # If type is of Range then we need to add collation,subtype etc in our output
+ if of_type == 'r':
+ SQL = render_template("/".join([self.template_path,
+ 'additional_properties.sql']),
+ type='r', tid=tid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+ range_dict = dict(res['rows'][0])
+ res.update(range_dict)
+
+ # Returning only additional properties only
+ return res
+
+ @check_precondition
+ def properties(self, gid, sid, did, scid, tid):
+ """
+ This function will show the properties of the selected schema node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ scid: Schema ID
+ tid: Type ID
+
+ Returns:
+ JSON of selected schema node
+ """
+
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ scid=scid, tid=tid,
+ datlastsysoid=self.datlastsysoid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # Making copy of output for future use
+ copy_dict = dict(res['rows'][0])
+
+ # We need to parse & convert ACL coming from database to json format
+ SQL = render_template("/".join([self.template_path, 'acl.sql']),
+ scid=scid, tid=tid)
+ status, acl = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=acl)
+
+ # We will set get privileges from acl sql so we don't need
+ # it from properties sql
+ copy_dict['typacl'] = []
+
+
+ for row in acl['rows']:
+ priv = parse_priv_from_db(row)
+ if row['deftype'] in copy_dict:
+ copy_dict[row['deftype']].append(priv)
+ else:
+ copy_dict[row['deftype']] = [priv]
+
+ # Calling function to check and additional properties if available
+ copy_dict.update(self.additional_properties(copy_dict, tid))
+
+ return ajax_response(
+ response=copy_dict,
+ status=200
+ )
+
+ @check_precondition
+ def get_collations(self, gid, sid, did, scid, tid=None):
+ """
+ This function will return list of collation available
+ as AJAX response.
+ """
+ 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['collation'],
+ 'value': row['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, tid=None):
+ """
+ This function will return list of types available
+ as AJAX response.
+ """
+ res = []
+ 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']:
+ # Attaching properties for precession
+ # & length validation for current type
+ precision = False
+ length = False
+ min_val = 0
+ max_val = 0
+
+ # Check against PGOID for specific type
+ if row['elemoid']:
+ if row['elemoid'] in (1560, 1561, 1562, 1563, 1042, 1043,
+ 1014, 1015):
+ typeval = 'L'
+ elif row['elemoid'] in (1083, 1114, 1115, 1183, 1184, 1185,
+ 1186, 1187, 1266, 1270):
+ typeval = 'D'
+ elif row['elemoid'] in (1231, 1700):
+ typeval = 'P'
+ else:
+ typeval = ' '
+
+ # Logic to set precision & length/min/max values
+ if typeval == 'P':
+ precision = True
+
+ if precision or typeval in ('L', 'D'):
+ length = True
+ min_val = 0 if typeval == 'D' else 1
+ if precision:
+ max_val = 1000
+ elif min_val:
+ # Max of integer value
+ max_val = 2147483647
+ else:
+ max_val = 10
+
+ res.append(
+ {'label': row['typname'], 'value': row['typname'],
+ 'typval': typeval, 'precision': precision,
+ 'length': length, 'min_val': min_val, 'max_val': max_val
+ }
+ )
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_subtypes(self, gid, sid, did, scid, tid=None):
+ """
+ This function will return list of subtypes available
+ as AJAX response.
+ """
+ res = [{'label': '', 'value': ''}]
+ try:
+ SQL = render_template("/".join([self.template_path,
+ 'get_subtypes.sql']),
+ subtype=True)
+ 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['stype'], 'value': row['stype'],
+ 'is_collate': row['is_collate']}
+ )
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_subtype_opclass(self, gid, sid, did, scid, tid=None):
+ """
+ This function will return list of subtype opclass available
+ as AJAX response.
+ """
+ res = [{'label': '', 'value': ''}]
+ data = request.args
+
+ try:
+ SQL = render_template("/".join([self.template_path,
+ 'get_subtypes.sql']),
+ subtype_opclass=True, data=data)
+ if 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['opcname'],
+ 'value': row['opcname']})
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_subtype_diff(self, gid, sid, did, scid, tid=None):
+ """
+ This function will return list of subtypes diff functions available
+ as AJAX response.
+ """
+ res = [{'label': '', 'value': ''}]
+ data = request.args
+
+ try:
+ SQL = render_template("/".join([self.template_path,
+ 'get_subtypes.sql']),
+ get_opcintype=True, data=data)
+ if SQL:
+ status, opcintype = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=opcintype)
+ SQL = render_template("/".join([self.template_path,
+ 'get_subtypes.sql']),
+ opcintype=opcintype, conn=self.conn)
+ 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['stypdiff'],
+ 'value': row['stypdiff']}
+ )
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_canonical(self, gid, sid, did, scid, tid=None):
+ """
+ This function will return list of canonical functions available
+ as AJAX response.
+ """
+ res = [{'label': '', 'value': ''}]
+ data = request.args
+ canonical = True
+
+ try:
+ # We want to send data only if in we are in edit mode
+ # else we will disable the combobox
+ SQL = render_template("/".join([self.template_path,
+ 'get_subtypes.sql']),
+ getoid=True, data=data)
+ if SQL:
+ status, oid = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=oid)
+ # If oid is None then do not run SQL
+ if oid is None:
+ canonical = False
+
+ SQL = render_template("/".join([self.template_path,
+ 'get_subtypes.sql']),
+ canonical=canonical, conn=self.conn, oid=oid)
+ if 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['canonical'],
+ 'value': row['canonical']})
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+
+ @check_precondition
+ def get_external_functions_list(self, gid, sid, did, scid, tid=None):
+ """
+ This function will return list of external functions available
+ as AJAX response.
+ """
+ res = [{'label': '', 'value': '', 'cbtype': 'all'}]
+
+ try:
+ # The SQL generated below will populate Input/Output/Send/
+ # Receive/Analyze/TypModeIN/TypModOUT combo box
+ SQL = render_template("/".join([self.template_path,
+ 'get_external_functions.sql']),
+ extfunc=True)
+ if 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['func'], 'value': row['func'],
+ 'cbtype': 'all'})
+
+ # The SQL generated below will populate TypModeIN combo box
+ SQL = render_template("/".join([self.template_path,
+ 'get_external_functions.sql']),
+ typemodin=True)
+ if 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['func'], 'value': row['func'],
+ 'cbtype': 'typmodin'})
+
+ # The SQL generated below will populate TypModeIN combo box
+ SQL = render_template("/".join([self.template_path,
+ 'get_external_functions.sql']),
+ typemodout=True)
+ if 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['func'], 'value': row['func'],
+ 'cbtype': 'typmodout'})
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+
+ @check_precondition
+ def create(self, gid, sid, did, scid):
+ """
+ This function will creates new the schema object
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+ data = request.form if request.form else json.loads(request.data.decode())
+ required_args = {
+ 'name': 'Name',
+ 'typtype': 'Type'
+ }
+
+ 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)." %
+ required_args[arg]
+ )
+ )
+ # Additional checks goes here
+ # If type is composite then check if it has two members
+ if data and data[arg] == 'c':
+ if len(data['composite']) < 2:
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ 'Composite type requires at least two members'
+ )
+ )
+ # If type is enum then check if it has minimum one label
+ if data and data[arg] == 'e':
+ if len(data['enum']) < 1:
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ 'Enumeration type requires at least one label'
+ )
+ )
+ # If type is enum then check if it has minimum one label
+ if data and data[arg] == 'r':
+ if data['typname'] is None:
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ 'Subtype must be defined for range type'
+ )
+ )
+ # If type is external then check if input/output
+ # conversion function is defined
+ if data and data[arg] == 'x':
+ if data['typinput'] is None or \
+ data['typoutput'] is None:
+ return make_json_response(
+ status=410,
+ success=0,
+ errormsg=gettext(
+ 'External type requires both Input & Output conversion function.'
+ )
+ )
+
+ # To format privileges coming from client
+ if 'typacl' in data and data['typacl'] is not None:
+ data['typacl'] = parse_priv_to_db(data['typacl'], self.acl)
+
+ try:
+ SQL = render_template("/".join([self.template_path, 'create.sql']),
+ data=data, conn=self.conn)
+ 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
+ SQL = render_template("/".join([self.template_path,
+ 'get_oid.sql']),
+ scid=scid, data=data)
+ status, tid = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=tid)
+
+ return jsonify(
+ node=self.blueprint.generate_browser_node(
+ tid,
+ scid,
+ data['name'],
+ icon="icon-type"
+ )
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def update(self, gid, sid, did, scid, tid):
+ """
+ This function will updates existing the type object
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+
+ data = request.form if request.form else json.loads(request.data.decode())
+ try:
+ SQL = self.get_sql(gid, sid, data, scid, tid)
+ if SQL and SQL.strip('\n') and SQL.strip(' '):
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ return make_json_response(
+ success=1,
+ info="Type updated",
+ data={
+ 'id': tid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+ else:
+ return make_json_response(
+ success=1,
+ info="Nothing to update",
+ data={
+ 'id': tid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+
+ @check_precondition
+ def delete(self, gid, sid, did, scid, tid):
+ """
+ This function will updates existing the schema object
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+
+ # Below will decide if it's simple drop or drop with cascade call
+ if self.cmd == 'delete':
+ # This is a cascade operation
+ cascade = True
+ else:
+ cascade = False
+
+ try:
+ SQL = render_template("/".join([self.template_path, 'get_name.sql']),
+ scid=scid, tid=tid)
+ status, name = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=name)
+
+ SQL = render_template("/".join([self.template_path, 'delete.sql']),
+ name=name, cascade=cascade, conn=self.conn)
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ return make_json_response(
+ success=1,
+ info=gettext("Type dropped"),
+ data={
+ 'id': tid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+
+ @check_precondition
+ def msql(self, gid, sid, did, scid, tid=None):
+ """
+ This function will generates modified sql for type object
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+ req = request.args
+ data = dict()
+
+ # converting nested request data in proper json format
+ for key,val in req.items():
+ if key in ['composite', 'enum', 'seclabels', 'typacl']:
+ data[key] = json.loads(val)
+ else:
+ data[key] = val
+
+ try:
+ SQL = self.get_sql(gid, sid, data, scid, tid)
+
+ if SQL and SQL.strip('\n') and SQL.strip(' '):
+ return make_json_response(
+ data=SQL,
+ status=200
+ )
+ except Exception as e:
+ internal_server_error(errormsg=str(e))
+
+ def get_sql(self, gid, sid, data, scid, tid=None):
+ """
+ This function will genrate sql from model data
+ """
+ if tid is not None:
+
+ for key in ['typacl']:
+ if key in data and data[key] is not None:
+ if 'added' in data[key]:
+ data[key]['added'] = parse_priv_to_db(data[key]['added'], self.acl)
+ if 'changed' in data[key]:
+ data[key]['changed'] = parse_priv_to_db(data[key]['changed'], self.acl)
+ if 'deleted' in data[key]:
+ data[key]['deleted'] = parse_priv_to_db(data[key]['deleted'], self.acl)
+
+ SQL = render_template("/".join([self.template_path, 'properties.sql']),
+ scid=scid, tid=tid,
+ datlastsysoid=self.datlastsysoid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # Making copy of output for future use
+ old_data = dict(res['rows'][0])
+
+ SQL = render_template("/".join([self.template_path, 'acl.sql']),
+ scid=scid, tid=tid)
+ status, acl = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=acl)
+
+ # We will set get privileges from acl sql so we don't need
+ # it from properties sql
+ old_data['typacl'] = []
+
+ for row in acl['rows']:
+ priv = parse_priv_from_db(row)
+ if row['deftype'] in old_data:
+ old_data[row['deftype']].append(priv)
+ else:
+ old_data[row['deftype']] = [priv]
+
+ # Calling function to check and additional properties if available
+ old_data.update(self.additional_properties(old_data, tid))
+
+ SQL = render_template(
+ "/".join([self.template_path, 'update.sql']),
+ data=data, o_data=old_data, conn=self.conn
+ )
+ else:
+ required_args = [
+ 'name',
+ 'typtype'
+ ]
+
+ for arg in required_args:
+ if arg not in data:
+ return " --definition incomplete"
+
+ # Privileges
+ if 'typacl' in data and data['typacl'] is not None:
+ data['typacl'] = parse_priv_to_db(data['typacl'], self.acl)
+
+ SQL = render_template("/".join([self.template_path,
+ 'create.sql']),
+ data=data, conn=self.conn)
+
+ return SQL
+
+
+ @check_precondition
+ def sql(self, gid, sid, did, scid, tid):
+ """
+ This function will generates reverse engineered sql for schema object
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+ SQL = render_template("/".join([self.template_path, 'properties.sql']),
+ scid=scid, tid=tid,
+ datlastsysoid=self.datlastsysoid)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ # Making copy of output for future use
+ data = dict(res['rows'][0])
+
+ SQL = render_template("/".join([self.template_path, 'acl.sql']),
+ scid=scid, tid=tid)
+ status, acl = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=acl)
+
+ # We will set get privileges from acl sql so we don't need
+ # it from properties sql
+ data['typacl'] = []
+
+ for row in acl['rows']:
+ priv = parse_priv_from_db(row)
+ if row['deftype'] in data:
+ data[row['deftype']].append(priv)
+ else:
+ data[row['deftype']] = [priv]
+
+ # Privileges
+ if 'typacl' in data and data['typacl'] is not None:
+ data['nspacl'] = parse_priv_to_db(data['typacl'], self.acl)
+
+ # Calling function to check and additional properties if available
+ data.update(self.additional_properties(data, tid))
+
+ # We do not want to display table which has '-' value
+ # setting them to None so that jinja avoid displaying them
+ for k in data:
+ if data[k] == '-':
+ data[k] = None
+
+ SQL = self.get_sql(gid, sid, data, scid, tid=None)
+
+ # We are appending headers here for sql panel
+ sql_header = "-- Type: {0}\n\n-- ".format(data['name'])
+ sql_header += render_template("/".join([self.template_path,
+ 'delete.sql']),
+ name=data['name'], conn=self.conn)
+ SQL = sql_header + '\n' + SQL
+
+ return ajax_response(response=SQL)
+
+ @check_precondition
+ def dependents(self, gid, sid, did, scid, tid):
+ """
+ This function get the dependents and return ajax response
+ for the type node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+ dependents_result = self.get_dependents(
+ self.conn, tid
+ )
+
+ return ajax_response(
+ response=dependents_result,
+ status=200
+ )
+
+ @check_precondition
+ def dependencies(self, gid, sid, did, scid, tid):
+ """
+ This function get the dependencies and return ajax response
+ for the type node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Type ID
+ """
+ dependencies_result = self.get_dependencies(
+ self.conn, tid
+ )
+
+ return ajax_response(
+ response=dependencies_result,
+ status=200
+ )
+
+TypeView.register_node_view(blueprint)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/img/coll-type.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/img/coll-type.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb020d7d99f84439046d288615e865ee1fbdb815
GIT binary patch
literal 329
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv3GfMV1=3NcXI=aM>fHaQT@Q91
z`hS1R{~OExU!3;;MEm~(mH&6<{olN3-cDJdI>wS9zhDN3XE)M-9L@rd$YLPv0mg18
zv+aP47*7|+5RU7%XQO!=40zlgo^wo$EU!My#3j(ks*}LT9dUr^nFV*x`<LfEXLU&{
zNT_QZ){p11jr8BRJf*J9t1q$D%X6FK(q}uIk4`OV_&v+tAZF)<c~_)!|NM{V=e#WX
zN#J9vG0+~>64!{5l*E!$tK_0oAjM#0U}&IgXryak7-D2#Wnye)VybOmYGq(B@15Q%
q6b-rgDVb@N5Df;FU=2XkCRPS!5DllMhpqu?VDNPHb6Mw<&;$UZ$8*O3
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/img/type.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/img/type.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c16764e7d08c56922a97a2f0c6cc06455c86a56
GIT binary patch
literal 325
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=8~#9EmzT>)QWU=l(xE
z`v2js|F_rtzdY~%nF;@oHvQjQ{(pPk|IMk)0@*;Nj3q&S!3+-1ZlnP@oCO|{#X#Bv
zjNMLV+W{G&o-U3d9M_W*4zM_RIV|8v(U4|t6r8Z|5fh7_LtB=H01KmJR;I%QmXsCK
znH_-=7a3W69onAxD9m6<$ym$O<m%A&El=SFOUjEmj7`o4+9Dfn@G_j<Bfar~Z-)!e
z0@V`Nh?11Vl2ohYqEsNoU}RuuplfKPYhV~+WME}tY-M7qZD49;U@-5U-YOIgx%nxX
kX_XKS29{tAK-DHz24)Zqr>2Ll0cv3IboFyt=akR{01h5&qyPW_
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
new file mode 100644
index 0000000..f90e9eb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
@@ -0,0 +1,841 @@
+define(
+ ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+ 'pgadmin.browser', 'alertify', 'backgrid', 'pgadmin.backgrid',
+ 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
+
+ if (!pgBrowser.Nodes['coll-type']) {
+ var databases = pgAdmin.Browser.Nodes['coll-type'] =
+ pgAdmin.Browser.Collection.extend({
+ node: 'type',
+ label: '{{ _('Types') }}',
+ type: 'coll-type',
+ columns: ['name', 'oid', 'description']
+ });
+ };
+
+ // Switch options to save space in model's field
+ var switchOptions = {
+ 'onText': 'Yes', 'offText': 'No',
+ 'onColor': 'success', 'offColor': 'default',
+ 'size': 'small'
+ };
+
+ // Security label model declaration
+ var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ provider: null,
+ security_label: null
+ },
+ schema: [{
+ id: 'provider', label: '{{ _('Provider') }}',
+ type: 'text', disabled: false
+ },{
+ id: 'security_label', label: '{{ _('Security Label') }}',
+ type: 'text', disabled: false
+ }],
+ validate: function() {
+ var err = {},
+ errmsg = null,
+ data = this.toJSON();
+
+ if (_.isUndefined(data.label) ||
+ _.isNull(data.label) ||
+ String(data.label).replace(/^\s+|\s+$/g, '') == '') {
+ errmsg = _("Please specify the value for all the security providers.");
+ this.errorModel.set('security_label', errmsg);
+ } else {
+ this.errorModel.unset('security_label');
+ }
+ return null;
+ }
+ });
+
+ // Composite type model declaration
+ var CompositeModel = Backform.CompositeModel = pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ member_name: undefined,
+ type: undefined,
+ tlength: undefined,
+ is_tlength: false,
+ precision: undefined,
+ is_precision: false,
+ collation: undefined,
+ min_val: undefined,
+ max_val: undefined,
+ },
+ type_options: undefined,
+ subtypes: undefined,
+ schema: [{
+ id: 'member_name', label: '{{ _('Member Name') }}',
+ type: 'text', disabled: false, editable: false
+ },{
+ id: 'type', label: '{{ _('Type') }}', control: 'node-ajax-options',
+ type: 'text', url: 'get_types', disabled: false, node: 'type',
+ editable: false,
+ transform: function(d){
+ this.model.type_options = d;
+ return d;
+ }
+ },{
+ id: 'tlength', label: '{{ _('Length') }}', deps: ['type'], type: 'text',
+ editable: false,
+ disabled: function(m) {
+ // We will store type from selected from combobox
+ var of_type = m.get('type');
+ if(m.type_options) {
+ // iterating over all the types
+ _.each(m.type_options, function(o) {
+ // if type from selected from combobox matches in options
+ if ( of_type == o.value ) {
+ // if length is allowed for selected type
+ if(o.length)
+ {
+ // set the values in model
+ m.set('is_tlength', true, {silent: true});
+ m.set('min_val', o.min_val, {silent: true});
+ m.set('max_val', o.max_val, {silent: true});
+ }
+ }
+ });
+ }
+ return !m.get('is_tlength');
+ }
+ },{
+ id: 'precision', label: '{{ _('Precision') }}', deps: ['type'],
+ type: 'text', editable: false,
+ disabled: function(m) {
+ // We will store type from selected from combobox
+ var of_type = m.get('type');
+ if(m.type_options) {
+ // iterating over all the types
+ _.each(m.type_options, function(o) {
+ // if type from selected from combobox matches in options
+ if ( of_type == o.value ) {
+ // if precession is allowed for selected type
+ if(o.precision)
+ {
+ // set the values in model
+ m.set('is_precision', true, {silent: true});
+ m.set('min_val', o.min_val, {silent: true});
+ m.set('max_val', o.max_val, {silent: true});
+ }
+ }
+ });
+ }
+ return !m.get('is_precision');
+ }
+ },{
+ id: 'collation', label: '{{ _('Collation') }}',
+ control: 'node-ajax-options', editable: false,
+ type: 'text', disabled: false, url: 'get_collations', node: 'type'
+ }],
+ validate: function() {
+ var err = {},
+ errmsg = null,
+ data = this.toJSON();
+ // Validation for member name
+ if (_.isUndefined(data.member_name) ||
+ _.isNull(data.member_name) ||
+ String(data.member_name).replace(/^\s+|\s+$/g, '') == '') {
+ errmsg = _("Please specify the value for member name.")
+ this.errorModel.set('member_name', errmsg)
+ return errmsg;
+ } else {
+ this.errorModel.unset('member_name');
+ }
+
+ // Validation for Length field
+ if (data.is_tlength && !_.isUndefined(data.tlength)) {
+ if (data.tlength < data.min_val )
+ errmsg = _("Length should not be less than " + data.min_val)
+ if (data.tlength > data.max_val )
+ errmsg = _("Length should not be greater than " + data.max_val)
+ // If we have any error set then throw it to user
+ if(errmsg) {
+ this.errorModel.set('tlength', errmsg)
+ return errmsg;
+ }
+ } else {
+ this.errorModel.unset('tlength');
+ }
+
+ // Validation for precision field
+ if (data.is_precision && !_.isUndefined(data.precision)) {
+ if (data.precision < data.min_val )
+ errmsg = _("Precision should not be less than " + data.min_val)
+ if (data.precision > data.max_val )
+ errmsg = _("Precision should not be greater than " + data.max_val)
+ // If we have any error set then throw it to user
+ if(errmsg) {
+ this.errorModel.set('precision', errmsg)
+ return errmsg;
+ }
+ } else {
+ this.errorModel.unset('precision');
+ }
+
+ return null;
+ }
+ });
+
+ var EnumModel = Backform.EnumModel = pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ label: null,
+ },
+ schema: [{
+ id: 'label', label: '{{ _('Label') }}',type: 'text', disabled: false,
+ cellHeaderClasses: 'width_percent_99'
+ }],
+ validate: function() {
+ var err = {},
+ errmsg = null,
+ data = this.toJSON();
+
+ if (_.isUndefined(data.label) ||
+ _.isNull(data.label) ||
+ String(data.label).replace(/^\s+|\s+$/g, '') == '') {
+ errmsg = _("Please specify the value for label.");
+ this.errorModel.set('label', errmsg)
+ return errmsg;
+ } else {
+ this.errorModel.unset('label');
+ }
+
+
+ return null;
+ }
+ });
+
+ if (!pgBrowser.Nodes['type']) {
+ pgAdmin.Browser.Nodes['type'] = pgBrowser.Node.extend({
+ type: 'type',
+ label: '{{ _('Type') }}',
+ collection_type: 'coll-type',
+ hasSQL: true,
+ hasDepends: true,
+ parent_type: ['schema', 'catalog'],
+ Init: function() {
+ /* Avoid mulitple registration of menus */
+ if (this.initialized)
+ return;
+
+ this.initialized = true;
+
+ pgBrowser.add_menus([{
+ name: 'create_type_on_coll', node: 'coll-type', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Type...') }}',
+ icon: 'wcTabIcon icon-type', data: {action: 'create', check: true},
+ enable: 'canCreate'
+ },{
+ name: 'create_type', node: 'type', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Type...') }}',
+ icon: 'wcTabIcon icon-type', data: {action: 'create', check: true},
+ enable: 'canCreate'
+ },{
+ name: 'create_type', node: 'schema', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ _('Type...') }}',
+ icon: 'wcTabIcon icon-type', data: {action: 'create', check: false},
+ enable: 'canCreate'
+ }
+ ]);
+
+ },
+ canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+ canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
+ ext_funcs: undefined,
+ model: pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ name: undefined,
+ oid: undefined,
+ is_sys_type: false,
+ typtype: undefined
+ },
+ schema: [{
+ id: 'name', label: '{{ _('Name') }}', cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchema'
+ },{
+ id: 'oid', label:'{{ _('Oid') }}', cell: 'string',
+ type: 'text' , mode: ['properties', 'edit'], disabled: true
+ },{
+ id: 'typeowner', label:'{{ _('Owner') }}', cell: 'string',
+ control: 'node-list-by-name',
+ type: 'text', mode: ['properties', 'create', 'edit'], node: 'role',
+ disabled: 'inSchema'
+ },{
+ id: 'schema', label:'{{ _('Schema') }}', cell: 'string',
+ type: 'text', mode: ['create', 'edit'], node: 'schema',
+ disabled: 'inSchema', filter: function(d) {
+ // If schema name start with pg_* then we need to exclude them
+ if(d && d.label.match(/^pg_/))
+ {
+ return false;
+ }
+ return true;
+ },
+ control: Backform.NodeListByNameControl.extend({
+ render: function(){
+ // Initialize parent's render method
+ Backform.NodeListByNameControl.prototype.render.apply(this, arguments);
+
+ // Set schema default value to its parent Schema
+ if(this.model.isNew()){
+ this.model.set({'schema': this.model.node_info.schema.label});
+ }
+ return this;
+ }
+ })
+ },{
+ id: 'typtype', label:'{{ _('Type') }}',
+ mode: ['create','edit'], disabled: 'inSchemaWithModelCheck',
+ group: '{{ _('Type Definition') }}',
+ mode: ['edit', 'create'],
+ select2: { width: "50%" },
+ options: [
+ {label: "Composite", value: "c"},
+ {label: "Enumration", value: "e"},
+ {label: "External", value: "x"},
+ {label: "Range", value: "r"},
+ ],
+ disabled: 'inSchemaWithModelCheck',
+ // If create mode then by default open composite type
+ control: Backform.Select2Control.extend({
+ render: function(){
+ // Initialize parent's render method
+ Backform.Select2Control.prototype.render.apply(this, arguments);
+ if(this.model.isNew()) {
+ this.model.set({'typtype': 'c'});
+ }
+ return this;
+ }
+ })
+ },{
+ id: 'composite', label: '{{ _('Composite Type') }}',
+ model: CompositeModel, editable: true, type: 'collection',
+ group: '{{ _('Type Definition') }}', mode: ['edit', 'create'],
+ control: 'unique-col-collection', uniqueCol : ['member_name'],
+ canAdd: true, canEdit: true, canDelete: true, disabled: 'inSchema',
+ deps: ['typtype'], deps: ['typtype'],
+ visible: function(m) {
+ if (m.get('typtype') === 'c') {
+ return true;
+ }
+ return false;
+ }
+ },{
+ id: 'enum', label: '{{ _('Enumration Type') }}',
+ model: EnumModel, editable: true, type: 'collection',
+ group: '{{ _('Type Definition') }}', mode: ['edit', 'create'],
+ canAdd: true, canEdit: false, canDelete: function(m) {
+ // We will disable it if it's in 'edit' mode
+ if (m.isNew()) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ disabled: 'inSchema', deps: ['typtype'],
+ control: 'unique-col-collection', uniqueCol : ['label'],
+ visible: function(m) {
+ return m.get('typtype') === 'e';
+ }
+ },{
+ // We will disable range type control in edit mode
+ type: 'nested', control: 'fieldset', group: '{{ _('Type Definition') }}',
+ mode: ['edit', 'create'],
+ visible: function(m) {
+ return m.get('typtype') === 'r';
+ }, deps: ['typtype'], label: '{{ _('Range Type') }}',
+ schema:[{
+ id: 'typname', label:'{{ _('Subtype') }}', cell: 'string',
+ control: 'node-ajax-options',
+ url: 'get_stypes', type: 'text', mode: ['properties', 'create', 'edit'],
+ group: '{{ _('Range Type') }}', disabled: 'inSchemaWithModelCheck',
+ transform: function(d){
+ this.model.subtypes = d;
+ return d;
+ }
+ },{
+ id: 'opcname', label:'{{ _('Subtype OpClass') }}', cell: 'string',
+ mode: ['properties', 'create', 'edit'], group: '{{ _('Range Type') }}',
+ disabled: 'inSchemaWithModelCheck', deps: ['typname'],
+ control: 'select', options: function() {
+ var l_typname = this.model.get('typname'),
+ self = this,
+ result = [];
+ if(!_.isUndefined(l_typname) && l_typname != '')
+ {
+ var node = this.field.get('schema_node'),
+ _url = node.generate_url.apply(
+ node, [
+ null, 'get_subopclass', this.field.get('node_data'), false,
+ this.field.get('node_info')
+ ]);
+ $.ajax({
+ async: false,
+ url: _url,
+ cache: false,
+ data: {'typname' : l_typname},
+ success: function(res) {
+ result = res.data;
+ },
+ error: function() {
+ self.model.trigger('pgadmin:view:fetch:error', self.model, self.field);
+ }
+ });
+ //
+ }
+ return result;
+ }
+ },{
+ id: 'collname', label:'{{ _('Collation') }}', cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ group: '{{ _('Range Type') }}',
+ deps: ['typname'], control: 'node-ajax-options', url: 'get_collations',
+ disabled: function(m) {
+ if(this.node_info && 'catalog' in this.node_info)
+ {
+ return true;
+ }
+
+ // Disbale in edit mode
+ if (!m.isNew()) {
+ return true;
+ }
+
+ // To check if collation is allowed?
+ var of_subtype = m.get('typname'),
+ is_collate = undefined;
+ if(!_.isUndefined(of_subtype)) {
+ // iterating over all the types
+ _.each(m.subtypes, function(s) {
+ // if subtype from selected from combobox matches
+ if ( of_subtype === s.label ) {
+ // if collation is allowed for selected subtype
+ // then enable it else disable it
+ is_collate = s.is_collate;
+ }
+ });
+ }
+ // If is_collate is true then do not disable
+ return is_collate ? false : true;
+ }
+ },{
+ id: 'rngcanonical', label:'{{ _('Canonical') }}', cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ group: '{{ _('Range Type') }}',
+ disabled: 'inSchemaWithModelCheck', deps: ['name', 'typname'],
+ control: 'select', options: function() {
+ var name = this.model.get('name'),
+ self = this,
+ result = [];
+
+ if(!_.isUndefined(name) && name != '')
+ {
+ var node = this.field.get('schema_node'),
+ _url = node.generate_url.apply(
+ node, [
+ null, 'get_canonical', this.field.get('node_data'), false,
+ this.field.get('node_info')
+ ]);
+ $.ajax({
+ async: false,
+ url: _url,
+ cache: false,
+ data: {"name" : name},
+ success: function(res) {
+ result = res.data;
+ },
+ error: function() {
+ self.model.trigger('pgadmin:view:fetch:error',
+ self.model, self.field);
+ }
+ });
+ }
+ return result;
+ }
+ },{
+ id: 'rngsubdiff', label:'{{ _('SubType diff') }}', cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ group: '{{ _('Range Type') }}',
+ disabled: 'inSchemaWithModelCheck', deps: ['opcname'],
+ control: 'select', options: function() {
+ var l_typname = this.model.get('typname'),
+ l_opcname = this.model.get('opcname'),
+ self = this,
+ result = [];
+
+ if(!_.isUndefined(l_typname) && l_typname != '' &&
+ !_.isUndefined(l_opcname) && l_opcname != '') {
+ var node = this.field.get('schema_node'),
+ _url = node.generate_url.apply(
+ node, [
+ null, 'get_stypediff',
+ this.field.get('node_data'), false,
+ this.field.get('node_info')
+ ]);
+ $.ajax({
+ async: false,
+ url: _url,
+ cache: false,
+ data: {'typname' : l_typname, 'opcname': l_opcname},
+ success: function(res) {
+ result = res.data;
+ },
+ error: function() {
+ self.model.trigger('pgadmin:view:fetch:error',
+ self.model, self.field);
+ }
+ });
+ }
+ return result;
+ }
+ }]
+ },{
+ type: 'nested', control: 'tab', group: '{{ _('Type Definition') }}',
+ label: '{{ _('External Type') }}', deps: ['typtype'],
+ mode: ['create', 'edit'],
+ visible: function(m) {
+ return m.get('typtype') === 'x';
+ },
+ schema:[{
+ id: 'typinput', label:'{{ _('Input function') }}',
+ cell: 'string',type: 'text',
+ mode: ['properties', 'create', 'edit'], group: 'Required',
+ disabled: 'inSchemaWithModelCheck',
+ control: 'node-ajax-options', url: 'get_external_functions',
+ transform: 'external_func_combo'
+ },{
+ id: 'typoutput', label:'{{ _('Output function') }}',
+ cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ group: 'Required',
+ disabled: 'inSchemaWithModelCheck'
+ ,control: 'node-ajax-options', url: 'get_external_functions',
+ transform: 'external_func_combo'
+ },{
+ id: 'typreceive', label:'{{ _('Receive function') }}',
+ cell: 'string', type: 'text', group: 'Optional-1',
+ mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck'
+ ,control: 'node-ajax-options', url: 'get_external_functions',
+ transform: 'external_func_combo'
+ },{
+ id: 'typsend', label:'{{ _('Send function') }}',
+ cell: 'string', group: 'Optional-1',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck'
+ ,control: 'node-ajax-options', url: 'get_external_functions',
+ transform: 'external_func_combo'
+ },{
+ id: 'typmodin', label:'{{ _('Typmod in function') }}',
+ cell: 'string', type: 'text',
+ mode: ['properties', 'create', 'edit'], group: 'Optional-1',
+ disabled: 'inSchemaWithModelCheck'
+ ,control: 'node-ajax-options', url: 'get_external_functions',
+ transform: function(d) {
+ var result = [{label :"", value : ""}];
+ _.each(d, function(item) {
+ // if type from selected from combobox matches in options
+ if ( item.cbtype === 'typmodin' || item.cbtype === 'all') {
+ result.push(item);
+ }
+ });
+ return result;
+ }
+ },{
+ id: 'typmodout', label:'{{ _('Typmod out function') }}',
+ cell: 'string', group: 'Optional-1',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck'
+ ,control: 'node-ajax-options', url: 'get_external_functions',
+ transform: function(d) {
+ var result = [{label :"", value : ""}];
+ _.each(d, function(item) {
+ // if type from selected from combobox matches in options
+ if ( item.cbtype === 'typmodout' || item.cbtype === 'all') {
+ result.push(item);
+ }
+ });
+ return result;
+ }
+ },{
+ id: 'typlen', label:'{{ _('Internal length') }}',
+ cell: 'integer', group: 'Optional-1',
+ type: 'int', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck'
+ },{
+ id: 'variable', label:'{{ _('Variable') }}', cell: 'switch',
+ group: 'Optional-1', type: 'switch',
+ mode: ['create','edit'], options: switchOptions,
+ disabled: 'inSchemaWithModelCheck'
+ },{
+ id: 'typdefault', label:'{{ _('Default') }}',
+ cell: 'string', group: 'Optional-1',
+ type: 'text', mode: ['properties', 'create','edit'],
+ disabled: 'inSchemaWithModelCheck'
+ },{
+ id: 'typanalyze', label:'{{ _('Analyze function') }}',
+ cell: 'string', group: 'Optional-1',
+ type: 'text', mode: ['properties', 'create','edit'],
+ disabled: 'inSchemaWithModelCheck'
+ ,control: 'node-ajax-options', url: 'get_external_functions',
+ transform: 'external_func_combo'
+ },{
+ id: 'typcategory', label:'{{ _('Category') }}',
+ cell: 'string', group: 'Optional-1',
+ type: 'text', mode: ['properties', 'create','edit'],
+ disabled: 'inSchemaWithModelCheck', control: 'select2',
+ select2: { placeholder: "Select category", allowClear: true,
+ width: "100%" },
+ options: [
+ {label :"", value : ""},
+ {label :"Array types", value : "A"},
+ {label :"Boolean types", value : "B"},
+ {label :"Composite types", value : "C"},
+ {label :"Date/time types", value : "D"},
+ {label :"Enum types", value : "E"},
+ {label :"Geometric types", value : "G"},
+ {label :"Network address types", value : "I"},
+ {label :"Numeric types", value : "N"},
+ {label :"Pseudo-types", value : "P"},
+ {label :"String types", value : "S"},
+ {label :"Timespan types", value : "T"},
+ {label :"User-defined types", value : "U"},
+ {label :"Bit-string types", value : "V"},
+ {label :"unknown type", value : "X"}
+ ]
+ },{
+ id: 'typispreferred', label:'{{ _('Prefered') }}', cell: 'switch',
+ type: 'switch', mode: ['properties', 'create','edit'],
+ options: switchOptions, disabled: 'inSchemaWithModelCheck',
+ group: 'Optional-1'
+ },{
+ id: 'element', label:'{{ _('Element') }}', cell: 'string',
+ control: 'node-ajax-options', group: 'Optional-2',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck', url: 'get_types'
+ },{
+ id: 'typdelim', label:'{{ _('Delimiter') }}', cell: 'string',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ group: 'Optional-2', disabled: 'inSchemaWithModelCheck'
+ },{
+ id: 'typalign', label:'{{ _('Alignment') }}',
+ cell: 'string', group: 'Optional-2',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck', control: 'select2',
+ select2: { placeholder: "Select alignment", allowClear: true,
+ width: "100%" },
+ options: [
+ {label :"", value : ""},
+ {label: "char", value: "c"},
+ {label: "int2", value: "s"},
+ {label: "in4", value: "i"},
+ {label: "double", value: "d"},
+ ]
+ },{
+ id: 'typstorage', label:'{{ _('Storage') }}',
+ type: 'text', mode: ['properties', 'create', 'edit'],
+ group: 'Optional-2', cell: 'string',
+ disabled: 'inSchemaWithModelCheck', control: 'select2',
+ select2: { placeholder: "Select storage", allowClear: true,
+ width: "100%" },
+ options: [
+ {label :"", value : ""},
+ {label: "PLAIN", value: "p"},
+ {label: "MAIN", value: "e"},
+ {label: "EXTERNAL", value: "m"},
+ {label: "EXTENDED", value: "x"},
+ ]
+ },{
+ id: 'typbyval', label:'{{ _('Passed by Value?') }}',
+ cell: 'switch', options: switchOptions,
+ type: 'switch', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchemaWithModelCheck', group: 'Optional-2',
+ },{
+ id: 'is_collatable', label:'{{ _('Collatable?') }}',
+ cell: 'switch', min_version: 90100, group: 'Optional-2',
+ type: 'switch', mode: ['properties', 'create', 'edit'],
+ options: switchOptions, disabled: 'inSchemaWithModelCheck'
+ // End of extension tab
+ }]
+ },{
+ id: 'alias', label:'{{ _('Alias') }}', cell: 'string',
+ type: 'text', mode: ['properties'],
+ disabled: 'inSchema'
+ },{
+ id: 'type_acl', label:'{{ _('ACL') }}', cell: 'string',
+ type: 'text', mode: ['properties'],
+ disabled: 'inSchema'
+ },{
+ id: 'member_list', label:'{{ _('Members') }}', cell: 'string',
+ type: 'text', mode: ['properties'],
+ disabled: 'inSchema', visible: function(m) {
+ if(m.get('typtype') === 'c') {
+ return true;
+ }
+ return false;
+ }
+ },{
+ id: 'enum_list', label:'{{ _('Labels') }}', cell: 'string',
+ type: 'text', mode: ['properties'],
+ disabled: 'inSchema', visible: function(m) {
+ if(m.get('typtype') === 'e') {
+ return true;
+ }
+ return false;
+ }
+ },{
+ id: 'is_sys_type', label:'{{ _('System type?') }}', cell: 'switch',
+ type: 'switch', mode: ['properties'], options: switchOptions,
+ disabled: 'inSchema'
+ },{
+ id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+ type: 'multiline', mode: ['properties', 'create', 'edit'],
+ disabled: 'inSchema'
+ },{
+ id: 'typacl', label: 'Privileges', type: 'collection',
+ group: '{{ _('Security') }}', control: 'unique-col-collection',
+ model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({privileges: ['U']}),
+ mode: ['edit', 'create'], canAdd: true, canDelete: true,
+ uniqueCol : ['grantee'],
+ columns: ['grantee', 'grantor', 'privileges']
+ },{
+ id: 'seclabels', label: '{{ _('Security Labels') }}',
+ model: SecurityModel, editable: false, type: 'collection',
+ group: '{{ _('Security') }}', mode: ['edit', 'create'],
+ min_version: 90200, canAdd: true,
+ canEdit: false, canDelete: true, control: 'unique-col-collection'
+ }],
+ validate: function() {
+ // Validation code for required fields
+ var changedAttrs = this.sessAttrs,
+ msg = undefined;
+
+ if (_.has(changedAttrs, 'name') &&
+ (_.isUndefined(this.get('name'))
+ || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '')) {
+ msg = '{{ _('Name can not be empty!') }}';
+ this.errorModel.set('name', msg);
+ } else if (_.has(changedAttrs, 'schema') &&
+ (_.isUndefined(this.get('schema'))
+ || String(this.get('schema')).replace(/^\s+|\s+$/g, '') == '')) {
+ msg = '{{ _('Schema can not be empty!') }}';
+ this.errorModel.set('schema', msg);
+ } else if (_.has(changedAttrs, 'typtype') &&
+ (_.isUndefined(this.get('typtype'))
+ || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '')) {
+ msg = '{{ _('Type can not be empty!') }}';
+ this.errorModel.set('typtype', msg);
+ } else if (this.get('typtype') == 'r' &&
+ _.has(changedAttrs, 'typname')
+ && (_.isUndefined(this.get('typname'))
+ || String(this.get('typname')).replace(/^\s+|\s+$/g, '') == '')) {
+ msg = '{{ _('Subtype Name can not be empty!') }}';
+ this.errorModel.set('typname', msg);
+ } else if (this.get('typtype') == 'x' &&
+ _.has(changedAttrs, 'typinput')
+ && (_.isUndefined(this.get('typinput'))
+ || String(this.get('typinput')).replace(/^\s+|\s+$/g, '') == '')) {
+ msg = '{{ _('Input function can not be empty!') }}';
+ this.errorModel.set('typinput', msg);
+ } else if (this.get('typtype') == 'x' &&
+ _.has(changedAttrs, 'typoutput')
+ && (_.isUndefined(this.get('typoutput'))
+ || String(this.get('typoutput')).replace(/^\s+|\s+$/g, '') == '')) {
+ msg = '{{ _('Output function can not be empty!') }}';
+ this.errorModel.set('typoutput', msg);
+ } else {
+ this.errorModel.unset('name');
+ this.errorModel.unset('schema');
+ this.errorModel.unset('typtype');
+ this.errorModel.unset('typname');
+ this.errorModel.unset('typinput');
+ this.errorModel.unset('typoutput');
+ }
+ return null;
+ },
+ // We will disable everything if we are under catalog node
+ inSchema: function() {
+ if(this.node_info && 'catalog' in this.node_info)
+ {
+ return true;
+ }
+ return false;
+ },
+ // We will check if we are under schema node & in 'create' mode
+ inSchemaWithModelCheck: function(m) {
+ if(this.node_info && 'schema' in this.node_info)
+ {
+ // We will disbale control if it's in 'edit' mode
+ if (m.isNew()) {
+ return false;
+ } else {
+ return true;
+ }
+
+ }
+ return true;
+ },
+ // We want to enable only in edit mode
+ inSchemaWithEditMode: function(m) {
+ if(this.node_info && 'schema' in this.node_info)
+ {
+ // We will disbale control if it's in 'edit' mode
+ if (m.isNew()) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ return true;
+ },
+ // Function will help us to fill combobox
+ external_func_combo: function(d) {
+ var result = [];
+ _.each(d, function(item) {
+ // if type from selected from combobox matches in options
+ if ( item.cbtype == 'all' ) {
+ result.push(item);
+ }
+ });
+ return result;
+ }
+ }),
+ 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 table
+ if (_.indexOf(['schema'], d._type) > -1)
+ return true;
+
+ if ('coll-type' == 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;
+ }
+ });
+ }
+ return pgBrowser.Nodes['type'];
+});
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..3ccf8e7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/acl.sql
@@ -0,0 +1,29 @@
+SELECT 'typacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+ (SELECT
+ d.grantee, d.grantor, d.is_grantable,
+ CASE d.privilege_type
+ WHEN 'USAGE' THEN 'U'
+ ELSE 'UNKNOWN'
+ END AS privilege_type
+ FROM
+ (SELECT t.typacl
+ FROM pg_type t
+ LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+ LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+ LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+ WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+ {% if tid %}
+ AND t.oid = {{tid}}::oid
+ {% endif %}
+ ) acl,
+ (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+ AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+ aclexplode(t.typacl) as d FROM pg_type t WHERE t.oid = {{tid}}::oid) a) d
+ ) d
+ LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+ LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
+
+
+
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/additional_properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/additional_properties.sql
new file mode 100644
index 0000000..d72874f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/additional_properties.sql
@@ -0,0 +1,40 @@
+{# The SQL given below will fetch composite type#}
+{% if type == 'c' %}
+SELECT attname, format_type(t.oid,NULL) AS typname, attndims, atttypmod, nsp.nspname,
+(SELECT COUNT(1) from pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup
+-- Min 9.1 start
+,collname, nspc.nspname as collnspname
+-- End
+, att.attrelid
+FROM pg_attribute att
+JOIN pg_type t ON t.oid=atttypid
+JOIN pg_namespace nsp ON t.typnamespace=nsp.oid
+LEFT OUTER JOIN pg_type b ON t.typelem=b.oid
+-- Min 9.1 start
+LEFT OUTER JOIN pg_collation c ON att.attcollation=c.oid
+LEFT OUTER JOIN pg_namespace nspc ON c.collnamespace=nspc.oid
+-- End
+WHERE att.attrelid = {{typrelid}}::oid
+ORDER by attnum;
+{% endif %}
+{# The SQL given below will fetch enum type#}
+{% if type == 'e' %}
+SELECT enumlabel FROM pg_enum WHERE enumtypid={{tid}}::oid
+-- Min 9.1
+ORDER by enumsortorder
+--End
+-- else
+-- ORDER by oid
+{% endif %}
+{# The SQL given below will fetch range type#}
+{% if type == 'r' %}
+SELECT rngsubtype, st.typname,
+rngcollation, col.collname,
+rngsubopc, opc.opcname,
+rngcanonical, rngsubdiff
+FROM pg_range
+LEFT JOIN pg_type st ON st.oid=rngsubtype
+LEFT JOIN pg_collation col ON col.oid=rngcollation
+LEFT JOIN pg_opclass opc ON opc.oid=rngsubopc
+WHERE rngtypid={{tid}}::oid;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/backend_support.sql
new file mode 100644
index 0000000..00b7fb4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/backend_support.sql
@@ -0,0 +1,18 @@
+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\\%'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..706f264
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/create.sql
@@ -0,0 +1,69 @@
+{% import 'macros/security.macros' as SECLABLE %}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{### Composite Type ###}
+{% if data and data.typtype == 'c' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS
+({% if data.composite %}{% for d in data.composite %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(d.member_name) }} {{ d.type }}{% if d.is_tlength and d.tlength %}({{d.tlength}}{% if d.is_precision and d.precision %},{{d.precision}}{% endif %}){% endif %}{% if d.collation %} COLLATE {{d.collation}}{% endif %}{% endfor %}{% endif %});
+{% endif %}
+{### Enum Type ###}
+{% if data and data.typtype == 'e' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS ENUM
+({% for e in data.enum %}{% if loop.index != 1 %}, {% endif %}{{ e.label|qtLiteral }}{% endfor %});
+{% endif %}
+{### Range Type ###}
+{% if data and data.typtype == 'r' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS RANGE
+({% if data.typname %} SUBTYPE={{ conn|qtTypeIdent(data.typname) }}{% endif %}{% if data.collname %}
+, COLLATION = {{ data.collname }}{% endif %}{% if data.opcname %}
+, SUBTYPE_OPCLASS = {{ data.opcname }}{% endif %}{% if data.rngcanonical %}
+, CANONICAL = {{ data.rngcanonical }}{% endif %}{% if data.rngsubdiff %}
+, SUBTYPE_DIFF = {{ data.rngsubdiff }}{% endif %} );
+{% endif %}
+{### External Type ###}
+{% if data and data.typtype == 'x' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS
+( {% if data.typinput %}
+INPUT = {{data.typinput}}{% endif %}{% if data.typoutput %}
+,OUTPUT = {{ data.typoutput }}{% endif %}{% if data.typreceive %}
+,RECEIVE = {{data.typreceive}}{% endif %}{% if data.typname %}
+,SEND = {{data.typsend}}{% endif %}{% if data.typmodin %}
+,TYPMOD_IN = {{data.typmodin}}{% endif %}{% if data.typmodout %}
+,TYPMOD_OUT = {{data.typmodout}}{% endif %}{% if data.typanalyze %}
+,ANALYZE = {{data.typanalyze}}{% endif %}{% if data.typlen %}
+,INTERNALLENGTH = {{data.typlen}}{% endif %}{% if data.typbyval %}
+,PASSEDBYVALUE{% endif %}{% if data.typalign %}
+,ALIGNMENT = {{data.typalign}}{% endif %}{% if data.typstorage %}
+,STORAGE = {{data.typstorage}}{% endif %}{% if data.typcategory %}
+,CATEGORY = {{data.typcategory}}{% endif %}{% if data.typispreferred %}
+,PREFERRED = {{data.typispreferred}}{% endif %}{% if data.typdefault %}
+,DEFAULT = {{data.typdefault}}{% endif %}{% if data.element %}
+,ELEMENT = {{data.element}}{% endif %}{% if data.typdelim %}
+,DELIMITER = {{data.typdelim|qtLiteral}}{% endif %}{% if data.is_collatable %}
+,COLLATABLE = {{data.is_collatable}}{% endif %} );
+{% endif %}
+{### Type Owner ###}
+{% if data and data.typeowner %}
+
+ALTER TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
+ OWNER TO {{data.typeowner}};
+{% endif %}
+{### Type Comments ###}
+{% if data and data.description %}
+
+COMMENT ON TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
+ IS {{data.description|qtLiteral}};
+{% endif %}
+{### Security Lables ###}
+{% if data.seclabels %}
+
+{% for r in data.seclabels %}
+{{ SECLABLE.APPLY(conn, 'TYPE', data.name, r.provider, r.security_label) }}
+{% endfor %}
+{% endif %}
+{### ACL ###}
+{% if data.typacl %}
+
+{% for priv in data.typacl %}
+{{ PRIVILEGE.APPLY(conn, 'TYPE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..17d4da1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/delete.sql
@@ -0,0 +1 @@
+DROP TYPE {{ conn|qtIdent(name) }}{% if cascade%} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_collations.sql
new file mode 100644
index 0000000..d1c29bb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_collations.sql
@@ -0,0 +1,7 @@
+SELECT --nspname, collname,
+ CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(collname))
+ ELSE '' END AS collation
+FROM pg_collation c, pg_namespace n
+WHERE c.collnamespace=n.oid
+ORDER BY nspname, collname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_external_functions.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_external_functions.sql
new file mode 100644
index 0000000..7b76ed5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_external_functions.sql
@@ -0,0 +1,40 @@
+{### Input/Output/Send/Receive/Analyze function list also append into TypModeIN/TypModOUT ###}
+{% if extfunc %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS func
+FROM (
+ SELECT proname, nspname, max(proargtypes[0]) AS arg0, max(proargtypes[1]) AS arg1
+FROM pg_proc p
+ JOIN pg_namespace n ON n.oid=pronamespace
+GROUP BY proname, nspname
+ HAVING count(proname) = 1 ) AS uniquefunc
+ WHERE arg0 <> 0 AND arg1 = 0;
+{% endif %}
+{### TypmodIN list ###}
+{% if typemodin %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS func
+ FROM pg_proc p
+ JOIN pg_namespace n ON n.oid=pronamespace
+ WHERE prorettype=(SELECT oid FROM pg_type WHERE typname='int4')
+ AND proargtypes[0]=(SELECT oid FROM pg_type WHERE typname='_cstring')
+ AND proargtypes[1] IS NULL
+ ORDER BY nspname, proname;
+{% endif %}
+{### TypmodOUT list ###}
+{% if typemodout %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS func
+ FROM pg_proc p
+ JOIN pg_namespace n ON n.oid=pronamespace
+ WHERE prorettype=(SELECT oid FROM pg_type WHERE typname='cstring')
+ AND proargtypes[0]=(SELECT oid FROM pg_type WHERE typname='int4')
+ AND proargtypes[1] IS NULL
+ ORDER BY nspname, proname;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_name.sql
new file mode 100644
index 0000000..d368f0f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_name.sql
@@ -0,0 +1,3 @@
+SELECT t.typname AS name
+FROM pg_type t
+WHERE t.oid = {{tid}}::oid;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..2dd81c0
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,11 @@
+{# Below will provide oid for newly created type #}
+SELECT t.oid
+FROM pg_type t
+LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+{% if data %}
+AND t.typname = {{data.name|qtLiteral}}
+{% endif %}
+ORDER BY t.typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_subtypes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_subtypes.sql
new file mode 100644
index 0000000..1138ba4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_subtypes.sql
@@ -0,0 +1,56 @@
+{### To fill subtype combobox ###}
+{% if subtype %}
+SELECT DISTINCT typ.typname AS stype,
+ (CASE WHEN typ.typcollation > 0 THEN true ELSE false END) AS is_collate
+FROM pg_opclass opc
+JOIN pg_type typ ON opc.opcintype = typ.oid
+WHERE opc.opcmethod = 403
+ORDER BY 1
+{% endif %}
+{### To fill subtype opclass combobox ###}
+{% if subtype_opclass and data and data.typname %}
+SELECT opc.opcname
+FROM pg_opclass opc
+JOIN pg_type typ ON opc.opcintype=typ.oid
+AND typ.typname = {{ data.typname|qtLiteral }}
+WHERE opc.opcmethod = 403
+ORDER BY opcname;
+{% endif %}
+{### To fetch opcinttype from subtype opclass ###}
+{% if get_opcintype and data and data.typname and data.opcname %}
+SELECT opc.opcintype
+FROM pg_opclass opc
+JOIN pg_type typ ON opc.opcintype=typ.oid
+AND typ.typname = {{ data.typname|qtLiteral }}
+WHERE opc.opcmethod = 403
+AND opc.opcname = {{ data.opcname|qtLiteral }}
+ORDER BY opcname;
+{% endif %}
+{### To fill subtype diff function combobox ###}
+{% if opcintype %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS stypdiff
+FROM pg_proc
+JOIN pg_namespace n ON n.oid=pronamespace
+WHERE prorettype = 701
+AND proargtypes = '{{opcintype}} {{opcintype}}'
+ORDER BY proname;
+{% endif %}
+{### To fill canonical combobox ###}
+{% if getoid %}
+SELECT oid FROM pg_type
+WHERE typname = {{ data.name|qtLiteral }}
+{% endif %}
+{% if canonical and oid %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS canonical
+FROM pg_proc
+JOIN pg_namespace n ON n.oid=pronamespace
+WHERE prorettype= {{ oid }}
+AND proargtypes = '{{ oid }}'
+ORDER BY proname;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_types.sql
new file mode 100644
index 0000000..2f2ca70
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/get_types.sql
@@ -0,0 +1,10 @@
+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', 'd', 'e', 'r')AND NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = typname and relkind != 'c') AND (typname not like '_%' OR NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = substring(typname from 2)::name and relkind != 'c')) AND nsp.nspname != 'information_schema'
+ ) AS dummy
+ ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..88cc34a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/nodes.sql
@@ -0,0 +1,7 @@
+SELECT t.oid, t.typname AS name
+FROM pg_type t
+LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+LEFT OUTER JOIN pg_namespace nsp ON nsp.oid = t.typnamespace
+WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+ORDER BY t.typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..56ab793
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/properties.sql
@@ -0,0 +1,21 @@
+SELECT t.oid, t.typname AS name
+ ,(CASE WHEN CAST(coalesce(t.typcollation, '0') AS integer) = 100 THEN true ElSE false END) AS is_collatable
+ ,t.typacl AS type_acl
+ ,t.*, format_type(t.oid, null) AS alias
+ ,pg_get_userbyid(t.typowner) as typeowner, e.typname as element
+ ,description, ct.oid AS taboid
+ ,nsp.nspname AS schema
+ --MinimumVersion 9.1 START
+ ,(SELECT array_agg(provider || '=' || label) FROM pg_shseclabel sl1 WHERE sl1.objoid=t.oid) AS seclabels
+ -- END
+ ,(CASE WHEN (t.oid <= {{ datlastsysoid}}::oid OR ct.oid != 0) THEN true ElSE false END) AS is_sys_type
+FROM pg_type t
+LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+LEFT OUTER JOIN pg_namespace nsp ON nsp.oid = t.typnamespace
+WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+{% if tid %}
+AND t.oid = {{tid}}::oid
+{% endif %}
+ORDER BY t.typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..16b72bc
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/9.1_plus/update.sql
@@ -0,0 +1,129 @@
+{% import 'macros/security.macros' as SECLABLE %}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{#======================================#}
+{# Below will change object owner #}
+{% if data.typeowner and data.typeowner != o_data.typeowner %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ OWNER TO {{ data.typeowner }};
+
+{% endif %}
+{#======================================#}
+{# Below will change objects comment #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{#======================================#}
+{### The sql given below will update composite type ###}
+{% if data.composite and data.composite|length > 0 %}
+{% set composite = data.composite %}
+{% if 'deleted' in composite and composite.deleted|length > 0 %}
+{% for r in composite.deleted %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ DROP ATTRIBUTE {{conn|qtIdent(r.member_name)}};
+{% endfor %}
+{% endif %}
+{% if 'added' in composite and composite.added|length > 0 %}
+{% for r in composite.added %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ADD ATTRIBUTE {{conn|qtIdent(r.member_name)}} {{conn|qtIdent(r.type)}}{% if r.is_tlength and r.tlength %}
+({{r.tlength}}{% if r.is_precision and r.precision %},{{r.precision}}{% endif %}){% endif %}{% if r.collation %}
+ COLLATE {{r.collation}}{% endif %};
+{% endfor %}
+{% endif %}
+{% if 'changed' in composite and composite.changed|length > 0 %}
+{% for r in composite.changed %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ALTER ATTRIBUTE {{conn|qtIdent(r.member_name)}} SET DATA TYPE {{conn|qtIdent(r.type)}}{% if r.is_tlength and r.tlength %}
+({{r.tlength}}{% if r.is_precision and r.precision %},{{r.precision}}{% endif %}){% endif %}{% if r.collation %}
+ COLLATE {{r.collation}}{% endif %};
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{### The sql given below will update enum type ###}
+{% if data.enum and data.enum|length > 0 %}
+{% set enum = data.enum %}
+{% set o_enum_len = o_data.enum|length %}
+{# We need actual list index from length #}
+{% set o_enum_len = o_enum_len - 1 %}
+{% if 'added' in enum and enum.added|length > 0 %}
+{% for r in enum.added %}
+{% set c_idx = loop.index %}
+{% if c_idx == 1 %}
+{# if first new element then add it after old data enum list#}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ADD VALUE {{r.label|qtLiteral}} AFTER {{o_data.enum[o_enum_len].label|qtLiteral }};
+{% else %}
+{# if first new element then add it after new data enum list#}
+{% set p_idx = loop.index - 2 %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ADD VALUE {{r.label|qtLiteral}} AFTER {{enum.added[p_idx].label|qtLiteral}};
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{# The SQL generated below will change Security Label #}
+{% if data.seclabels and data.seclabels|length > 0 %}
+{% set seclabels = data.seclabels %}
+{% set name = conn|qtIdent(o_data.schema, o_data.name) %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABLE.DROP(conn, 'TYPE', name, r.provider) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABLE.APPLY(conn, 'TYPE', name, r.provider, r.security_label) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABLE.APPLY(conn, 'TYPE', name, r.provider, r.security_label) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{# Change the privileges #}
+{% if data.typacl and data.typacl|length > 0 %}
+{% set name = conn|qtIdent(o_data.schema, o_data.name) %}
+{% if 'deleted' in data.typacl %}
+{% for priv in data.typacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'TYPE', priv.grantee, name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.typacl %}
+{% for priv in data.typacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'TYPE', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'TYPE', priv.grantee, name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.typacl %}
+{% for priv in data.typacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'TYPE', priv.grantee, name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{#======================================#}
+{# Below will change object name #}
+{% if data.name and data.name != o_data.name %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{#======================================#}
+{# Below will change the schema for object #}
+{# with extra if condition we will also make sure that object has correct name #}
+{% if data.schema and data.schema != o_data.schema %}
+ALTER TYPE {% if data.name != o_data.name %}{{ conn|qtIdent(o_data.schema, data.name) }}
+{% else %}{{ conn|qtIdent(o_data.schema, o_data.name) }}{% endif %}
+ SET SCHEMA {{ conn|qtIdent(data.schema) }};
+
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/postgres_inbuit_types.txt b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/postgres_inbuit_types.txt
new file mode 100644
index 0000000..4a616b6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/postgres_inbuit_types.txt
@@ -0,0 +1,53 @@
+"""
+Here are the list of Postgres inbuilt types & their OID's
+We will use these type to check for validations
+
+## PGOID_TYPE_SERIAL -42L
+## PGOID_TYPE_SERIAL8 -43L
+## PGOID_TYPE_SERIAL2 -44L
+## PGOID_TYPE_BOOL 16L
+## PGOID_TYPE_BYTEA 17L
+## PGOID_TYPE_CHAR 18L
+## PGOID_TYPE_NAME 19L
+## PGOID_TYPE_INT8 20L
+## PGOID_TYPE_INT2 21L
+## PGOID_TYPE_INT4 23L
+## PGOID_TYPE_TEXT 25L
+## PGOID_TYPE_OID 26L
+## PGOID_TYPE_TID 27L
+## PGOID_TYPE_XID 28L
+## PGOID_TYPE_CID 29L
+## PGOID_TYPE_FLOAT4 700L
+## PGOID_TYPE_FLOAT8 701L
+## PGOID_TYPE_MONEY 790L
+## PGOID_TYPE_CHAR_ARRAY 1002L
+## PGOID_TYPE_TEXT_ARRAY 1009L
+## PGOID_TYPE_BPCHAR_ARRAY 1014L
+## PGOID_TYPE_VARCHAR_ARRAY 1015L
+## PGOID_TYPE_BPCHAR 1042L
+## PGOID_TYPE_VARCHAR 1043L
+## PGOID_TYPE_DATE 1082L
+## PGOID_TYPE_TIME 1083L
+## PGOID_TYPE_TIMESTAMP 1114L
+## PGOID_TYPE_TIMESTAMP_ARRAY 1115L
+## PGOID_TYPE_TIME_ARRAY 1183L
+## PGOID_TYPE_TIMESTAMPTZ 1184L
+## PGOID_TYPE_TIMESTAMPTZ_ARRAY 1185L
+## PGOID_TYPE_INTERVAL 1186L
+## PGOID_TYPE_INTERVAL_ARRAY 1187L
+## PGOID_TYPE_NUMERIC_ARRAY 1231L
+## PGOID_TYPE_TIMETZ 1266L
+## PGOID_TYPE_TIMETZ_ARRAY 1270L
+## PGOID_TYPE_BIT 1560L
+## PGOID_TYPE_BIT_ARRAY 1561L
+## PGOID_TYPE_VARBIT 1562L
+## PGOID_TYPE_VARBIT_ARRAY 1563L
+## PGOID_TYPE_NUMERIC 1700L
+## PGOID_TYPE_CSTRING 2275L
+## PGOID_TYPE_ANY 2276L
+## PGOID_TYPE_VOID 2278L
+## PGOID_TYPE_TRIGGER 2279L
+## PGOID_TYPE_LANGUAGE_HANDLER 2280L
+## PGOID_TYPE_INTERNAL 2281L
+## PGOID_TYPE_HANDLER 3115L
+"""
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/acl.sql
new file mode 100644
index 0000000..3ccf8e7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/acl.sql
@@ -0,0 +1,29 @@
+SELECT 'typacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+ (SELECT
+ d.grantee, d.grantor, d.is_grantable,
+ CASE d.privilege_type
+ WHEN 'USAGE' THEN 'U'
+ ELSE 'UNKNOWN'
+ END AS privilege_type
+ FROM
+ (SELECT t.typacl
+ FROM pg_type t
+ LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+ LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+ LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+ WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+ {% if tid %}
+ AND t.oid = {{tid}}::oid
+ {% endif %}
+ ) acl,
+ (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+ AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+ aclexplode(t.typacl) as d FROM pg_type t WHERE t.oid = {{tid}}::oid) a) d
+ ) d
+ LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+ LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
+
+
+
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/additional_properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/additional_properties.sql
new file mode 100644
index 0000000..d72874f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/additional_properties.sql
@@ -0,0 +1,40 @@
+{# The SQL given below will fetch composite type#}
+{% if type == 'c' %}
+SELECT attname, format_type(t.oid,NULL) AS typname, attndims, atttypmod, nsp.nspname,
+(SELECT COUNT(1) from pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup
+-- Min 9.1 start
+,collname, nspc.nspname as collnspname
+-- End
+, att.attrelid
+FROM pg_attribute att
+JOIN pg_type t ON t.oid=atttypid
+JOIN pg_namespace nsp ON t.typnamespace=nsp.oid
+LEFT OUTER JOIN pg_type b ON t.typelem=b.oid
+-- Min 9.1 start
+LEFT OUTER JOIN pg_collation c ON att.attcollation=c.oid
+LEFT OUTER JOIN pg_namespace nspc ON c.collnamespace=nspc.oid
+-- End
+WHERE att.attrelid = {{typrelid}}::oid
+ORDER by attnum;
+{% endif %}
+{# The SQL given below will fetch enum type#}
+{% if type == 'e' %}
+SELECT enumlabel FROM pg_enum WHERE enumtypid={{tid}}::oid
+-- Min 9.1
+ORDER by enumsortorder
+--End
+-- else
+-- ORDER by oid
+{% endif %}
+{# The SQL given below will fetch range type#}
+{% if type == 'r' %}
+SELECT rngsubtype, st.typname,
+rngcollation, col.collname,
+rngsubopc, opc.opcname,
+rngcanonical, rngsubdiff
+FROM pg_range
+LEFT JOIN pg_type st ON st.oid=rngsubtype
+LEFT JOIN pg_collation col ON col.oid=rngcollation
+LEFT JOIN pg_opclass opc ON opc.oid=rngsubopc
+WHERE rngtypid={{tid}}::oid;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/backend_support.sql
new file mode 100644
index 0000000..00b7fb4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/backend_support.sql
@@ -0,0 +1,18 @@
+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\\%'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/create.sql
new file mode 100644
index 0000000..4136d91
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/create.sql
@@ -0,0 +1,61 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{### Composite Type ###}
+{% if data and data.typtype == 'c' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS
+({% if data.composite %}{% for d in data.composite %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(d.member_name) }} {{ d.type }}{% if d.is_tlength and d.tlength %}({{d.tlength}}{% if d.is_precision and d.precision %},{{d.precision}}{% endif %}){% endif %}{% if d.collation %} COLLATE {{d.collation}}{% endif %}{% endfor %}{% endif %});
+{% endif %}
+{### Enum Type ###}
+{% if data and data.typtype == 'e' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS ENUM
+({% for e in data.enum %}{% if loop.index != 1 %}, {% endif %}{{ e.label|qtLiteral }}{% endfor %});
+{% endif %}
+{### Range Type ###}
+{% if data and data.typtype == 'r' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS RANGE
+({% if data.typname %} SUBTYPE={{ conn|qtTypeIdent(data.typname) }}{% endif %}{% if data.collname %}
+, COLLATION = {{ data.collname }}{% endif %}{% if data.opcname %}
+, SUBTYPE_OPCLASS = {{ data.opcname }}{% endif %}{% if data.rngcanonical %}
+, CANONICAL = {{ data.rngcanonical }}{% endif %}{% if data.rngsubdiff %}
+, SUBTYPE_DIFF = {{ data.rngsubdiff }}{% endif %} );
+{% endif %}
+{### External Type ###}
+{% if data and data.typtype == 'x' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS
+( {% if data.typinput %}
+INPUT = {{data.typinput}}{% endif %}{% if data.typoutput %}
+,OUTPUT = {{ data.typoutput }}{% endif %}{% if data.typreceive %}
+,RECEIVE = {{data.typreceive}}{% endif %}{% if data.typname %}
+,SEND = {{data.typsend}}{% endif %}{% if data.typmodin %}
+,TYPMOD_IN = {{data.typmodin}}{% endif %}{% if data.typmodout %}
+,TYPMOD_OUT = {{data.typmodout}}{% endif %}{% if data.typanalyze %}
+,ANALYZE = {{data.typanalyze}}{% endif %}{% if data.typlen %}
+,INTERNALLENGTH = {{data.typlen}}{% endif %}{% if data.typbyval %}
+,PASSEDBYVALUE{% endif %}{% if data.typalign %}
+,ALIGNMENT = {{data.typalign}}{% endif %}{% if data.typstorage %}
+,STORAGE = {{data.typstorage}}{% endif %}{% if data.typcategory %}
+,CATEGORY = {{data.typcategory}}{% endif %}{% if data.typispreferred %}
+,PREFERRED = {{data.typispreferred}}{% endif %}{% if data.typdefault %}
+,DEFAULT = {{data.typdefault}}{% endif %}{% if data.element %}
+,ELEMENT = {{data.element}}{% endif %}{% if data.typdelim %}
+,DELIMITER = {{data.typdelim|qtLiteral}}{% endif %}{% if data.is_collatable %}
+,COLLATABLE = {{data.is_collatable}}{% endif %} );
+{% endif %}
+{### Type Owner ###}
+{% if data and data.typeowner %}
+
+ALTER TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
+ OWNER TO {{data.typeowner}};
+{% endif %}
+{### Type Comments ###}
+{% if data and data.description %}
+
+COMMENT ON TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
+ IS {{data.description|qtLiteral}};
+{% endif %}
+{### ACL ###}
+{% if data.typacl %}
+
+{% for priv in data.typacl %}
+{{ PRIVILEGE.APPLY(conn, 'TYPE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/delete.sql
new file mode 100644
index 0000000..06a279e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/delete.sql
@@ -0,0 +1,8 @@
+{% if scid and tid %}
+SELECT t.typname AS name
+FROM pg_type t
+WHERE t.oid = {{tid}}::oid
+{% endif %}
+{% if name %}
+DROP TYPE {{ conn|qtIdent(name) }}{% if cascade%} CASCADE{% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_collations.sql
new file mode 100644
index 0000000..d1c29bb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_collations.sql
@@ -0,0 +1,7 @@
+SELECT --nspname, collname,
+ CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(collname))
+ ELSE '' END AS collation
+FROM pg_collation c, pg_namespace n
+WHERE c.collnamespace=n.oid
+ORDER BY nspname, collname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_external_functions.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_external_functions.sql
new file mode 100644
index 0000000..7b76ed5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_external_functions.sql
@@ -0,0 +1,40 @@
+{### Input/Output/Send/Receive/Analyze function list also append into TypModeIN/TypModOUT ###}
+{% if extfunc %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS func
+FROM (
+ SELECT proname, nspname, max(proargtypes[0]) AS arg0, max(proargtypes[1]) AS arg1
+FROM pg_proc p
+ JOIN pg_namespace n ON n.oid=pronamespace
+GROUP BY proname, nspname
+ HAVING count(proname) = 1 ) AS uniquefunc
+ WHERE arg0 <> 0 AND arg1 = 0;
+{% endif %}
+{### TypmodIN list ###}
+{% if typemodin %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS func
+ FROM pg_proc p
+ JOIN pg_namespace n ON n.oid=pronamespace
+ WHERE prorettype=(SELECT oid FROM pg_type WHERE typname='int4')
+ AND proargtypes[0]=(SELECT oid FROM pg_type WHERE typname='_cstring')
+ AND proargtypes[1] IS NULL
+ ORDER BY nspname, proname;
+{% endif %}
+{### TypmodOUT list ###}
+{% if typemodout %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS func
+ FROM pg_proc p
+ JOIN pg_namespace n ON n.oid=pronamespace
+ WHERE prorettype=(SELECT oid FROM pg_type WHERE typname='cstring')
+ AND proargtypes[0]=(SELECT oid FROM pg_type WHERE typname='int4')
+ AND proargtypes[1] IS NULL
+ ORDER BY nspname, proname;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_name.sql
new file mode 100644
index 0000000..d368f0f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_name.sql
@@ -0,0 +1,3 @@
+SELECT t.typname AS name
+FROM pg_type t
+WHERE t.oid = {{tid}}::oid;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_oid.sql
new file mode 100644
index 0000000..2dd81c0
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_oid.sql
@@ -0,0 +1,11 @@
+{# Below will provide oid for newly created type #}
+SELECT t.oid
+FROM pg_type t
+LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+{% if data %}
+AND t.typname = {{data.name|qtLiteral}}
+{% endif %}
+ORDER BY t.typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_schemas.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_schemas.sql
new file mode 100644
index 0000000..f64b68a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_schemas.sql
@@ -0,0 +1,25 @@
+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)) OR
+ (nspname = 'dbo' OR nspname = 'sys')
+ )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\\_%' ) AND
+ -- Specific code for EDB PPAS
+ nsp.nspparent = 0 AND NOT
+ (nspname = 'dbms_job_procedure' AND EXISTS(SELECT 1 FROM pg_proc WHERE pronamespace = nsp.oid and proname = 'run_job' LIMIT 1))
+ORDER BY nspname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_subtypes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_subtypes.sql
new file mode 100644
index 0000000..1138ba4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_subtypes.sql
@@ -0,0 +1,56 @@
+{### To fill subtype combobox ###}
+{% if subtype %}
+SELECT DISTINCT typ.typname AS stype,
+ (CASE WHEN typ.typcollation > 0 THEN true ELSE false END) AS is_collate
+FROM pg_opclass opc
+JOIN pg_type typ ON opc.opcintype = typ.oid
+WHERE opc.opcmethod = 403
+ORDER BY 1
+{% endif %}
+{### To fill subtype opclass combobox ###}
+{% if subtype_opclass and data and data.typname %}
+SELECT opc.opcname
+FROM pg_opclass opc
+JOIN pg_type typ ON opc.opcintype=typ.oid
+AND typ.typname = {{ data.typname|qtLiteral }}
+WHERE opc.opcmethod = 403
+ORDER BY opcname;
+{% endif %}
+{### To fetch opcinttype from subtype opclass ###}
+{% if get_opcintype and data and data.typname and data.opcname %}
+SELECT opc.opcintype
+FROM pg_opclass opc
+JOIN pg_type typ ON opc.opcintype=typ.oid
+AND typ.typname = {{ data.typname|qtLiteral }}
+WHERE opc.opcmethod = 403
+AND opc.opcname = {{ data.opcname|qtLiteral }}
+ORDER BY opcname;
+{% endif %}
+{### To fill subtype diff function combobox ###}
+{% if opcintype %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS stypdiff
+FROM pg_proc
+JOIN pg_namespace n ON n.oid=pronamespace
+WHERE prorettype = 701
+AND proargtypes = '{{opcintype}} {{opcintype}}'
+ORDER BY proname;
+{% endif %}
+{### To fill canonical combobox ###}
+{% if getoid %}
+SELECT oid FROM pg_type
+WHERE typname = {{ data.name|qtLiteral }}
+{% endif %}
+{% if canonical and oid %}
+SELECT proname, nspname,
+ CASE WHEN length(nspname) > 0 AND length(proname) > 0 THEN
+ concat(quote_ident(nspname), '.', quote_ident(proname))
+ ELSE '' END AS canonical
+FROM pg_proc
+JOIN pg_namespace n ON n.oid=pronamespace
+WHERE prorettype= {{ oid }}
+AND proargtypes = '{{ oid }}'
+ORDER BY proname;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_types.sql
new file mode 100644
index 0000000..2f2ca70
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/get_types.sql
@@ -0,0 +1,10 @@
+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', 'd', 'e', 'r')AND NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = typname and relkind != 'c') AND (typname not like '_%' OR NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = substring(typname from 2)::name and relkind != 'c')) AND nsp.nspname != 'information_schema'
+ ) AS dummy
+ ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/nodes.sql
new file mode 100644
index 0000000..88cc34a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/nodes.sql
@@ -0,0 +1,7 @@
+SELECT t.oid, t.typname AS name
+FROM pg_type t
+LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+LEFT OUTER JOIN pg_namespace nsp ON nsp.oid = t.typnamespace
+WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+ORDER BY t.typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/properties.sql
new file mode 100644
index 0000000..f26ac7c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/properties.sql
@@ -0,0 +1,16 @@
+SELECT t.oid, t.typname AS name
+ ,(CASE WHEN CAST(coalesce(t.typcollation, '0') AS integer) = 100 THEN true ElSE false END) AS is_collatable
+ ,t.typacl AS type_acl
+ ,t.*, format_type(t.oid, null) AS alias
+ ,pg_get_userbyid(t.typowner) as typeowner, e.typname as element
+ ,description, ct.oid AS taboid
+ ,(CASE WHEN (t.oid <= {{ datlastsysoid}}::oid OR ct.oid != 0) THEN true ElSE false END) AS is_sys_type
+FROM pg_type t
+LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
+LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
+{% if tid %}
+AND t.oid = {{tid}}::oid
+{% endif %}
+ORDER BY t.typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/update.sql
new file mode 100644
index 0000000..3f2663a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/sql/pre_9.1/update.sql
@@ -0,0 +1,107 @@
+{% import 'macros/security.macros' as SECLABLE %}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{#======================================#}
+{# Below will change object owner #}
+{% if data.typeowner and data.typeowner != o_data.typeowner %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ OWNER TO {{ data.typeowner }};
+
+{% endif %}
+{#======================================#}
+{# Below will change objects comment #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{#======================================#}
+{### The sql given below will update composite type ###}
+{% if data.composite and data.composite|length > 0 %}
+{% set composite = data.composite %}
+{% if 'deleted' in composite and composite.deleted|length > 0 %}
+{% for r in composite.deleted %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ DROP ATTRIBUTE {{conn|qtIdent(r.member_name)}};
+{% endfor %}
+{% endif %}
+{% if 'added' in composite and composite.added|length > 0 %}
+{% for r in composite.added %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ADD ATTRIBUTE {{conn|qtIdent(r.member_name)}} {{conn|qtIdent(r.type)}}{% if r.is_tlength and r.tlength %}
+({{r.tlength}}{% if r.is_precision and r.precision %},{{r.precision}}{% endif %}){% endif %}{% if r.collation %}
+ COLLATE {{r.collation}}{% endif %};
+{% endfor %}
+{% endif %}
+{% if 'changed' in composite and composite.changed|length > 0 %}
+{% for r in composite.changed %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ALTER ATTRIBUTE {{conn|qtIdent(r.member_name)}} SET DATA TYPE {{conn|qtIdent(r.type)}}{% if r.is_tlength and r.tlength %}
+({{r.tlength}}{% if r.is_precision and r.precision %},{{r.precision}}{% endif %}){% endif %}{% if r.collation %}
+ COLLATE {{r.collation}}{% endif %};
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{### The sql given below will update enum type ###}
+{% if data.enum and data.enum|length > 0 %}
+{% set enum = data.enum %}
+{% set o_enum_len = o_data.enum|length %}
+{# We need actual list index from length #}
+{% set o_enum_len = o_enum_len - 1 %}
+{% if 'added' in enum and enum.added|length > 0 %}
+{% for r in enum.added %}
+{% set c_idx = loop.index %}
+{% if c_idx == 1 %}
+{# if first new element then add it after old data enum list#}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ADD VALUE {{r.label|qtLiteral}} AFTER {{o_data.enum[o_enum_len].label|qtLiteral }};
+{% else %}
+{# if first new element then add it after new data enum list#}
+{% set p_idx = loop.index - 2 %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ ADD VALUE {{r.label|qtLiteral}} AFTER {{enum.added[p_idx].label|qtLiteral}};
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{# Change the privileges #}
+{% if data.typacl %}
+{% if 'deleted' in data.typacl %}
+{% for priv in data.typacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'TYPE', priv.grantee, o_data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.typacl %}
+{% for priv in data.typacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'TYPE', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.typacl %}
+{% for priv in data.typacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{# Below will change object name #}
+{% if data.name and data.name != o_data.name %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+ RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{#======================================#}
+{# Below will change the schema for object #}
+{# with extra if condition we will also make sure that object has correct name #}
+{% if data.schema and data.schema != o_data.schema %}
+ALTER TYPE {% if data.name != o_data.name %}{{ conn|qtIdent(o_data.schema, data.name) }}
+{% else %}{{ conn|qtIdent(o_data.schema, o_data.name) }}{% endif %}
+ SET SCHEMA {{ conn|qtIdent(data.schema) }};
+
+{% endif %}
+{% endif %}
\ No newline at end of file
[application/octet-stream] catalog_objects_node_v4.patch (38.0K, 4-catalog_objects_node_v4.patch)
download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/__init__.py
new file mode 100644
index 0000000..408ecd3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/__init__.py
@@ -0,0 +1,314 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Catalog objects Node """
+
+from flask import render_template
+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.server_groups.servers.databases.schemas.utils \
+ import SchemaChildModule
+import pgadmin.browser.server_groups.servers.databases as database
+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 CatalogObjectModule(SchemaChildModule):
+ """
+ class CatalogObjectModule(CollectionNodeModule)
+
+ A module class for Catalog objects node derived from CollectionNodeModule.
+
+ Methods:
+ -------
+ * __init__(*args, **kwargs)
+ - Method is used to initialize the Catalog objects and it's base module.
+
+ * get_nodes(gid, sid, did, scid, coid)
+ - Method is used to generate the browser collection node.
+
+ * node_inode()
+ - Method is overridden from its base class to make the node as leaf node.
+
+ * script_load()
+ - Load the module script for Catalog objects, when any of the server node is
+ initialized.
+ """
+ NODE_TYPE = 'catalogobject'
+ COLLECTION_LABEL = gettext("Catalog Objects")
+
+ # Flag for not to show node under Schema/Catalog node
+ # By default its set to True to display node in schema/catalog
+ # We do not want to display 'Catalog Objects' under Schema/Catalog
+ # but only in information_schema/sys/dbo
+ CATALOG_DB_SUPPORTED = False
+ SUPPORTED_SCHEMAS = ['information_schema', 'sys', 'dbo']
+
+ def __init__(self, *args, **kwargs):
+ """
+ Method is used to initialize the CatalogObjectModule and it's base module.
+
+ Args:
+ *args:
+ **kwargs:
+ """
+ super(CatalogObjectModule, self).__init__(*args, **kwargs)
+ self.min_ver = None
+ self.max_ver = None
+
+ def get_nodes(self, gid, sid, did, scid):
+ """
+ Generate the collection node
+ """
+ yield self.generate_browser_collection_node(scid)
+
+ @property
+ def script_load(self):
+ """
+ Load the module script for server, when any of the database node is
+ initialized.
+ """
+ return database.DatabaseModule.NODE_TYPE
+
+blueprint = CatalogObjectModule(__name__)
+
+
+class CatalogObjectView(PGChildNodeView):
+ """
+ This class is responsible for generating routes for Catalog objects node
+
+ Methods:
+ -------
+ * __init__(**kwargs)
+ - Method is used to initialize the CatalogObjectView and it's base view.
+
+ * check_precondition()
+ - This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+
+ * list()
+ - This function is used to list all the Catalog objects nodes within that
+ collection.
+
+ * nodes()
+ - This function will used to create all the child node within that
+ collection, Here it will create all the Catalog objects node.
+
+ * properties(gid, sid, did, scid, coid)
+ - This function will show the properties of the selected
+ Catalog objects node
+
+ * dependency(gid, sid, did, scid):
+ - This function will generate dependency list show it in dependency
+ pane for the selected Catalog objects node.
+
+ * dependent(gid, sid, did, scid):
+ - This function will generate dependent list to show it in dependent
+ pane for the selected Catalog objects node.
+
+ """
+ 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': 'coid'}
+ ]
+
+ operations = dict({
+ 'obj': [
+ {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+ {'get': 'list', 'post': 'create'}
+ ],
+ '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'}],
+ 'configs': [{'get': 'configs'}]
+ })
+
+ def check_precondition(f):
+ """
+ This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+ """
+ @wraps(f)
+ def wrap(*args, **kwargs):
+ # Here args[0] will hold self & kwargs will hold gid,sid,did
+ self = args[0]
+ self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+ kwargs['sid']
+ )
+ self.conn = self.manager.connection(did=kwargs['did'])
+ # If DB not connected then return error to browser
+ if not self.conn.connected():
+ return precondition_required(
+ gettext(
+ "Connection to the server has been lost!"
+ )
+ )
+
+ self.template_path = 'catalogobject/sql/9.1_plus'
+
+ return f(*args, **kwargs)
+
+ return wrap
+
+ @check_precondition
+ def list(self, gid, sid, did, scid):
+ """
+ This function is used to list all the catalog objects
+ nodes within that collection.
+
+ Args:
+ gid: Server group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+
+ Returns:
+ JSON of available catalog objects nodes
+ """
+
+ SQL = render_template("/".join([self.template_path,
+ 'properties.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):
+ """
+ This function will used to create all the child node within that collection.
+ Here it will create all the catalog objects node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+
+ Returns:
+ JSON of available catalog objects child nodes
+ """
+ res = []
+ SQL = render_template("/".join([self.template_path,
+ 'nodes.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-catalogobject"
+ ))
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ @check_precondition
+ def properties(self, gid, sid, did, scid, coid):
+ """
+ This function will show the properties of the selected
+ catalog objects node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ scid: Schema ID
+ coid: Catalog object ID
+
+ Returns:
+ JSON of selected catalog objects node
+ """
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),
+ scid=scid, 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 dependents(self, gid, sid, did, scid, coid):
+ """
+ This function get the dependents and return ajax response
+ for the catalog objects node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ coid: catalog objects 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, coid):
+ """
+ This function get the dependencies and return ajax response
+ for the catalog objects node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ coid: catalog objects ID
+ """
+ dependencies_result = self.get_dependencies(
+ self.conn, coid
+ )
+
+ return ajax_response(
+ response=dependencies_result,
+ status=200
+ )
+
+CatalogObjectView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/__init__.py
new file mode 100644
index 0000000..d7d92aa
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/__init__.py
@@ -0,0 +1,355 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Columns Node (For Catalog objects) """
+
+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 as database
+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 ColumnsModule(CollectionNodeModule):
+ """
+ class ColumnModule(CollectionNodeModule)
+
+ A module class for column node derived from CollectionNodeModule.
+
+ Methods:
+ -------
+ * __init__(*args, **kwargs)
+ - Method is used to initialize the column and it's base module.
+
+ * get_nodes(gid, sid, did, scid, coid)
+ - Method is used to generate the browser collection node.
+
+ * node_inode()
+ - Method is overridden from its base class to make the node as leaf node.
+
+ * script_load()
+ - Load the module script for column, when any of the server node is
+ initialized.
+ """
+
+ NODE_TYPE = 'columns'
+ COLLECTION_LABEL = gettext("Columns")
+
+ def __init__(self, *args, **kwargs):
+ """
+ Method is used to initialize the ColumnModule and it's base module.
+
+ Args:
+ *args:
+ **kwargs:
+ """
+ super(ColumnsModule, self).__init__(*args, **kwargs)
+ self.min_ver = None
+ self.max_ver = None
+
+ def get_nodes(self, gid, sid, did, scid, coid):
+ """
+ Generate the collection node
+ """
+ yield self.generate_browser_collection_node(coid)
+
+ @property
+ def script_load(self):
+ """
+ Load the module script for server, when any of the database node is
+ initialized.
+ """
+ return database.DatabaseModule.NODE_TYPE
+
+ @property
+ def node_inode(self):
+ """
+ Load the module node as a leaf node
+ """
+ return False
+
+blueprint = ColumnsModule(__name__)
+
+
+class ColumnsView(PGChildNodeView):
+ """
+ This class is responsible for generating routes for column node
+
+ Methods:
+ -------
+ * __init__(**kwargs)
+ - Method is used to initialize the ColumnView and it's base view.
+
+ * check_precondition()
+ - This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+
+ * list()
+ - This function is used to list all the column nodes within that
+ collection.
+
+ * nodes()
+ - This function will used to create all the child node within that
+ collection, Here it will create all the column node.
+
+ * properties(gid, sid, did, scid, coid, clid)
+ - This function will show the properties of the selected
+ column node
+
+ * dependency(gid, sid, did, scid, coid, clid):
+ - This function will generate dependency list show it in dependency
+ pane for the selected column node.
+
+ * dependent(gid, sid, did, scid, coid, clid):
+ - This function will generate dependent list to show it in dependent
+ pane for the selected column node.
+
+ """
+
+ 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': 'coid'}
+ ]
+ ids = [
+ {'type': 'int', 'id': 'clid'}
+ ]
+
+ operations = dict({
+ 'obj': [
+ {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+ {'get': 'list', 'post': 'create'}
+ ],
+ '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'}],
+ 'configs': [{'get': 'configs'}]
+ })
+
+ def check_precondition(f):
+ """
+ This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+ """
+ @wraps(f)
+ def wrap(*args, **kwargs):
+ # Here args[0] will hold self & kwargs will hold gid,sid,did
+ self = args[0]
+ self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+ kwargs['sid']
+ )
+ self.conn = self.manager.connection(did=kwargs['did'])
+ # If DB not connected then return error to browser
+ if not self.conn.connected():
+ return precondition_required(
+ gettext(
+ "Connection to the server has been lost!"
+ )
+ )
+
+ self.template_path = 'columns/sql/9.1_plus'
+
+ return f(*args, **kwargs)
+
+ return wrap
+
+ @check_precondition
+ def list(self, gid, sid, did, scid, coid):
+ """
+ This function is used to list all the column
+ nodes within that collection.
+
+ Args:
+ gid: Server group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ coid: Catalog objects ID
+
+ Returns:
+ JSON of available column nodes
+ """
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']), coid=coid)
+ 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, coid):
+ """
+ This function will used to create all the child node within that collection.
+ Here it will create all the column node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ coid: Catalog objects ID
+
+ Returns:
+ JSON of available column child nodes
+ """
+ res = []
+ SQL = render_template("/".join([self.template_path,
+ 'nodes.sql']), coid=coid)
+ 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['atttypid'],
+ coid,
+ row['attname'],
+ icon="icon-column"
+ ))
+
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+ @check_precondition
+ def properties(self, gid, sid, did, scid, coid, clid):
+ """
+ This function will show the properties of the selected
+ column node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ scid: Schema ID
+ coid: Catalog object ID
+ clid: Column ID
+
+ Returns:
+ JSON of selected column node
+ """
+ SQL = render_template("/".join([self.template_path,
+ 'properties.sql']),coid=coid, clid=clid)
+ 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 dependents(self, gid, sid, did, scid, coid, clid):
+ """
+ This function get the dependents and return ajax response
+ for the column node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ coid: Catalog object ID
+ clid: Column ID
+ """
+ # Specific condition for column which we need to append
+ where = "WHERE dep.refobjid={0}::OID AND dep.refobjsubid={1}".format(
+ coid, clid
+ )
+
+ dependents_result = self.get_dependents(
+ self.conn, clid, where=where
+ )
+
+ # Specific sql to run againt column to fetch dependents
+ SQL = render_template("/".join([self.template_path,
+ 'depend.sql']), where=where)
+
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ for row in res['rows']:
+ ref_name = row['refname']
+ if ref_name is None:
+ continue
+
+ dep_type = ''
+ dep_str = row['deptype']
+ if dep_str == 'a':
+ dep_type = 'auto'
+ elif dep_str == 'n':
+ dep_type = 'normal'
+ elif dep_str == 'i':
+ dep_type = 'internal'
+
+ dependents_result.append({'type': 'sequence', 'name': ref_name, 'field': dep_type})
+
+ return ajax_response(
+ response=dependents_result,
+ status=200
+ )
+
+ @check_precondition
+ def dependencies(self, gid, sid, did, scid, coid, clid):
+ """
+ This function get the dependencies and return ajax response
+ for the column node.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ coid: Catalog objects ID
+ clid: Column ID
+
+ """
+ # Specific condition for column which we need to append
+ where = "WHERE dep.objid={0}::OID AND dep.objsubid={1}".format(
+ coid, clid
+ )
+
+ dependencies_result = self.get_dependencies(
+ self.conn, clid, where=where
+ )
+
+ return ajax_response(
+ response=dependencies_result,
+ status=200
+ )
+
+
+ColumnsView.register_node_view(blueprint)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/static/img/coll-columns.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/static/img/coll-columns.png
new file mode 100644
index 0000000000000000000000000000000000000000..89d758834d4176c1df2548db10b46b1f6b2e4ec5
GIT binary patch
literal 400
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}cz{ocE09*4`h3Ev&s(m&yL<QU
z)2C0LJ$u%^|9SG<<M-~}d-(9-vSrKOym_;3-MW`AU#?uaa_!o+>({S;_3G90=g%KJ
zc<}o5>kl73eEaro$BrEvHf-3qapU*z-`~D{TatgM6KFJJNswPKgTu2MX+REVfk$L9
zkoEv$x0Bg+Kt_S5i(`ny<=FG?VhsvBt`}W4E@ZQg__p6qm@nby;qrG1j0_I@c^(;r
zuhP)2X<D_P?dti2$vzyv(k(V*o?f?H<i?gXiRA)mhTUpwofQn*P8`|LWw=McNaXQ!
zy+q@@Yd0m1ylF3f{(An_-EV$!P4L^#_`09vh+=cW8=&2)C9V-ADTyViR>?)FK#IZ0
zz|cU~&`8(7FvQ5f%EZ{p#6;V`)XKoXVy3DbiiX_$l+3hBhz0{oum+H7D+4o#hEvl+
R*8nvzc)I$ztaD0e0s#BYr!@co
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/static/img/columns.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/static/img/columns.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd9f81df98fe27d81ade5144d66b3b09b96123c1
GIT binary patch
literal 435
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}X@F0NE09*4`h3Ev&s(m&yL<QU
zy?giW-@pI#>C<P=p0)3PzHHgD=g*(Nc=6)Rn>Xv$t$X?M<;s;SSFBjEcJ12r>({?}
z_3FWc2M-@UeDvti>eZ{)tXZ>Z)20s}KD>VY`qQURpFe;8`t|F#Z{K$8*s)>5hK(CH
ze*gac?c2BS-o49eKe!ZVF=I)PUoeBivm0qZ4rhT!WHFHT0Ash4*>*risi%u$h{WaE
z^B0Ah6a-om4Rm-iuV3+X<o2rm?|w$}?!!eN_y0*dcT_ORb6x7A={6cu<^6X}kY2Ib
zZ0TMHrih1I^CUh^d%@<y)3TvOv&K6iH~-RCTdVU6czMe9*h~1l{VS1_(D3~9P6_q4
zgXi+))!6E^|9xfrB*GzI-TA)^=m6Cc*NBpo#FA92<f2p{#b9J$XrOCoq-$UpVq{=t
zVr*q%qHSPmWnf@2Q&kQ{LvDUbW?CgggMlSj14y-%ff+=@sp+9>fEpM)UHx3vIVCg!
E0NRqnZ~y=R
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/js/columns.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/js/columns.js
new file mode 100644
index 0000000..f4a6ab7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/js/columns.js
@@ -0,0 +1,72 @@
+define(
+ ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+ if (!pgBrowser.Nodes['coll-columns']) {
+ var databases = pgAdmin.Browser.Nodes['coll-columns'] =
+ pgAdmin.Browser.Collection.extend({
+ node: 'columns',
+ label: '{{ _('Columns') }}',
+ type: 'coll-columns'
+ });
+ };
+
+ if (!pgBrowser.Nodes['columns']) {
+ pgAdmin.Browser.Nodes['columns'] = pgAdmin.Browser.Node.extend({
+ parent_type: 'catalogobject',
+ type: 'columns',
+ label: '{{ _('Columns') }}',
+ hasSQL: false,
+ hasDepends: true,
+ Init: function() {
+ /* Avoid mulitple registration of menus */
+ if (this.initialized)
+ return;
+
+ this.initialized = true;
+
+ },
+ model: pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ attname: undefined,
+ attowner: undefined,
+ atttypid: undefined,
+ attnum: undefined,
+ cltype: undefined,
+ collspcname: undefined,
+ attacl: undefined,
+ description: undefined
+ },
+ schema: [{
+ id: 'attname', label: '{{ _('Column') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'atttypid', label: '{{ _('Oid') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'attowner', label: '{{ _('Owner') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'attnum', label:'{{ _('Position') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'cltype', label:'{{ _('Data type') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'collspcname', label:'{{ _('Collation') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'attacl', label:'{{ _('ACL') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+ type: 'multiline', disabled: true
+ }
+ ]
+ })
+ });
+
+ }
+
+ return pgBrowser.Nodes['columns'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/depend.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/depend.sql
new file mode 100644
index 0000000..13c9229
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/depend.sql
@@ -0,0 +1,9 @@
+SELECT
+ ref.relname AS refname, d2.refclassid, dep.deptype AS deptype
+FROM pg_depend dep
+LEFT JOIN pg_depend d2 ON dep.objid=d2.objid AND dep.refobjid != d2.refobjid
+LEFT JOIN pg_class ref ON ref.oid=d2.refobjid
+LEFT JOIN pg_attribute att ON d2.refclassid=att.attrelid AND d2.refobjsubid=att.attnum
+{{ where }} AND
+dep.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef') AND
+dep.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d2.refobjid)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..f319b7f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/nodes.sql
@@ -0,0 +1,10 @@
+SELECT atttypid, attname
+FROM pg_attribute att
+ JOIN pg_type ty ON ty.oid=atttypid
+ JOIN pg_namespace tn ON tn.oid=ty.typnamespace
+ JOIN pg_class cl ON cl.oid=att.attrelid
+ JOIN pg_namespace na ON na.oid=cl.relnamespace
+WHERE att.attrelid = {{coid}}::oid
+ AND att.attnum > 0
+ AND att.attisdropped IS FALSE
+ORDER BY att.attnum
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..8362bcb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/columns/templates/columns/sql/9.1_plus/properties.sql
@@ -0,0 +1,39 @@
+SELECT att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
+ CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray,
+ format_type(ty.oid,NULL) AS typname,
+ format_type(ty.oid,att.atttypmod) AS displaytypname,
+ tn.nspname as typnspname, et.typname as elemtypname,
+ ty.typstorage AS defaultstorage, cl.relname, na.nspname,
+ att.attstattarget, description, cs.relname AS sername,
+ ns.nspname AS serschema,
+ (SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup,
+ indkey, coll.collname, nspc.nspname as collnspname , attoptions,
+ -- Start pgAdmin4, added to save time on client side parsing
+ CASE WHEN length(coll.collname) > 0 AND length(nspc.nspname) > 0 THEN
+ concat(coll.collname,'."',nspc.nspname,'"')
+ ELSE '' END AS collspcname,
+ CASE WHEN strpos(format_type(ty.oid,att.atttypmod), '.') > 0 THEN
+ split_part(format_type(ty.oid,att.atttypmod), '.', 2)
+ ELSE format_type(ty.oid,att.atttypmod) END AS cltype,
+ -- End pgAdmin4
+ EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As isfk,
+ (SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS labels,
+ (SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=att.attrelid AND sl2.objsubid=att.attnum) AS providers
+FROM pg_attribute att
+ JOIN pg_type ty ON ty.oid=atttypid
+ JOIN pg_namespace tn ON tn.oid=ty.typnamespace
+ JOIN pg_class cl ON cl.oid=att.attrelid
+ JOIN pg_namespace na ON na.oid=cl.relnamespace
+ LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem
+ LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
+ LEFT OUTER JOIN pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
+ LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
+ LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace
+ LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
+ LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid
+ LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
+WHERE att.attrelid = {{coid}}::oid
+ {% if clid %}AND att.atttypid = {{clid}}::oid{% endif %}
+ AND att.attnum > 0
+ AND att.attisdropped IS FALSE
+ORDER BY att.attnum
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/static/img/catalogobject.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/static/img/catalogobject.png
new file mode 100644
index 0000000000000000000000000000000000000000..54ed7389c128fdcdcd86bc504311b9ed62e890ff
GIT binary patch
literal 409
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E09*4`n>nT|4HY6FS`77
z*NwLq@4vkN`1#Xk&!0VecI)BOHRqluZ+xLQ`$hNp|E*{K)t&fLdiYn)z8{G@zJ+c2
z?7ilL!}53L3*P9?d8IbvW$T&0+53JtE_-LT@QvP_S6i;V`}u8J`~K&*j@bWvKj-(&
zo4+qyn4y_82WTr}NswPKgTu2MX+REVfk$L9koEv$x0Bg+Kt`OWi(`ny<>Z6}7e*c)
zo*thwI%{&?$jq4&bH`?n0;63WqoZP?V4z_kr{@MPJ55H%%mocSYh+v;;u!fv4l;3h
zFz78{aWi04RS0O9aOL`<HH&)Ixr&B%Z_;vMxcZwR(@;29_qOf^piQbJt`Q|Ei6yC4
z$wjF^iowXh&_LJFNY}tH#K^$P#MsKjMBBjB%D}*4rm7r@hTQy=%(O~~1_Mj529Rni
Y12c$*Q`1A&05vdpy85}Sb4q9e0Lf^e3;+NC
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/static/img/coll-catalogobject.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/static/img/coll-catalogobject.png
new file mode 100644
index 0000000000000000000000000000000000000000..85b89f1e75c3ba919e0f3f63235d14fb7bc58940
GIT binary patch
literal 419
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}W`IwKE09*4`n>DhzbWT`uD$x{
z)SXxN9zTEf{Q0wI&yL=BR<`qn!JHQzXa5Cl__X=z+n?X2HJ|=hb?kTkfuG4czlCl3
z?78}b?b5e~^IogZeA#^ZuNRQJ<gLccm+c3h-#TJH;ne49km4U2GhaM;`TYdYGRBf1
zzhDN3XE)M-9L@rd$YLPv0mg18v+aP4LQfaR5Q)pNeVlv^3Op<;)wR0J=T-dqKXF=D
z;7x%`K53IvKePoN_}pyJW$AzE4V%(`YXup0uH%d^EjTV{uHKcoJB~Mj!D=z%<uzj5
zT$!7r8kR3pmtU}z@dxAWZMQcV-k!sy{5*K!&;MLji|+8>Dm=t0E5ucyF7nz8Xt`>M
zYeY#(Vo9o1a#1RfVlXl=G|)9P(lsy)F*2|+F}5->(Kax(GBB{1sVaw}AvZrIGp!P$
f!N3x%0i@c>zzm|{)b!9bKn)C@u6{1-oD!M<aEhuj
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/js/catalogobject.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/js/catalogobject.js
new file mode 100644
index 0000000..d6f601a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/js/catalogobject.js
@@ -0,0 +1,56 @@
+define(
+ ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+ if (!pgBrowser.Nodes['coll-catalogobject']) {
+ var databases = pgAdmin.Browser.Nodes['coll-catalogobject'] =
+ pgAdmin.Browser.Collection.extend({
+ node: 'catalogobject',
+ label: '{{ _('Catalog Objects') }}',
+ type: 'coll-catalogobject'
+ });
+ };
+
+ if (!pgBrowser.Nodes['catalogobject']) {
+ pgAdmin.Browser.Nodes['catalogobject'] = pgAdmin.Browser.Node.extend({
+ parent_type: 'catalog',
+ type: 'catalogobject',
+ label: '{{ _('Catalog Object') }}',
+ hasSQL: false,
+ hasDepends: true,
+ Init: function() {
+ /* Avoid mulitple registration of menus */
+ if (this.initialized)
+ return;
+
+ this.initialized = true;
+
+ },
+ model: pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ name: undefined,
+ namespaceowner: undefined,
+ nspacl: undefined,
+ description: undefined,
+ },
+ schema: [{
+ id: 'name', label: '{{ _('Name') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'oid', label:'{{ _('Oid') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'owner', label:'{{ _('Owner') }}', cell: 'string',
+ type: 'text', disabled: true
+ },{
+ id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+ type: 'multiline' , disabled: true
+ }
+ ]
+ })
+ });
+
+ }
+
+ return pgBrowser.Nodes['catalogobject'];
+});
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/backend_support.sql
new file mode 100644
index 0000000..f9b9564
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/backend_support.sql
@@ -0,0 +1,18 @@
+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\\%'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..13a6db7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/nodes.sql
@@ -0,0 +1,9 @@
+SELECT c.oid, c.relname as name
+ FROM pg_class c
+WHERE relnamespace = {{scid}}::int
+OR (-- On EnterpriseDB we need to ignore some objects in the catalog, namely, _*, dual and type_object_source.
+ select 'sys' ~ (SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{scid}}::int)
+ AND
+ (c.relname NOT LIKE '\\_%' AND c.relname = 'dual' AND c.relname = 'type_object_source')
+ )
+ORDER BY relname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..5cf3e96
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalogobjects/templates/catalogobject/sql/9.1_plus/properties.sql
@@ -0,0 +1,13 @@
+SELECT c.oid, c.relname as name, pg_get_userbyid(relowner) AS owner, description
+ FROM pg_class c
+LEFT OUTER JOIN pg_description d ON (d.objoid=c.oid AND d.classoid='pg_class'::regclass)
+WHERE relnamespace = {{scid}}::int
+{% if coid %}
+AND c.oid = {{coid}}::int
+{% endif %}
+OR (-- On EnterpriseDB we need to ignore some objects in the catalog, namely, _*, dual and type_object_source.
+ select 'sys' ~ (SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{scid}}::int)
+ AND
+ (c.relname NOT LIKE '\\_%' AND c.relname = 'dual' AND c.relname = 'type_object_source')
+ )
+ORDER BY relname;
\ No newline at end of file
view thread (26+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: PATCH: Added Node Type & Catalog objects [pgAdmin4]
In-Reply-To: <CAKKotZSda6+wgyzckDJPXKK3dc8U-UXho9hmaaBp+LwZzdnhaQ@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox