Type support
parent
3914f5095a
commit
ca277bc8b6
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 329 B |
Binary file not shown.
After Width: | Height: | Size: 325 B |
|
@ -0,0 +1,863 @@
|
|||
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', 'typeowner', 'description']
|
||||
});
|
||||
};
|
||||
|
||||
// Security label model declaration
|
||||
var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
provider: undefined,
|
||||
security_label: undefined
|
||||
},
|
||||
schema: [{
|
||||
id: 'provider', label: '{{ _('Provider') }}',
|
||||
type: 'text', disabled: false, cellHeaderClasses:'width_percent_50'
|
||||
},{
|
||||
id: 'security_label', label: '{{ _('Security Label') }}',
|
||||
type: 'text', disabled: false, cellHeaderClasses:'width_percent_50'
|
||||
}],
|
||||
validate: function() {
|
||||
var err = {},
|
||||
errmsg = null,
|
||||
data = this.toJSON();
|
||||
|
||||
if (_.isUndefined(this.get('security_label')) ||
|
||||
_.isNull(this.get('security_label')) ||
|
||||
String(this.get('security_label')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
errmsg = '{{ _('Please provide the value for security label.') }}';
|
||||
this.errorModel.set('security_label', errmsg);
|
||||
return errmsg;
|
||||
} else {
|
||||
this.errorModel.unset('security_label');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Composite type model declaration
|
||||
var CompositeModel = Backform.CompositeModel = pgAdmin.Browser.Node.Model.extend({
|
||||
idAttribute: 'attnum',
|
||||
defaults: {
|
||||
attnum: undefined,
|
||||
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;
|
||||
}
|
||||
},{
|
||||
// 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', label: '{{ _('Length/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 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');
|
||||
}
|
||||
},{
|
||||
// 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', label: '{{ _('Scale') }}', 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,
|
||||
changedAttrs = this.sessAttrs;
|
||||
// Clearing previous errors first.
|
||||
this.errorModel.clear();
|
||||
// Validation for member name
|
||||
if ( _.has(changedAttrs, 'member_name') && _.isUndefined(this.get('member_name')) ||
|
||||
_.isNull(this.get('member_name')) ||
|
||||
String(this.get('member_name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
errmsg = '{{ _('Please specify the value for member name.') }}';
|
||||
this.errorModel.set('member_name', errmsg)
|
||||
return errmsg;
|
||||
}
|
||||
// Validation for Length/precision field (see comments above if confused about the naming!)
|
||||
else if (_.has(changedAttrs, 'tlength') && this.get('is_tlength')
|
||||
&& !_.isUndefined(this.get('tlength'))) {
|
||||
if (this.get('tlength') < this.get('min_val'))
|
||||
errmsg = '{{ _('Length/precision should not be less than ') }}' + this.get('min_val');
|
||||
if (this.get('tlength') > this.get('max_val') )
|
||||
errmsg = '{{ _('Length/precision should not be greater than ') }}' + this.get('max_val');
|
||||
// If we have any error set then throw it to user
|
||||
if(errmsg) {
|
||||
this.errorModel.set('tlength', errmsg)
|
||||
return errmsg;
|
||||
}
|
||||
}
|
||||
// Validation for scale field (see comments above if confused about the naming!)
|
||||
else if (_.has(changedAttrs, 'precision') && this.get('is_precision')
|
||||
&& !_.isUndefined(this.get('precision'))) {
|
||||
if (this.get('precision') < this.get('min_val'))
|
||||
errmsg = '{{ _('Scale should not be less than ') }}' + this.get('min_val');
|
||||
if (this.get('precision') > this.get('max_val'))
|
||||
errmsg = '{{ _('Scale should not be greater than ') }}' + this.get('max_val');
|
||||
// If we have any error set then throw it to user
|
||||
if(errmsg) {
|
||||
this.errorModel.set('precision', errmsg)
|
||||
return errmsg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
var EnumModel = Backform.EnumModel = pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
label: undefined,
|
||||
},
|
||||
schema: [{
|
||||
id: 'label', label: '{{ _('Label') }}',type: 'text', disabled: false,
|
||||
cellHeaderClasses: 'width_percent_99', editable: function(m) {
|
||||
return _.isUndefined(m.get('label'));
|
||||
}
|
||||
}],
|
||||
validate: function() {
|
||||
var err = {},
|
||||
errmsg = null;
|
||||
|
||||
if (_.isUndefined(this.get('label') ||
|
||||
_.isNull(this.get('label')) ||
|
||||
String(this.get('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 multiple 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
|
||||
},
|
||||
|
||||
// Default values!
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
|
||||
if (isNew) {
|
||||
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
|
||||
var schemaInfo = args.node_info.schema;
|
||||
|
||||
this.set({'typeowner': userInfo.name}, {silent: true});
|
||||
this.set({'schema': schemaInfo.label}, {silent: true});
|
||||
}
|
||||
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
|
||||
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'], 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: '{{ _('Definition') }}',
|
||||
mode: ['edit', 'create'],
|
||||
select2: { width: "50%" },
|
||||
options: function() {
|
||||
if(!this.model.isNew()) {
|
||||
return [
|
||||
{label: "Composite", value: "c"},
|
||||
{label: "Enumeration", value: "e"},
|
||||
{label: "External", value: "b"},
|
||||
{label: "Range", value: "r"},
|
||||
]
|
||||
} else {
|
||||
return [
|
||||
{label: "Composite", value: "c"},
|
||||
{label: "Enumeration", value: "e"},
|
||||
{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: '{{ _('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: '{{ _('Enumeration Type') }}',
|
||||
model: EnumModel, editable: true, type: 'collection',
|
||||
group: '{{ _('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: 'plain-fieldset', group: '{{ _('Definition') }}',
|
||||
mode: ['edit', 'create'],
|
||||
visible: function(m) {
|
||||
return m.get('typtype') === 'r';
|
||||
}, deps: ['typtype'], label: '{{ _('') }}',
|
||||
schema:[{
|
||||
id: 'typname', label:'{{ _('Sub-type') }}', cell: 'string',
|
||||
control: 'node-ajax-options',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" },
|
||||
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:'{{ _('Sub-type operator class') }}', 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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" },
|
||||
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 function') }}', 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:'{{ _('Sub-type diff function') }}', 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: '{{ _('Definition') }}',
|
||||
label: '{{ _('External Type') }}', deps: ['typtype'],
|
||||
mode: ['edit'],
|
||||
visible: function(m) {
|
||||
return m.get('typtype') === 'b';
|
||||
},
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" }
|
||||
},{
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" }
|
||||
},{
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" }
|
||||
},{
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" }
|
||||
},{
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" },
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" },
|
||||
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'],
|
||||
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',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" }
|
||||
},{
|
||||
id: 'typcategory', label:'{{ _('Category type') }}',
|
||||
cell: 'string', group: 'Optional-1',
|
||||
type: 'text', mode: ['properties', 'create','edit'],
|
||||
disabled: 'inSchemaWithModelCheck', control: 'select2',
|
||||
select2: { allowClear: true, placeholder: "", 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:'{{ _('Preferred?') }}', cell: 'switch',
|
||||
type: 'switch', mode: ['properties', 'create','edit'],
|
||||
disabled: 'inSchemaWithModelCheck',
|
||||
group: 'Optional-1'
|
||||
},{
|
||||
id: 'element', label:'{{ _('Element type') }}', 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 type') }}',
|
||||
cell: 'string', group: 'Optional-2',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
disabled: 'inSchemaWithModelCheck', control: 'select2',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" },
|
||||
options: [
|
||||
{label :"", value : ""},
|
||||
{label: "char", value: "c"},
|
||||
{label: "int2", value: "s"},
|
||||
{label: "int4", value: "i"},
|
||||
{label: "double", value: "d"},
|
||||
]
|
||||
},{
|
||||
id: 'typstorage', label:'{{ _('Storage type') }}',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
group: 'Optional-2', cell: 'string',
|
||||
disabled: 'inSchemaWithModelCheck', control: 'select2',
|
||||
select2: { allowClear: true, placeholder: "", width: "100%" },
|
||||
options: [
|
||||
{label :"", value : ""},
|
||||
{label: "PLAIN", value: "p"},
|
||||
{label: "EXTERNAL", value: "e"},
|
||||
{label: "MAIN", value: "m"},
|
||||
{label: "EXTENDED", value: "x"},
|
||||
]
|
||||
},{
|
||||
id: 'typbyval', label:'{{ _('Passed by value?') }}',
|
||||
cell: 'switch',
|
||||
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'],
|
||||
disabled: 'inSchemaWithModelCheck'
|
||||
// End of extension tab
|
||||
}]
|
||||
},{
|
||||
id: 'alias', label:'{{ _('Alias') }}', cell: 'string',
|
||||
type: 'text', mode: ['properties'],
|
||||
disabled: 'inSchema'
|
||||
},{
|
||||
id: 'type_acl', label:'{{ _('Privileges') }}', cell: 'string',
|
||||
type: 'text', mode: ['properties'], group: '{{ _('Security') }}',
|
||||
disabled: 'inSchema'
|
||||
},{
|
||||
id: 'member_list', label:'{{ _('Members') }}', cell: 'string',
|
||||
type: 'text', mode: ['properties'], group: '{{ _('Definition') }}',
|
||||
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'], group: '{{ _('Definition') }}',
|
||||
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'],
|
||||
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']
|
||||
},{
|
||||
id: 'seclabels', label: '{{ _('Security Labels') }}',
|
||||
model: SecurityModel, editable: false, type: 'collection',
|
||||
group: '{{ _('Security') }}', mode: ['edit', 'create'],
|
||||
min_version: 90100, canAdd: true,
|
||||
canEdit: false, canDelete: true, control: 'unique-col-collection'
|
||||
}],
|
||||
validate: function() {
|
||||
// Validation code for required fields
|
||||
var changedAttrs = this.sessAttrs,
|
||||
msg = undefined;
|
||||
|
||||
this.errorModel.clear();
|
||||
|
||||
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);
|
||||
}
|
||||
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'];
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
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
|
|
@ -0,0 +1,35 @@
|
|||
{# The SQL given below will fetch composite type#}
|
||||
{% if type == 'c' %}
|
||||
SELECT attnum, 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,
|
||||
collname, nspc.nspname as collnspname, 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
|
||||
LEFT OUTER JOIN pg_collation c ON att.attcollation=c.oid
|
||||
LEFT OUTER JOIN 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 type == 'e' %}
|
||||
SELECT enumlabel
|
||||
FROM pg_enum
|
||||
WHERE enumtypid={{tid}}::oid
|
||||
ORDER by enumsortorder
|
||||
{% 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 %}
|
|
@ -0,0 +1,79 @@
|
|||
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||
{% import 'macros/schemas/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 == '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 %}
|
||||
{### 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.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.security_label %}
|
||||
{{ SECLABLE.SET(conn, 'TYPE', data.name, r.provider, r.security_label, data.schema) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
|
@ -0,0 +1 @@
|
|||
DROP TYPE {{ conn|qtIdent(data.schema, data.name) }}{% if cascade%} CASCADE{% endif %};
|
|
@ -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;
|
|
@ -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 IS NULL;
|
||||
{% 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 %}
|
|
@ -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;
|
|
@ -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 %}
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
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
|
||||
{% if not show_system_objects %}
|
||||
AND ct.oid is NULL
|
||||
{% endif %}
|
||||
ORDER BY t.typname;
|
|
@ -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.*, 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 %}
|
||||
{% if not show_system_objects %}
|
||||
AND ct.oid is NULL
|
||||
{% endif %}
|
||||
ORDER BY t.typname;
|
|
@ -0,0 +1,139 @@
|
|||
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||
{% import 'macros/schemas/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|qtTypeIdent(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 %}
|
||||
{% for o in o_data.composite %}
|
||||
{% if o.attnum == r.attnum and 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}};
|
||||
{% if r.type and o.type != r.type %}
|
||||
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
|
||||
ALTER ATTRIBUTE {{conn|qtIdent(r.member_name)}} SET DATA TYPE {{conn|qtTypeIdent(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 %};
|
||||
{% else %}
|
||||
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
|
||||
ALTER ATTRIBUTE {{conn|qtIdent(r.member_name)}} SET DATA TYPE {{conn|qtTypeIdent(o.type)}}{% if o.is_tlength and o.tlength %}
|
||||
({{o.tlength}}{% if o.is_precision and o.precision %},{{o.precision}}{% endif %}){% endif %}{% if o.collation %}
|
||||
COLLATE {{r.collation}}{% endif %};
|
||||
{% 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}} 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 %}
|
||||
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
|
||||
{% for r in seclabels.deleted %}
|
||||
{{ SECLABLE.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 %}
|
||||
{{ SECLABLE.SET(conn, 'TYPE', o_data.name, r.provider, r.security_label, o_data.schema) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
|
||||
{% for r in seclabels.changed %}
|
||||
{{ SECLABLE.SET(conn, 'TYPE', o_data.name, r.provider, r.security_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 %}
|
||||
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
|
||||
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, 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, 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 != 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 %}
|
|
@ -0,0 +1,53 @@
|
|||
"""
|
||||
Here is the list of Postgres inbuilt types & their OID's
|
||||
We will use these types 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
|
||||
"""
|
Loading…
Reference in New Issue