Hi,

Attached patch adds support for Nested Table & Varay Type creation in
Advance Server.(Supported by  version > PPAS 96 )

Thanks,
Yogesh Mahajan
EnterpriseDB
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
index 143dc934f..46efe57f5 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
@@ -246,14 +246,12 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
             # Declare allows acl on type
             self.acl = ['U']
 
-            ver = self.manager.version
-            server_type = self.manager.server_type
-            # Set the template path for the SQL scripts
-            self.template_path = 'types/sql/' + (
-                '#{0}#{1}#'.format(server_type, ver)
-                if server_type == 'gpdb' else
-                '#{0}#'.format(ver)
-            )
+            self.template_path = "/".join([
+                'types',
+                self.manager.server_type,
+                'sql',
+                '#{0}#'
+            ]).format(self.manager.version)
 
             return f(*args, **kwargs)
 
@@ -472,6 +470,31 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
 
         return res
 
+    def _additional_properties_advanced_server_type(self, data):
+        """
+        Used by additional_properties internally for advanced server types.
+        :param rows: list of data
+        :return: formatted response
+        """
+        is_tlength, is_precision, typeval = \
+            self.get_length_precision(data.get('elemoid', None))
+
+        # Split length, precision from type name for grid
+        t_len, t_prec = DataTypeReader.parse_length_precision(
+            data['fulltype'], is_tlength, is_precision)
+
+        data = self.convert_length_precision_to_string(data)
+        data['type'] = self._cltype_formatter(data['type'])
+        data['cltype'] = self._cltype_formatter(data['type'])
+        data['hasSqrBracket'] = self.hasSqrBracket
+        data['tlength'] = t_len,
+        data['precision'] = t_prec
+        data['is_tlength'] = is_tlength,
+        data['is_precision'] = is_precision,
+        data['maxsize'] = data['typndims']
+
+        return data
+
     def additional_properties(self, copy_dict, tid):
         """
         We will use this function to add additional properties according to
@@ -485,13 +508,13 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
         of_type = copy_dict['typtype']
         res = dict()
 
-        render_args = {'type': of_type}
+        render_args = {'typtype': of_type}
         if of_type == 'c':
             render_args['typrelid'] = copy_dict['typrelid']
         else:
             render_args['tid'] = tid
 
-        if of_type in ('c', 'e', 'r'):
+        if of_type in ('c', 'e', 'r', 'N', 'V', 'A'):
             SQL = render_template("/".join([self.template_path,
                                             'additional_properties.sql']),
                                   **render_args)
@@ -505,6 +528,11 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
             # To display in properties
             res = self._additional_properties_composite(rset['rows'])
 
+        if of_type in ('N', 'V'):
+            # To display in properties
+            res = self._additional_properties_advanced_server_type(
+                rset['rows'][0])
+
         # If type is of ENUM then we need to add labels in our output
         if of_type == 'e':
             # To display in properties
@@ -1003,6 +1031,12 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
                         each_type['type'])
                     each_type['hasSqrBracket'] = self.hasSqrBracket
 
+            of_type = data.get('typtype', None)
+            if of_type in ('N', 'V'):
+                data = self.convert_length_precision_to_string(data)
+                data['cltype'] = self._cltype_formatter(data['type'])
+                data['hasSqrBracket'] = self.hasSqrBracket
+
             SQL = render_template("/".join([self.template_path,
                                             self._CREATE_SQL]),
                                   data=data, conn=self.conn)
@@ -1281,6 +1315,15 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
                     each_type['type'])
                 each_type['hasSqrBracket'] = self.hasSqrBracket
 
+        of_type = data.get('typtype', None)
+        if of_type in ('N', 'V', 'A'):
+            data = self.convert_length_precision_to_string(data)
+            data['cltype'] = self._cltype_formatter(data['type'])
+            data['hasSqrBracket'] = self.hasSqrBracket
+            if of_type == 'V':
+                data['typndims'] = data['maxsize']
+                # data['maxsize'] = data['typndims']
+
         SQL = render_template("/".join([self.template_path,
                                         self._CREATE_SQL]),
                               data=data, conn=self.conn, is_sql=is_sql)
@@ -1307,6 +1350,16 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
                         each_type['type'])
                     each_type['hasSqrBracket'] = self.hasSqrBracket
 
+            of_type = data.get('typtype', None)
+            if of_type in ('N', 'V', 'A'):
+                data = self.convert_length_precision_to_string(data)
+                data['cltype'] = self._cltype_formatter(data['type'])
+                data['hasSqrBracket'] = self.hasSqrBracket
+
+                if of_type == 'V':
+                    data['typndims'] = data['maxsize']
+                    # data['maxsize'] = data['typndims']
+
         SQL = render_template(
             "/".join([self.template_path,
                       self._PROPERTIES_SQL]),
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/js/type.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/js/type.js
index 5c4b869fd..f0196a61f 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/js/type.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/static/js/type.js
@@ -343,13 +343,21 @@ define('pgadmin.node.type', [
           group: gettext('Definition'),
           select2: { allowClear: false },
           options: function() {
-            return [
+            var typetype = [
               {label: gettext('Composite'), value: 'c'},
               {label: gettext('Enumeration'), value: 'e'},
               {label: gettext('External'), value: 'b'},
               {label: gettext('Range'), value: 'r'},
               {label: gettext('Shell'), value: 'p'},
             ];
+            if (this.node_info.server.server_type === 'ppas' &&
+            this.node_info.server.version >= 100000){
+              typetype.push(
+                {label: gettext('Nested Table'), value: 'N'},
+                {label: gettext('Varying Array'), value: 'V'}
+              );
+            }
+            return typetype;
           },
           // If create mode then by default open composite type
           control: Backform.Select2Control.extend({
@@ -385,6 +393,171 @@ define('pgadmin.node.type', [
           visible: function(m) {
             return m.get('typtype') === 'e';
           },
+        },{
+          type: 'nested',
+          group: gettext('Definition'),
+          label: '',
+          control: 'plain-fieldset',
+          deps: ['typtype'],
+          mode: ['edit', 'create', 'properties'],
+          visible: function (m) {
+            return m.get('typtype') === 'N' || m.get('typtype') === 'V';
+          },
+          schema: [{
+            id: 'type',
+            type: 'text',
+            label: gettext('Data Type'),
+            group: gettext('Definition'),
+            control: 'node-ajax-options',
+            mode: ['edit', 'create','properties'],
+            readonly: 'inEditMode',
+            url: 'get_types',
+            disabled: false,
+            node: 'type',
+            cache_node: 'domain',
+            editable: true,
+            deps: ['typtype'],
+            cell: 'node-ajax-options',
+            select2: { allowClear: false },
+            transform: function (d, control) {
+              var data_types = [];
+              _.each(d, function (o) {
+                if (!(o.value.includes('[]'))) {
+                  data_types.push(o);
+                }
+              });
+              control.model.type_options = data_types;
+              return data_types;
+            },
+          },{
+            id: 'maxsize',
+            group: gettext('Definition'),
+            label: gettext('Size'),
+            type: 'int',
+            deps: ['typtype'],
+            cell: IntegerDepCell,
+            mode: ['create', 'edit','properties'],
+            readonly: 'inEditMode',
+            visible: function (m) {
+              return m.get('typtype') === 'V';
+            }
+          },{
+          // Note: There are ambiguities in the PG catalogs and docs between
+          // precision and scale. In the UI, we try to follow the docs as
+          // closely as possible, therefore we use Length/Precision and Scale
+            id: 'tlength',
+            group: gettext('Data Type'),
+            label: gettext('Length/Precision'),
+            mode: ['edit', 'create','properties'],
+            deps: ['type'],
+            type: 'text',
+            readonly: 'inEditMode',
+            cell: IntegerDepCell,
+            visible: function (m) {
+              return m.get('typtype') === 'N';
+            },
+            disabled: function (m) {
+              var of_type = m.get('type'),
+                flag = true;
+              _.each(m.type_options, function (o) {
+                if (of_type == o.value) {
+                  if (o.length) {
+                    m.set('min_val_attlen', o.min_val, { silent: true });
+                    m.set('max_val_attlen', o.max_val, { silent: true });
+                    flag = false;
+                  }
+                }
+              });
+              flag && setTimeout(function () {
+                if (m.get('attlen')) {
+                  m.set('attlen', null);
+                }
+              }, 10);
+              return flag;
+            },
+            editable: 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 });
+                    } else {
+                      // set the values in model
+                      m.set('is_tlength', false, { silent: true });
+                    }
+                  }
+                });
+              }
+              return m.get('is_tlength');
+            }
+          },{
+            // Note: There are ambiguities in the PG catalogs and docs between
+            // precision and scale. In the UI, we try to follow the docs as
+            // closely as possible, therefore we use Length/Precision and Scale
+            id: 'precision', 
+            group: gettext('Data Type'),
+            label: gettext('Scale'),
+            mode: ['edit', 'create','properties'],
+            deps: ['type'],
+            type: 'text', 
+            readonly: 'inEditMode',
+            cell: IntegerDepCell,
+            visible: function (m) {
+              return m.get('typtype') === 'N';
+            },
+            disabled: function(m) {
+              var of_type = m.get('type'),
+                flag = true;
+              _.each(m.type_options, function(o) {
+                if ( of_type == o.value ) {
+                  if(o.precision) {
+                    m.set('min_val_attprecision', 0, {silent: true});
+                    m.set('max_val_attprecision', o.max_val, {silent: true});
+                    flag = false;
+                  }
+                }
+              });
+
+              flag && setTimeout(function() {
+                if(m.get('attprecision')) {
+                  m.set('attprecision', null);
+                }
+              },10);
+              return flag;
+            },
+            editable: 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});
+                    } else {
+                      // set the values in model
+                      m.set('is_precision', false, {silent: true});
+                    }
+                  }
+                });
+              }
+              return m.get('is_precision');
+            },
+          }]
         },{
           // We will disable range type control in edit mode
           type: 'nested', control: 'plain-fieldset', group: gettext('Definition'),
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/acl.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/acl.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/acl.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/additional_properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/additional_properties.sql
similarity index 95%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/additional_properties.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/additional_properties.sql
index fd97d8c37..1f4d45255 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/additional_properties.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/additional_properties.sql
@@ -1,5 +1,5 @@
 {# The SQL given below will fetch composite type#}
-{% if type == 'c' %}
+{% if typtype == 'c' %}
 SELECT attnum, attname, pg_catalog.format_type(t.oid,NULL) AS typname, attndims, atttypmod, nsp.nspname,
     (SELECT COUNT(1) from pg_catalog.pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup,
     collname, nspc.nspname as collnspname, att.attrelid,
@@ -16,7 +16,7 @@ FROM pg_catalog.pg_attribute att
 {% endif %}
 
 {# The SQL given below will fetch enum type#}
-{% if type == 'e' %}
+{% if typtype == 'e' %}
 SELECT enumlabel
 FROM pg_catalog.pg_enum
     WHERE enumtypid={{tid}}::oid
@@ -24,7 +24,7 @@ FROM pg_catalog.pg_enum
 {% endif %}
 
 {# The SQL given below will fetch range type#}
-{% if type == 'r' %}
+{% if typtype == 'r' %}
 SELECT rngsubtype, st.typname,
     rngcollation,
     CASE WHEN n.nspname IS NOT NULL THEN pg_catalog.concat(pg_catalog.quote_ident(n.nspname), '.', pg_catalog.quote_ident(col.collname)) ELSE col.collname END AS collname,
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/create.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/create.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/create.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/delete.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/delete.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/delete.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_collations.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_collations.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_collations.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_external_functions.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_external_functions.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_external_functions.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_external_functions.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_oid.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_oid.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_oid.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_scid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_scid.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_scid.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_scid.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_subtypes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_subtypes.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_subtypes.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_subtypes.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_types.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/get_types.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/get_types.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/nodes.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/nodes.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/nodes.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/properties.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/properties.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/properties.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/type_schema_diff.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/type_schema_diff.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/type_schema_diff.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/type_schema_diff.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/update.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/default/update.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/default/update.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/acl.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/acl.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/acl.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/additional_properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/additional_properties.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/additional_properties.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/additional_properties.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/get_collations.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/get_collations.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/get_collations.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/properties.sql
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/gpdb_5.0_plus/properties.sql
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/gpdb_5.0_plus/properties.sql
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/postgres_inbuit_types.txt b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/postgres_inbuit_types.txt
similarity index 100%
rename from web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/sql/postgres_inbuit_types.txt
rename to web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/pg/sql/postgres_inbuit_types.txt
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/acl.sql
new file mode 100644
index 000000000..54dc1eed1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/acl.sql
@@ -0,0 +1,27 @@
+SELECT 'typacl' as deftype, COALESCE(gt.rolname, 'PUBLIC') grantee, g.rolname grantor, pg_catalog.array_agg(privilege_type) as privileges, pg_catalog.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_catalog.pg_type t
+            LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
+            LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+            LEFT OUTER JOIN pg_catalog.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
+            pg_catalog.aclexplode(t.typacl) as d FROM pg_catalog.pg_type t WHERE t.oid = {{tid}}::oid) a ORDER BY privilege_type) 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
+ORDER BY grantee
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/additional_properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/additional_properties.sql
new file mode 100644
index 000000000..8379a23e8
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/additional_properties.sql
@@ -0,0 +1,58 @@
+{# The SQL given below will fetch composite type#}
+{% if typtype == 'c' %}
+SELECT attnum, attname, pg_catalog.format_type(t.oid,NULL) AS typname, attndims, atttypmod, nsp.nspname,
+    (SELECT COUNT(1) from pg_catalog.pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup,
+    collname, nspc.nspname as collnspname, att.attrelid,
+    pg_catalog.format_type(t.oid, att.atttypmod) AS fulltype,
+    CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END as elemoid
+FROM pg_catalog.pg_attribute att
+    JOIN pg_catalog.pg_type t ON t.oid=atttypid
+    JOIN pg_catalog.pg_namespace nsp ON t.typnamespace=nsp.oid
+    LEFT OUTER JOIN pg_catalog.pg_type b ON t.typelem=b.oid
+    LEFT OUTER JOIN pg_catalog.pg_collation c ON att.attcollation=c.oid
+    LEFT OUTER JOIN pg_catalog.pg_namespace nspc ON c.collnamespace=nspc.oid
+    WHERE att.attrelid = {{typrelid}}::oid
+    ORDER by attnum;
+{% endif %}
+
+{# The SQL given below will fetch enum type#}
+{% if typtype == 'e' %}
+SELECT enumlabel
+FROM pg_catalog.pg_enum
+    WHERE enumtypid={{tid}}::oid
+    ORDER by enumsortorder
+{% endif %}
+
+{# The SQL given below will fetch range type#}
+{% if typtype == 'r' %}
+SELECT rngsubtype, st.typname,
+    rngcollation,
+    CASE WHEN n.nspname IS NOT NULL THEN pg_catalog.concat(pg_catalog.quote_ident(n.nspname), '.', pg_catalog.quote_ident(col.collname)) ELSE col.collname END AS collname,
+    rngsubopc, opc.opcname,
+    rngcanonical, rngsubdiff
+FROM pg_catalog.pg_range
+    LEFT JOIN pg_catalog.pg_type st ON st.oid=rngsubtype
+    LEFT JOIN pg_catalog.pg_collation col ON col.oid=rngcollation
+    LEFT JOIN pg_catalog.pg_namespace n ON col.collnamespace=n.oid
+    LEFT JOIN pg_catalog.pg_opclass opc ON opc.oid=rngsubopc
+    WHERE rngtypid={{tid}}::oid;
+{% endif %}
+
+{# The SQL given below will fetch enum type#}
+{% if typtype == 'N' or typtype == 'V' %}
+SELECT t.typname AS typname,
+	   CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END AS elemoid,
+	   t.typtypmod,
+	   t.typtype,
+	   t.typndims,
+	   pg_catalog.format_type(e.oid,NULL) AS type,
+	   pg_catalog.format_type(e.oid, t.typtypmod) AS fulltype,
+	   nsp.nspname as typnspname,
+	   e.typname as type,
+	   (SELECT COUNT(1) FROM pg_catalog.pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup,
+       CASE WHEN t.typcollation != 0 THEN TRUE ELSE FALSE END AS is_collatable
+FROM pg_catalog.pg_type t
+	LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON typnamespace=nsp.oid
+	LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
+WHERE t.oid={{tid}}::oid;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/create.sql
new file mode 100644
index 000000000..691735732
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/create.sql
@@ -0,0 +1,94 @@
+{% import 'macros/schemas/security.macros' as SECLABEL %}
+{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
+{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
+{## If user selected shell type then just create type template ##}
+{% if data and data.typtype == 'p' %}
+CREATE TYPE {{ conn|qtIdent(data.schema, data.name) }};
+{% endif %}
+{###  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
+({{"\n\t"}}{% if data.composite %}{% for d in data.composite %}{% if loop.index != 1 %},{{"\n\t"}}{% endif %}{{ conn|qtIdent(d.member_name) }} {% if is_sql %}{{ d.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, d.cltype, d.tlength, d.precision, d.hasSqrBracket) }}{% endif %}{% if d.collation %} COLLATE {{d.collation}}{% endif %}{% endfor %}{% endif %}{{"\n"}});
+{% 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 == 'b' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
+
+(
+    {% if data.typinput %}INPUT = {{data.typinput}}{% endif %}{% if data.typoutput %},
+    OUTPUT = {{ data.typoutput }}{% endif %}{% if data.typreceive %},
+    RECEIVE = {{data.typreceive}}{% endif %}{% if data.typsend %},
+    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|qtLiteral}}{% endif %}{% if data.typispreferred %},
+    PREFERRED =  {{data.typispreferred}}{% endif %}{% if data.typdefault %},
+    DEFAULT = {{data.typdefault|qtLiteral}}{% 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 %}
+{###  Nested-table Type ###}
+{% if data and data.typtype == 'N' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS TABLE OF
+    {% if is_sql %}{{ data.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.tlength, data.precision, data.hasSqrBracket) }}{% endif %};
+{% endif %}
+{###  VARRAY Type ###}
+{% if data and data.typtype == 'V' %}
+CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS VARRAY({{data.maxsize}}) OF
+    {% if is_sql %}{{ data.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.tlength, data.precision, data.hasSqrBracket) }}{% 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 {{ conn|qtIdent(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.SET(conn, 'TYPE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{###  Security Lables ###}
+{% if data.seclabels %}
+
+{% for r in data.seclabels %}
+{% if r.provider and r.label %}
+{{ SECLABEL.SET(conn, 'TYPE', data.name, r.provider, r.label, data.schema) }}
+{% endif %}
+{% endfor %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/delete.sql
new file mode 100644
index 000000000..c25882706
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/delete.sql
@@ -0,0 +1 @@
+DROP TYPE {{ conn|qtIdent(data.schema, data.name) }}{% if cascade%} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_collations.sql
new file mode 100644
index 000000000..2b5cb534c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_collations.sql
@@ -0,0 +1,7 @@
+SELECT --nspname, collname,
+    CASE WHEN length(nspname::text) > 0 AND length(collname::text) > 0  THEN
+        pg_catalog.concat(pg_catalog.quote_ident(nspname), '.', pg_catalog.quote_ident(collname))
+    ELSE '' END AS collation
+FROM pg_catalog.pg_collation c, pg_catalog.pg_namespace n
+WHERE c.collnamespace=n.oid
+ORDER BY nspname, collname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_external_functions.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_external_functions.sql
new file mode 100644
index 000000000..425df8845
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_external_functions.sql
@@ -0,0 +1,42 @@
+{### Input/Output/Send/Receive/Analyze function list also append into TypModeIN/TypModOUT ###}
+{% if extfunc %}
+SELECT proname, nspname,
+    CASE WHEN (length(nspname::text) > 0 AND nspname != 'public') and length(proname::text) > 0  THEN
+        pg_catalog.concat(pg_catalog.quote_ident(nspname), '.', pg_catalog.quote_ident(proname))
+    WHEN length(proname::text) > 0 THEN
+        pg_catalog.quote_ident(proname)
+    ELSE '' END AS func
+FROM (
+    SELECT proname, nspname, max(proargtypes[0]) AS arg0, max(proargtypes[1]) AS arg1
+FROM pg_catalog.pg_proc p
+    JOIN pg_catalog.pg_namespace n ON n.oid=pronamespace
+GROUP BY proname, nspname
+HAVING count(proname) = 1) AS uniquefunc
+WHERE arg0 <> 0 AND (arg1 IS NULL OR arg1 <> 0);
+{% endif %}
+{### TypmodIN list ###}
+{% if typemodin %}
+SELECT proname, nspname,
+    CASE WHEN length(nspname::text) > 0 AND length(proname::text) > 0  THEN
+        pg_catalog.concat(pg_catalog.quote_ident(nspname), '.', pg_catalog.quote_ident(proname))
+    ELSE '' END AS func
+FROM pg_catalog.pg_proc p
+    JOIN pg_catalog.pg_namespace n ON n.oid=pronamespace
+WHERE prorettype=(SELECT oid FROM pg_catalog.pg_type WHERE typname='int4')
+    AND proargtypes[0]=(SELECT oid FROM pg_catalog.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::text) > 0 AND length(proname::text) > 0  THEN
+        pg_catalog.concat(pg_catalog.quote_ident(nspname), '.', pg_catalog.quote_ident(proname))
+    ELSE '' END AS func
+FROM pg_catalog.pg_proc p
+    JOIN pg_catalog.pg_namespace n ON n.oid=pronamespace
+WHERE prorettype=(SELECT oid FROM pg_catalog.pg_type WHERE typname='cstring')
+    AND proargtypes[0]=(SELECT oid FROM pg_catalog.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/types/ppas/sql/default/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_oid.sql
new file mode 100644
index 000000000..d5282bc10
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_oid.sql
@@ -0,0 +1,11 @@
+{# Below will provide oid for newly created type #}
+SELECT t.oid
+FROM pg_catalog.pg_type t
+    LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
+    LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+    LEFT OUTER JOIN pg_catalog.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;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_scid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_scid.sql
new file mode 100644
index 000000000..65d7661d4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_scid.sql
@@ -0,0 +1,15 @@
+{% if tid %}
+SELECT
+    t.typnamespace as scid
+FROM
+    pg_catalog.pg_type t
+WHERE
+    t.oid = {{tid}}::oid;
+{% else %}
+SELECT
+    ns.oid as scid
+FROM
+    pg_catalog.pg_namespace ns
+WHERE
+    ns.nspname = {{schema|qtLiteral}}::text;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_subtypes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_subtypes.sql
new file mode 100644
index 000000000..f8ba524a2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/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_catalog.pg_opclass opc
+    JOIN pg_catalog.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_catalog.pg_opclass opc
+    JOIN pg_catalog.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_catalog.pg_opclass opc
+    JOIN pg_catalog.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::text) > 0 AND length(proname::text) > 0  THEN
+        pg_catalog.concat(quote_ident(nspname), '.', pg_catalog.quote_ident(proname))
+    ELSE '' END AS stypdiff
+FROM pg_catalog.pg_proc
+    JOIN pg_catalog.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_catalog.pg_type
+WHERE typname = {{ data.name|qtLiteral }}
+{% endif %}
+{% if canonical and oid %}
+SELECT proname, nspname,
+    CASE WHEN length(nspname::text) > 0 AND length(proname::text) > 0  THEN
+        pg_catalog.concat(quote_ident(nspname), '.', pg_catalog.quote_ident(proname))
+    ELSE '' END AS canonical
+FROM pg_catalog.pg_proc
+    JOIN pg_catalog.pg_namespace n ON n.oid=pronamespace
+WHERE prorettype= {{ oid }}
+    AND proargtypes = '{{ oid }}'
+ORDER BY proname;
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_types.sql
new file mode 100644
index 000000000..4beb57574
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/get_types.sql
@@ -0,0 +1,11 @@
+SELECT * FROM
+    (SELECT pg_catalog.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_catalog.pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup,
+    CASE WHEN t.typcollation != 0 THEN TRUE ELSE FALSE END AS is_collatable
+FROM pg_catalog.pg_type t
+   JOIN pg_catalog.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_catalog.pg_class where relnamespace=typnamespace and relname = typname and relkind != 'c') AND (typname not like '_%' OR NOT EXISTS (select 1 from pg_catalog.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
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/nodes.sql
new file mode 100644
index 000000000..5cab7ef1d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/nodes.sql
@@ -0,0 +1,13 @@
+SELECT t.oid, t.typname AS name
+FROM pg_catalog.pg_type t
+    LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
+    LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+    LEFT OUTER JOIN pg_catalog.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 %}
+{% if not show_system_objects %}
+    AND ct.oid is NULL
+{% endif %}
+ORDER BY t.typname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/properties.sql
new file mode 100644
index 000000000..09728bf20
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/properties.sql
@@ -0,0 +1,24 @@
+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.*, pg_catalog.format_type(t.oid, null) AS alias,
+    pg_catalog.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 pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabel 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_catalog.pg_type t
+    LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
+    LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
+    LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
+    LEFT OUTER JOIN pg_catalog.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 %}
+{% if not show_system_objects %}
+    AND ct.oid is NULL
+{% endif %}
+ORDER BY t.typname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/update.sql
new file mode 100644
index 000000000..036ea2a11
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/types/ppas/sql/default/update.sql
@@ -0,0 +1,161 @@
+{% import 'macros/schemas/security.macros' as SECLABEL %}
+{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
+{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
+{#======================================#}
+{# 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 {{ conn|qtIdent(data.typeowner) }};
+
+{% endif %}
+{#======================================#}
+{# Below will change objects comment  #}
+{% if data.description is defined 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)}} {{ GET_TYPE.CREATE_TYPE_SQL(conn, r.cltype, r.tlength, r.precision, r.hasSqrBracket) }}{% if r.collation %}
+ COLLATE {{r.collation}}{% endif %};
+{% endfor %}
+{% endif %}
+{% if 'changed' in composite and composite.changed|length > 0 %}
+{% for r in composite.changed %}
+{% for o in o_data.composite %}
+{##### Variables for the loop #####}
+{% set member_name = o.member_name %}
+{% set cltype = o.cltype %}
+{% set tlength = o.tlength %}
+{% set precision = o.precision %}
+{% set hasSqrBracket = o.hasSqrBracket %}
+{##### If member name changed #####}
+{% if o.attnum == r.attnum %}
+{% if r.member_name and o.member_name != r.member_name %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+    RENAME ATTRIBUTE {{o.member_name}} TO {{r.member_name}};
+{% set member_name = r.member_name %}
+{% endif %}
+{##### If type changed #####}
+{% if r.cltype and cltype != r.cltype %}
+{% set cltype = r.cltype %}
+{% set hasSqrBracket = r.hasSqrBracket %}
+{##### If length is not allowed on type #####}
+{% if not r.is_tlength %}
+{% set tlength = 0 %}
+{% set precision = 0 %}
+{% endif %}
+{% endif %}
+{##### If length changed #####}
+{% if r.tlength and tlength != r.tlength %}
+{% set tlength = r.tlength %}
+{% endif %}
+{##### If precision changed #####}
+{% if tlength and r.precision and precision != r.precision %}
+{% set precision = r.precision %}
+{% endif %}
+ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
+        ALTER ATTRIBUTE {{conn|qtIdent(member_name)}} SET DATA TYPE {{ GET_TYPE.CREATE_TYPE_SQL(conn, cltype, tlength, precision, hasSqrBracket) }}{% if r.collation %}
+ COLLATE {{r.collation}}{% endif %};
+{% endif%}
+{% endfor %}
+{% 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}} {% if o_enum_len > 0 %}AFTER {{o_data.enum[o_enum_len].label|qtLiteral }}{% endif %};
+{% 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 %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABEL.UNSET(conn, 'TYPE', o_data.name, r.provider, o_data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABEL.SET(conn, 'TYPE', o_data.name, r.provider, r.label, o_data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABEL.SET(conn, 'TYPE', o_data.name, r.provider, r.label, o_data.schema) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
+{#======================================#}
+{# Change the privileges #}
+{% if data.typacl and data.typacl|length > 0 %}
+{% if 'deleted' in data.typacl %}
+{% for priv in data.typacl.deleted %}
+{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.typacl %}
+{% for priv in data.typacl.changed %}
+{% if priv.grantee != priv.old_grantee %}
+{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.old_grantee, o_data.name, o_data.schema) }}
+{% else %}
+{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
+{% endif %}
+{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant, o_data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.typacl %}
+{% for priv in data.typacl.added %}
+{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant, o_data.schema) }}
+{% 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 and 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 %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/create_nested_table_type.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/create_nested_table_type.sql
new file mode 100644
index 000000000..82188ce58
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/create_nested_table_type.sql
@@ -0,0 +1,9 @@
+-- Type: nested_table_type_$%{}[]()&*^!@"'`\/#
+
+-- DROP TYPE public."nested_table_type_$%{}[]()&*^!@""'`\/#";
+
+CREATE TYPE public."nested_table_type_$%{}[]()&*^!@""'`\/#" AS TABLE OF
+    numeric(2,1);
+
+ALTER TYPE public."nested_table_type_$%{}[]()&*^!@""'`\/#"
+    OWNER TO enterprisedb;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/create_varray_type.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/create_varray_type.sql
new file mode 100644
index 000000000..b7f01d412
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/create_varray_type.sql
@@ -0,0 +1,9 @@
+-- Type: varray_type_$%{}[]()&*^!@"'`\/#
+
+-- DROP TYPE public."varray_type_$%{}[]()&*^!@""'`\/#";
+
+CREATE TYPE public."varray_type_$%{}[]()&*^!@""'`\/#" AS VARRAY(10) OF
+    integer;
+
+ALTER TYPE public."varray_type_$%{}[]()&*^!@""'`\/#"
+    OWNER TO enterprisedb;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/tests.json
index cc662721e..94018e027 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/tests.json
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/ppas/default/tests.json
@@ -53,7 +53,45 @@
       "data": {}
     },
 
-
+    {
+      "type": "create",
+      "name": "Create Nested Table type",
+      "endpoint": "NODE-type.obj",
+      "sql_endpoint": "NODE-type.sql_id",
+      "msql_endpoint": "NODE-type.msql",
+      "data": {
+        "name": "nested_table_type_$%{}[]()&*^!@\"'`\\/#",
+        "is_sys_type":false,
+        "typtype":"N",
+        "schema":"public",
+        "type": "numeric",
+        "tlength": 2,
+        "precision": 1,
+        "typacl":[],
+        "seclabels":[],
+        "description":""
+      },
+      "expected_sql_file": "create_nested_table_type.sql"
+    },
+     {
+      "type": "create",
+      "name": "Create Varray type",
+      "endpoint": "NODE-type.obj",
+      "sql_endpoint": "NODE-type.sql_id",
+      "msql_endpoint": "NODE-type.msql",
+      "data": {
+        "name": "varray_type_$%{}[]()&*^!@\"'`\\/#",
+        "is_sys_type":false,
+        "typtype":"V",
+        "schema":"public",
+        "type": "integer",
+        "maxsize": 10,
+        "typacl":[],
+        "seclabels":[],
+        "description":""
+      },
+      "expected_sql_file": "create_varray_type.sql"
+    },
     {
       "type": "create",
       "name": "Create Composite type",
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/test_types_add.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/test_types_add.py
index 7a3cbd13a..77b81a430 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/test_types_add.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/test_types_add.py
@@ -19,6 +19,7 @@ from regression import parent_node_dict
 from regression.python_test_utils import test_utils as utils
 from . import utils as types_utils
 from unittest.mock import patch
+from pgadmin.utils import server_utils as server_utils
 
 
 class TypesAddTestCase(BaseTestGenerator):
@@ -27,10 +28,23 @@ class TypesAddTestCase(BaseTestGenerator):
                                          types_utils.test_cases)
 
     def setUp(self):
+        self.data = self.test_data
         self.db_name = parent_node_dict["database"][-1]["db_name"]
         schema_info = parent_node_dict["schema"][-1]
         self.server_id = schema_info["server_id"]
         self.db_id = schema_info["db_id"]
+
+        # Check DB version
+        if "server_min_version" in self.data:
+            server_con = server_utils.connect_server(self, self.server_id)
+            if not server_con["info"] == "Server connected.":
+                raise Exception("Could not connect to server to add "
+                                "a table.")
+            if (server_con["data"]["type"] == 'pg' or
+                    server_con["data"]["version"] <=
+                    self.data["server_min_version"]):
+                self.skipTest(self.data["skip_msg"])
+
         db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
                                                  self.server_id, self.db_id)
         if not db_con['data']["connected"]:
@@ -57,15 +71,17 @@ class TypesAddTestCase(BaseTestGenerator):
 
     def runTest(self):
         """ This function will add type under schema node. """
+        if "name" in self.data:
+            self.data["name"] = self.data["name"] + (str(uuid.uuid4())[1:8])
+
         db_user = self.server["username"]
-        self.type_name = "test_type_add_%s" % (str(uuid.uuid4())[1:8])
-        self.data = types_utils.get_types_data(self.type_name,
-                                               self.schema_name, db_user)
+        self.data["typeowner"] = db_user
+        self.data["schema"] = self.schema_name
+
         if self.is_positive_test:
             response = self.create_types()
         else:
             if hasattr(self, "missing_parameter"):
-                del self.data['name']
                 response = self.create_types()
 
             if hasattr(self, "internal_server_error"):
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/types_test_data.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/types_test_data.json
index 58937e88c..220df84a4 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/types_test_data.json
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/tests/types_test_data.json
@@ -3,8 +3,68 @@
     {
       "name": "Create types: With valid data.",
       "url": "/browser/type/obj/",
+      "server_min_version": "10000",
+      "skip_msg": "Nested Table types are supported for PPAS & version > 9.6",
       "is_positive_test": true,
-      "test_data": {},
+      "test_data": {
+        "name": "type_name_add",
+            "is_sys_type": false,
+            "typtype": "c",
+            "typeowner": "db_user",
+            "schema": "schema_name",
+            "composite": [{"member_name": "one", "type": "bigint",
+                           "is_tlength": false, "is_precision": false},
+                          {"member_name": "two", "type": "\"char\"[]",
+                           "is_tlength": false, "is_precision": false}],
+            "enum": [], "typacl": [], "seclabels": []
+      },
+      "mocking_required": false,
+      "mock_data": {},
+      "expected_data": {
+        "status_code": 200
+      }
+    },
+    {
+      "name": "Create Nested types: With valid data for Advanced Server.",
+      "url": "/browser/type/obj/",
+      "is_positive_test": true,
+      "test_data": {
+        "name": "type_name_add",
+            "is_sys_type": false,
+            "typeowner": "db_user",
+            "schema": "schema_name",
+             "typtype":"N",
+        "type": "numeric",
+        "tlength": 2,
+        "precision": 1,
+        "typacl":[],
+        "seclabels":[],
+        "server_min_version": 10000,
+      "skip_msg": "Nested Table types are supported for PPAS & version > 9.6"
+      },
+      "mocking_required": false,
+      "mock_data": {},
+      "expected_data": {
+        "status_code": 200
+      }
+    },
+        {
+      "name": "Create Varray types: With valid data for Advanced Server.",
+      "url": "/browser/type/obj/",
+      "is_positive_test": true,
+      "test_data": {
+        "name": "type_name_add",
+            "is_sys_type": false,
+            "typeowner": "db_user",
+            "schema": "schema_name",
+             "typtype":"V",
+        "type": "integer",
+        "maxsize": 10,
+        "typacl":[],
+        "seclabels":[],
+        "server_min_version": 10000,
+      "skip_msg": "Varray types are supported for PPAS & version > 9.6"
+      },
       "mocking_required": false,
       "mock_data": {},
       "expected_data": {
@@ -16,7 +76,17 @@
       "url": "/browser/type/obj/",
       "is_positive_test": false,
       "missing_parameter": true,
-      "test_data": {},
+      "test_data": {
+            "is_sys_type": false,
+            "typtype": "c",
+            "typeowner": "db_user",
+            "schema": "schema_name",
+            "composite": [{"member_name": "one", "type": "bigint",
+                           "is_tlength": false, "is_precision": false},
+                          {"member_name": "two", "type": "\"char\"[]",
+                           "is_tlength": false, "is_precision": false}],
+            "enum": [], "typacl": [], "seclabels": []
+      },
       "mocking_required": false,
       "mock_data": {},
       "expected_data": {
@@ -28,7 +98,18 @@
       "url": "/browser/type/obj/",
       "is_positive_test": false,
       "internal_server_error": true,
-      "test_data": {},
+      "test_data": {
+         "name": "type_name_add",
+            "is_sys_type": false,
+            "typtype": "c",
+            "typeowner": "db_user",
+            "schema": "schema_name",
+            "composite": [{"member_name": "one", "type": "bigint",
+                           "is_tlength": false, "is_precision": false},
+                          {"member_name": "two", "type": "\"char\"[]",
+                           "is_tlength": false, "is_precision": false}],
+            "enum": [], "typacl": [], "seclabels": []
+      },
       "mocking_required": true,
       "mock_data": {
         "function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
@@ -43,7 +124,18 @@
       "url": "/browser/type/obj/",
       "is_positive_test": false,
       "error_in_db": true,
-      "test_data": {},
+      "test_data": {
+         "name": "type_name_add",
+            "is_sys_type": false,
+            "typtype": "c",
+            "typeowner": "db_user",
+            "schema": "schema_name",
+            "composite": [{"member_name": "one", "type": "bigint",
+                           "is_tlength": false, "is_precision": false},
+                          {"member_name": "two", "type": "\"char\"[]",
+                           "is_tlength": false, "is_precision": false}],
+            "enum": [], "typacl": [], "seclabels": []
+      },
       "mocking_required": true,
       "mock_data": {
         "function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",

Reply via email to