Add support for generated columns in Postgres 12+. Fixes #4334
Ensure columns can be created when they are IDENTITY fields with the CYCLE option enabled. Fixes #4496 Ensure purely numeric comments can be saved on new columns. Fixed #4497
@ -39,9 +39,69 @@ are disabled if inapplicable.)
|
|||||||
a text value.
|
a text value.
|
||||||
* Use the drop-down listbox next to *Collation* to apply a collation setting to
|
* Use the drop-down listbox next to *Collation* to apply a collation setting to
|
||||||
the column.
|
the column.
|
||||||
|
|
||||||
|
Click the *Constraints* tab to continue.
|
||||||
|
|
||||||
|
.. image:: images/column_constraints.png
|
||||||
|
:alt: Column dialog constraints tab
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Use the fields in the *Constraints* tab to specify constraints for the column.
|
||||||
|
(Fields are disabled if inapplicable.)
|
||||||
|
|
||||||
* Use the *Default Value* field to specify a default data value.
|
* Use the *Default Value* field to specify a default data value.
|
||||||
* Move the *Not Null* switch to the *Yes* position to specify the column may not
|
* Move the *Not Null* switch to the *Yes* position to specify the column may not
|
||||||
contain null values. The default is *No*.
|
contain null values. The default is *No*.
|
||||||
|
* Use the *Type* field to specify the column type (NONE/IDENTITY/GENERATED).
|
||||||
|
The default is *NONE*.
|
||||||
|
|
||||||
|
Click the *IDENTITY* type to create Identity column.
|
||||||
|
|
||||||
|
.. image:: images/column_constraint_identity.png
|
||||||
|
:alt: Column dialog constraints tab
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Use the following fields to create *IDENTITY* column. Identity columns are
|
||||||
|
applicable for PG/EPAS version 10 and above.
|
||||||
|
|
||||||
|
* Use the *Identity* field to specify ALWAYS or BY DEFAULT. This clause is
|
||||||
|
used to determine how the sequence value is given precedence over a
|
||||||
|
user-specified value in an INSERT statement.
|
||||||
|
* Use the *Increment* field to specify which value is added to the current
|
||||||
|
sequence value to create a new value.
|
||||||
|
* Provide a value in the *Start* field to specify the beginning value of the
|
||||||
|
sequence. The default starting value is MINVALUE for ascending sequences and
|
||||||
|
MAXVALUE for descending ones.
|
||||||
|
* Provide a value in the *Minimum* field to specify the minimum value a sequence
|
||||||
|
can generate. If this clause is not supplied or NO MINVALUE is specified,
|
||||||
|
then defaults will be used. The defaults are 1 and -263-1 for ascending and
|
||||||
|
descending sequences, respectively.
|
||||||
|
* Provide a value in the *Maximum* field to specify the maximum value for the
|
||||||
|
sequence. If this clause is not supplied or NO MAXVALUE is specified, then
|
||||||
|
default values will be used. The defaults are 263-1 and -1 for ascending and
|
||||||
|
descending sequences, respectively.
|
||||||
|
* Provide a value in the *Cache* field to specify how many sequence numbers are
|
||||||
|
to be preallocated and stored in memory for faster access. The minimum value
|
||||||
|
is 1 (only one value can be generated at a time, i.e., no cache), and this is
|
||||||
|
also the default.
|
||||||
|
* Move the *Cycled* switch to the *Yes* position to allow the sequence to wrap
|
||||||
|
around when the MAXVALUE or the MINVALUE has been reached by an ascending or
|
||||||
|
descending sequence respectively. If the limit is reached, the next number
|
||||||
|
generated will be the MINVALUE or MAXVALUE, respectively. The default is *No*.
|
||||||
|
|
||||||
|
Click the *GENERATED* type to create Generated column.
|
||||||
|
|
||||||
|
.. image:: images/column_constraint_generated.png
|
||||||
|
:alt: Column dialog constraints tab
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Use the following fields to create *GENERATED* column. Generated columns are
|
||||||
|
applicable for PG/EPAS version 12 and above.
|
||||||
|
|
||||||
|
* Use the *Expression* field to specify the generation expression. It can
|
||||||
|
refer to other columns in the table, but not other generated columns.
|
||||||
|
Any functions and operators used must be immutable. References to other
|
||||||
|
tables are not allowed.
|
||||||
|
|
||||||
Click the *Variables* tab to continue.
|
Click the *Variables* tab to continue.
|
||||||
|
|
||||||
|
BIN
docs/en_US/images/column_constraint_generated.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
docs/en_US/images/column_constraint_identity.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
docs/en_US/images/column_constraints.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
docs/en_US/images/column_definition.png
Executable file → Normal file
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 43 KiB |
BIN
docs/en_US/images/column_general.png
Executable file → Normal file
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 37 KiB |
BIN
docs/en_US/images/column_security.png
Executable file → Normal file
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 42 KiB |
BIN
docs/en_US/images/column_variables.png
Executable file → Normal file
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 40 KiB |
@ -10,6 +10,7 @@ New features
|
|||||||
************
|
************
|
||||||
|
|
||||||
| `Issue #4333 <https://redmine.postgresql.org/issues/4333>`_ - Add support for planner support functions in PostgreSQL 12+ functions.
|
| `Issue #4333 <https://redmine.postgresql.org/issues/4333>`_ - Add support for planner support functions in PostgreSQL 12+ functions.
|
||||||
|
| `Issue #4334 <https://redmine.postgresql.org/issues/4334>`_ - Add support for generated columns in Postgres 12+.
|
||||||
|
|
||||||
Housekeeping
|
Housekeeping
|
||||||
************
|
************
|
||||||
@ -20,4 +21,6 @@ Bug fixes
|
|||||||
|
|
||||||
| `Issue #4179 <https://redmine.postgresql.org/issues/4179>`_ - Fix generation of reverse engineered SQL for tables with Greenplum 5.x.
|
| `Issue #4179 <https://redmine.postgresql.org/issues/4179>`_ - Fix generation of reverse engineered SQL for tables with Greenplum 5.x.
|
||||||
| `Issue #4490 <https://redmine.postgresql.org/issues/4490>`_ - Fix accessibility issue for checkbox in IE11.
|
| `Issue #4490 <https://redmine.postgresql.org/issues/4490>`_ - Fix accessibility issue for checkbox in IE11.
|
||||||
|
| `Issue #4496 <https://redmine.postgresql.org/issues/4496>`_ - Ensure columns can be created when they are IDENTITY fields with the CYCLE option enabled.
|
||||||
|
| `Issue #4497 <https://redmine.postgresql.org/issues/4497>`_ - Ensure purely numeric comments can be saved on new columns.
|
||||||
| `Issue #4508 <https://redmine.postgresql.org/issues/4508>`_ - Fix accessibility issue for Datetime cell in backgrid.
|
| `Issue #4508 <https://redmine.postgresql.org/issues/4508>`_ - Fix accessibility issue for Datetime cell in backgrid.
|
||||||
|
@ -547,7 +547,13 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
|||||||
)
|
)
|
||||||
|
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
data[k] = json.loads(v, encoding='utf-8', cls=ColParamsJSONDecoder)
|
# comments should be taken as is because if user enters a
|
||||||
|
# json comment it is parsed by loads which should not happen
|
||||||
|
if k in ('description',):
|
||||||
|
data[k] = v
|
||||||
|
else:
|
||||||
|
data[k] = json.loads(v, encoding='utf-8',
|
||||||
|
cls=ColParamsJSONDecoder)
|
||||||
|
|
||||||
required_args = {
|
required_args = {
|
||||||
'name': 'Name',
|
'name': 'Name',
|
||||||
|
@ -24,7 +24,7 @@ define('pgadmin.node.column', [
|
|||||||
type: 'coll-column',
|
type: 'coll-column',
|
||||||
columns: ['name', 'atttypid', 'description'],
|
columns: ['name', 'atttypid', 'description'],
|
||||||
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||||
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
canDropCascade: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,13 +185,15 @@ define('pgadmin.node.column', [
|
|||||||
attnotnull: false,
|
attnotnull: false,
|
||||||
attlen: null,
|
attlen: null,
|
||||||
attprecision: null,
|
attprecision: null,
|
||||||
attidentity: undefined,
|
attidentity: 'a',
|
||||||
seqincrement: undefined,
|
seqincrement: undefined,
|
||||||
seqstart: undefined,
|
seqstart: undefined,
|
||||||
seqmin: undefined,
|
seqmin: undefined,
|
||||||
seqmax: undefined,
|
seqmax: undefined,
|
||||||
seqcache: undefined,
|
seqcache: undefined,
|
||||||
seqcycle: undefined,
|
seqcycle: undefined,
|
||||||
|
colconstype: 'n',
|
||||||
|
genexpr: undefined,
|
||||||
},
|
},
|
||||||
initialize: function(attrs) {
|
initialize: function(attrs) {
|
||||||
if (_.size(attrs) !== 0) {
|
if (_.size(attrs) !== 0) {
|
||||||
@ -479,67 +481,6 @@ define('pgadmin.node.column', [
|
|||||||
}
|
}
|
||||||
return flag;
|
return flag;
|
||||||
},
|
},
|
||||||
},{
|
|
||||||
id: 'defval', label: gettext('Default'), cell: 'string',
|
|
||||||
type: 'text', group: gettext('Definition'), deps: ['cltype'],
|
|
||||||
disabled: function(m) {
|
|
||||||
if(!m.inSchemaWithModelCheck.apply(this, [m])) {
|
|
||||||
var type = m.get('cltype');
|
|
||||||
return type == 'serial' || type == 'bigserial'
|
|
||||||
|| type == 'smallserial';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},{
|
|
||||||
id: 'attnotnull', label: gettext('Not NULL?'), cell: 'switch',
|
|
||||||
type: 'switch', disabled: 'inSchemaWithColumnCheck', cellHeaderClasses:'width_percent_20',
|
|
||||||
group: gettext('Definition'), editable: 'editable_check_for_table',
|
|
||||||
options: { onText: gettext('Yes'), offText: gettext('No'), onColor: 'success', offColor: 'primary' },
|
|
||||||
},{
|
|
||||||
type: 'nested', control: 'fieldset', label: gettext('Identity'),
|
|
||||||
group: gettext('Definition'),
|
|
||||||
schema:[{
|
|
||||||
id: 'attidentity', label: gettext('Identity'), control: 'select2',
|
|
||||||
cell: 'select2', select2: { placeholder: 'Select identity',
|
|
||||||
allowClear: true,
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
min_version: 100000, group: gettext('Identity'),
|
|
||||||
'options': [
|
|
||||||
{label: gettext('ALWAYS'), value: 'a'},
|
|
||||||
{label: gettext('BY DEFAULT'), value: 'd'},
|
|
||||||
],
|
|
||||||
},{
|
|
||||||
id: 'seqincrement', label: gettext('Increment'), type: 'int',
|
|
||||||
mode: ['properties', 'create', 'edit'], group: gettext('Identity'),
|
|
||||||
min: 1, deps: ['attidentity'], disabled: 'isIdentityColumn',
|
|
||||||
},{
|
|
||||||
id: 'seqstart', label: gettext('Start'), type: 'int',
|
|
||||||
mode: ['properties', 'create'], group: gettext('Identity'),
|
|
||||||
disabled: function(m) {
|
|
||||||
if (!m.isNew())
|
|
||||||
return true;
|
|
||||||
let isIdentity = m.get('attidentity');
|
|
||||||
if(!_.isUndefined(isIdentity) && !_.isNull(isIdentity) && !_.isEmpty(isIdentity))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}, deps: ['attidentity'],
|
|
||||||
},{
|
|
||||||
id: 'seqmin', label: gettext('Minimum'), type: 'int',
|
|
||||||
mode: ['properties', 'create', 'edit'], group: gettext('Identity'),
|
|
||||||
deps: ['attidentity'], disabled: 'isIdentityColumn',
|
|
||||||
},{
|
|
||||||
id: 'seqmax', label: gettext('Maximum'), type: 'int',
|
|
||||||
mode: ['properties', 'create', 'edit'], group: gettext('Identity'),
|
|
||||||
deps: ['attidentity'], disabled: 'isIdentityColumn',
|
|
||||||
},{
|
|
||||||
id: 'seqcache', label: gettext('Cache'), type: 'int',
|
|
||||||
mode: ['properties', 'create', 'edit'], group: gettext('Identity'),
|
|
||||||
min: 1, deps: ['attidentity'], disabled: 'isIdentityColumn',
|
|
||||||
},{
|
|
||||||
id: 'seqcycle', label: gettext('Cycled'), type: 'switch',
|
|
||||||
mode: ['properties', 'create', 'edit'], group: gettext('Identity'),
|
|
||||||
deps: ['attidentity'], disabled: 'isIdentityColumn',
|
|
||||||
}],
|
|
||||||
},{
|
},{
|
||||||
id: 'attstattarget', label: gettext('Statistics'), cell: 'string',
|
id: 'attstattarget', label: gettext('Statistics'), cell: 'string',
|
||||||
type: 'text', disabled: 'inSchemaWithColumnCheck', mode: ['properties', 'edit'],
|
type: 'text', disabled: 'inSchemaWithColumnCheck', mode: ['properties', 'edit'],
|
||||||
@ -558,6 +499,149 @@ define('pgadmin.node.column', [
|
|||||||
{label: 'EXTERNAL', value: 'e'},
|
{label: 'EXTERNAL', value: 'e'},
|
||||||
{label: 'EXTENDED', value: 'x'},
|
{label: 'EXTENDED', value: 'x'},
|
||||||
],
|
],
|
||||||
|
},{
|
||||||
|
id: 'defval', label: gettext('Default'), cell: 'string',
|
||||||
|
type: 'text', group: gettext('Constraints'), deps: ['cltype', 'colconstype'],
|
||||||
|
disabled: function(m) {
|
||||||
|
var is_disabled = false;
|
||||||
|
if(!m.inSchemaWithModelCheck.apply(this, [m])) {
|
||||||
|
var type = m.get('cltype');
|
||||||
|
is_disabled = (type == 'serial' || type == 'bigserial' || type == 'smallserial');
|
||||||
|
}
|
||||||
|
|
||||||
|
is_disabled = is_disabled || m.get('colconstype') != 'n';
|
||||||
|
if (is_disabled && m.isNew()) {
|
||||||
|
setTimeout(function () {
|
||||||
|
m.set('defval', undefined);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_disabled;
|
||||||
|
},
|
||||||
|
},{
|
||||||
|
id: 'attnotnull', label: gettext('Not NULL?'), cell: 'switch',
|
||||||
|
type: 'switch', cellHeaderClasses:'width_percent_20',
|
||||||
|
group: gettext('Constraints'), editable: 'editable_check_for_table',
|
||||||
|
options: { onText: gettext('Yes'), offText: gettext('No'), onColor: 'success', offColor: 'primary' },
|
||||||
|
deps: ['colconstype'],
|
||||||
|
disabled: function(m) {
|
||||||
|
if (m.get('colconstype') == 'i') {
|
||||||
|
setTimeout(function () {
|
||||||
|
m.set('attnotnull', true);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
return m.inSchemaWithColumnCheck(m);
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'colconstype',
|
||||||
|
label: gettext('Type'),
|
||||||
|
cell: 'string',
|
||||||
|
type: 'radioModern',
|
||||||
|
controlsClassName: 'pgadmin-controls col-12 col-sm-9',
|
||||||
|
controlLabelClassName: 'control-label col-sm-3 col-12',
|
||||||
|
group: gettext('Constraints'),
|
||||||
|
options: function(m) {
|
||||||
|
var opt_array = [
|
||||||
|
{'label': gettext('NONE'), 'value': 'n'},
|
||||||
|
{'label': gettext('IDENTITY'), 'value': 'i'},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (m.top.node_info && m.top.node_info.server &&
|
||||||
|
m.top.node_info.server.version >= 120000) {
|
||||||
|
// You can't change the existing column to Generated column.
|
||||||
|
if (m.isNew()) {
|
||||||
|
opt_array.push({
|
||||||
|
'label': gettext('GENERATED'),
|
||||||
|
'value': 'g',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
opt_array.push({
|
||||||
|
'label': gettext('GENERATED'),
|
||||||
|
'value': 'g',
|
||||||
|
'disabled': true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return opt_array;
|
||||||
|
},
|
||||||
|
disabled: function(m) {
|
||||||
|
if (!m.isNew() && m.get('colconstype') == 'g') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
visible: function(m) {
|
||||||
|
if (m.top.node_info && m.top.node_info.server &&
|
||||||
|
m.top.node_info.server.version >= 100000) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'attidentity', label: gettext('Identity'), control: 'select2',
|
||||||
|
cell: 'select2',
|
||||||
|
select2: {placeholder: 'Select identity', allowClear: false, width: '100%'},
|
||||||
|
min_version: 100000, group: gettext('Constraints'),
|
||||||
|
'options': [
|
||||||
|
{label: gettext('ALWAYS'), value: 'a'},
|
||||||
|
{label: gettext('BY DEFAULT'), value: 'd'},
|
||||||
|
],
|
||||||
|
deps: ['colconstype'], visible: 'isTypeIdentity',
|
||||||
|
disabled: function(m) {
|
||||||
|
if (!m.isNew()) {
|
||||||
|
if (m.get('attidentity') == '' && m.get('colconstype') == 'i') {
|
||||||
|
setTimeout(function () {
|
||||||
|
m.set('attidentity', m.get('old_attidentity'));
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'seqincrement', label: gettext('Increment'), type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
|
||||||
|
min: 1, deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
|
||||||
|
visible: 'isTypeIdentity',
|
||||||
|
},{
|
||||||
|
id: 'seqstart', label: gettext('Start'), type: 'int',
|
||||||
|
mode: ['properties', 'create'], group: gettext('Constraints'),
|
||||||
|
disabled: function(m) {
|
||||||
|
if (!m.isNew())
|
||||||
|
return true;
|
||||||
|
let isIdentity = m.get('attidentity');
|
||||||
|
if(!_.isUndefined(isIdentity) && !_.isNull(isIdentity) && !_.isEmpty(isIdentity))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}, deps: ['attidentity', 'colconstype'],
|
||||||
|
visible: 'isTypeIdentity',
|
||||||
|
},{
|
||||||
|
id: 'seqmin', label: gettext('Minimum'), type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
|
||||||
|
deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
|
||||||
|
visible: 'isTypeIdentity',
|
||||||
|
},{
|
||||||
|
id: 'seqmax', label: gettext('Maximum'), type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
|
||||||
|
deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
|
||||||
|
visible: 'isTypeIdentity',
|
||||||
|
},{
|
||||||
|
id: 'seqcache', label: gettext('Cache'), type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
|
||||||
|
min: 1, deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
|
||||||
|
visible: 'isTypeIdentity',
|
||||||
|
},{
|
||||||
|
id: 'seqcycle', label: gettext('Cycled'), type: 'switch',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
|
||||||
|
deps: ['attidentity', 'colconstype'], disabled: 'isIdentityColumn',
|
||||||
|
visible: 'isTypeIdentity',
|
||||||
|
},{
|
||||||
|
id: 'genexpr', label: gettext('Expression'), type: 'text',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: gettext('Constraints'),
|
||||||
|
min_version: 120000, deps: ['colconstype'], visible: 'isTypeGenerated',
|
||||||
|
disabled: function(m) {
|
||||||
|
return !m.isNew();
|
||||||
|
},
|
||||||
},{
|
},{
|
||||||
id: 'is_pk', label: gettext('Primary key?'),
|
id: 'is_pk', label: gettext('Primary key?'),
|
||||||
type: 'switch', disabled: true, mode: ['properties'],
|
type: 'switch', disabled: true, mode: ['properties'],
|
||||||
@ -665,12 +749,23 @@ define('pgadmin.node.column', [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let genexpr = this.get('genexpr');
|
||||||
|
if (this.get('colconstype') == 'g' &&
|
||||||
|
(_.isUndefined(genexpr) || _.isNull(genexpr) || genexpr == '')) {
|
||||||
|
msg = gettext('Expression value cannot be empty.');
|
||||||
|
this.errorModel.set('genexpr', msg);
|
||||||
|
return msg;
|
||||||
|
} else {
|
||||||
|
this.errorModel.unset('genexpr');
|
||||||
|
}
|
||||||
|
|
||||||
var minimum = this.get('seqmin'),
|
var minimum = this.get('seqmin'),
|
||||||
maximum = this.get('seqmax'),
|
maximum = this.get('seqmax'),
|
||||||
start = this.get('seqstart');
|
start = this.get('seqstart');
|
||||||
|
|
||||||
if (!this.isNew() && (this.get('old_attidentity') == 'a' || this.get('old_attidentity') == 'd') &&
|
if (!this.isNew() && this.get('colconstype') == 'i' &&
|
||||||
(this.get('attidentity') == 'a' || this.get('attidentity') == 'd')) {
|
(this.get('old_attidentity') == 'a' || this.get('old_attidentity') == 'd') &&
|
||||||
|
(this.get('attidentity') == 'a' || this.get('attidentity') == 'd')) {
|
||||||
if (_.isUndefined(this.get('seqincrement'))
|
if (_.isUndefined(this.get('seqincrement'))
|
||||||
|| String(this.get('seqincrement')).replace(/^\s+|\s+$/g, '') == '') {
|
|| String(this.get('seqincrement')).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
msg = gettext('Increment value cannot be empty.');
|
msg = gettext('Increment value cannot be empty.');
|
||||||
@ -745,6 +840,22 @@ define('pgadmin.node.column', [
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
// Check whether the column is a identity column
|
||||||
|
isTypeIdentity: function(m) {
|
||||||
|
let colconstype = m.get('colconstype');
|
||||||
|
if (!_.isUndefined(colconstype) && !_.isNull(colconstype) && colconstype == 'i') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
// Check whether the column is a generated column
|
||||||
|
isTypeGenerated: function(m) {
|
||||||
|
let colconstype = m.get('colconstype');
|
||||||
|
if (!_.isUndefined(colconstype) && !_.isNull(colconstype) && colconstype == 'g') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
// We will check if we are under schema node & in 'create' mode
|
// We will check if we are under schema node & in 'create' mode
|
||||||
notInSchema: function() {
|
notInSchema: function() {
|
||||||
if(this.node_info && 'catalog' in this.node_info)
|
if(this.node_info && 'catalog' in this.node_info)
|
||||||
|
@ -25,31 +25,83 @@ from pgadmin.utils import server_utils as server_utils
|
|||||||
class ColumnAddTestCase(BaseTestGenerator):
|
class ColumnAddTestCase(BaseTestGenerator):
|
||||||
"""This class will add new column under table node."""
|
"""This class will add new column under table node."""
|
||||||
scenarios = [
|
scenarios = [
|
||||||
('Add column', dict(url='/browser/column/obj/')),
|
('Add column', dict(
|
||||||
('Add column with Identity', dict(url='/browser/column/obj/',
|
url='/browser/column/obj/',
|
||||||
server_min_version=100000,
|
data={
|
||||||
identity_opt={
|
'cltype': "\"char\"",
|
||||||
'cltype': 'bigint',
|
'attacl': [],
|
||||||
'attidentity': 'a',
|
'is_primary_key': False,
|
||||||
'seqincrement': 1,
|
'attnotnull': False,
|
||||||
'seqstart': 1,
|
'attlen': None,
|
||||||
'seqmin': 1,
|
'attprecision': None,
|
||||||
'seqmax': 10,
|
'attoptions':[],
|
||||||
'seqcache': 1,
|
'seclabels':[],
|
||||||
'seqcycle': True
|
})),
|
||||||
})),
|
('Add Identity column with Always', dict(
|
||||||
('Add column with Identity', dict(url='/browser/column/obj/',
|
url='/browser/column/obj/',
|
||||||
server_min_version=100000,
|
server_min_version=100000,
|
||||||
identity_opt={
|
skip_msg='Identity column are not supported by EPAS/PG 10.0 '
|
||||||
'cltype': 'bigint',
|
'and below.',
|
||||||
'attidentity': 'd',
|
data={
|
||||||
'seqincrement': 2,
|
'cltype': 'bigint',
|
||||||
'seqstart': 2,
|
'attacl': [],
|
||||||
'seqmin': 2,
|
'is_primary_key': False,
|
||||||
'seqmax': 2000,
|
'attnotnull': True,
|
||||||
'seqcache': 1,
|
'attlen': None,
|
||||||
'seqcycle': True
|
'attprecision': None,
|
||||||
}))
|
'attoptions': [],
|
||||||
|
'seclabels': [],
|
||||||
|
'colconstype': 'i',
|
||||||
|
'attidentity': 'a',
|
||||||
|
'seqincrement': 1,
|
||||||
|
'seqstart': 1,
|
||||||
|
'seqmin': 1,
|
||||||
|
'seqmax': 10,
|
||||||
|
'seqcache': 1,
|
||||||
|
'seqcycle': True
|
||||||
|
})),
|
||||||
|
('Add Identity column with As Default', dict(
|
||||||
|
url='/browser/column/obj/',
|
||||||
|
col_data_type='bigint',
|
||||||
|
server_min_version=100000,
|
||||||
|
skip_msg='Identity column are not supported by EPAS/PG 10.0 '
|
||||||
|
'and below.',
|
||||||
|
data={
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attnotnull': True,
|
||||||
|
'attlen': None,
|
||||||
|
'attprecision': None,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': [],
|
||||||
|
'colconstype': 'i',
|
||||||
|
'attidentity': 'd',
|
||||||
|
'seqincrement': 2,
|
||||||
|
'seqstart': 2,
|
||||||
|
'seqmin': 2,
|
||||||
|
'seqmax': 2000,
|
||||||
|
'seqcache': 1,
|
||||||
|
'seqcycle': True
|
||||||
|
})),
|
||||||
|
('Add Generated column', dict(
|
||||||
|
url='/browser/column/obj/',
|
||||||
|
col_data_type='bigint',
|
||||||
|
server_min_version=120000,
|
||||||
|
skip_msg='Generated column are not supported by EPAS/PG 12.0 '
|
||||||
|
'and below.',
|
||||||
|
data={
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attnotnull': True,
|
||||||
|
'attlen': None,
|
||||||
|
'attprecision': None,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': [],
|
||||||
|
'colconstype': 'g',
|
||||||
|
'genexpr': '100 * 100'
|
||||||
|
})),
|
||||||
]
|
]
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -64,9 +116,7 @@ class ColumnAddTestCase(BaseTestGenerator):
|
|||||||
raise Exception("Could not connect to server to add "
|
raise Exception("Could not connect to server to add "
|
||||||
"a table.")
|
"a table.")
|
||||||
if server_con["data"]["version"] < self.server_min_version:
|
if server_con["data"]["version"] < self.server_min_version:
|
||||||
message = "Identity columns are not supported by " \
|
self.skipTest(self.skip_msg)
|
||||||
"PPAS/PG 10.0 and below."
|
|
||||||
self.skipTest(message)
|
|
||||||
|
|
||||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
self.server_id, self.db_id)
|
self.server_id, self.db_id)
|
||||||
@ -87,26 +137,16 @@ class ColumnAddTestCase(BaseTestGenerator):
|
|||||||
def runTest(self):
|
def runTest(self):
|
||||||
"""This function will add column under table node."""
|
"""This function will add column under table node."""
|
||||||
self.column_name = "test_column_add_%s" % (str(uuid.uuid4())[1:8])
|
self.column_name = "test_column_add_%s" % (str(uuid.uuid4())[1:8])
|
||||||
data = {
|
self.data.update({
|
||||||
"name": self.column_name,
|
'name': self.column_name
|
||||||
"cltype": "\"char\"",
|
})
|
||||||
"attacl": [],
|
|
||||||
"is_primary_key": False,
|
|
||||||
"attnotnull": False,
|
|
||||||
"attlen": None,
|
|
||||||
"attprecision": None,
|
|
||||||
"attoptions": [],
|
|
||||||
"seclabels": []
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasattr(self, 'identity_opt'):
|
|
||||||
data.update(self.identity_opt)
|
|
||||||
# Add table
|
# Add table
|
||||||
response = self.tester.post(
|
response = self.tester.post(
|
||||||
self.url + str(utils.SERVER_GROUP) + '/' +
|
self.url + str(utils.SERVER_GROUP) + '/' +
|
||||||
str(self.server_id) + '/' + str(self.db_id) +
|
str(self.server_id) + '/' + str(self.db_id) +
|
||||||
'/' + str(self.schema_id) + '/' + str(self.table_id) + '/',
|
'/' + str(self.schema_id) + '/' + str(self.table_id) + '/',
|
||||||
data=json.dumps(data),
|
data=json.dumps(self.data),
|
||||||
content_type='html/json')
|
content_type='html/json')
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
|
|
||||||
|
@ -26,32 +26,54 @@ from pgadmin.utils import server_utils as server_utils
|
|||||||
class ColumnPutTestCase(BaseTestGenerator):
|
class ColumnPutTestCase(BaseTestGenerator):
|
||||||
"""This class will update the column under table node."""
|
"""This class will update the column under table node."""
|
||||||
scenarios = [
|
scenarios = [
|
||||||
('Edit column Node URL', dict(url='/browser/column/obj/',
|
('Edit column comments and null constraints', dict(
|
||||||
col_data_type='char')),
|
url='/browser/column/obj/',
|
||||||
('Edit column with Identity', dict(url='/browser/column/obj/',
|
col_data_type='char',
|
||||||
col_data_type='bigint',
|
data={
|
||||||
server_min_version=100000,
|
'attnotnull': True,
|
||||||
identity_opt={
|
'description': "This is test comment for column"
|
||||||
'attidentity': 'a',
|
})),
|
||||||
'seqincrement': 1,
|
('Edit column to Identity column as Always', dict(
|
||||||
'seqstart': 1,
|
url='/browser/column/obj/',
|
||||||
'seqmin': 1,
|
col_data_type='bigint',
|
||||||
'seqmax': 10,
|
server_min_version=100000,
|
||||||
'seqcache': 1,
|
skip_msg='Identity column are not supported by EPAS/PG 10.0 '
|
||||||
'seqcycle': True
|
'and below.',
|
||||||
})),
|
data={
|
||||||
('Edit column with Identity', dict(url='/browser/column/obj/',
|
'attnotnull': True,
|
||||||
server_min_version=100000,
|
'attidentity': 'a',
|
||||||
col_data_type='bigint',
|
'seqincrement': 1,
|
||||||
identity_opt={
|
'seqstart': 1,
|
||||||
'attidentity': 'd',
|
'seqmin': 1,
|
||||||
'seqincrement': 2,
|
'seqmax': 10,
|
||||||
'seqstart': 2,
|
'seqcache': 1,
|
||||||
'seqmin': 2,
|
'seqcycle': True
|
||||||
'seqmax': 2000,
|
})),
|
||||||
'seqcache': 1,
|
('Edit column to Identity column as Default', dict(
|
||||||
'seqcycle': True
|
url='/browser/column/obj/',
|
||||||
}))
|
col_data_type='bigint',
|
||||||
|
server_min_version=100000,
|
||||||
|
skip_msg='Identity column are not supported by EPAS/PG 10.0 '
|
||||||
|
'and below.',
|
||||||
|
data={
|
||||||
|
'attnotnull': True,
|
||||||
|
'attidentity': 'd',
|
||||||
|
'seqincrement': 2,
|
||||||
|
'seqstart': 2,
|
||||||
|
'seqmin': 2,
|
||||||
|
'seqmax': 2000,
|
||||||
|
'seqcache': 1,
|
||||||
|
'seqcycle': True
|
||||||
|
})),
|
||||||
|
('Edit column Drop Identity by changing constraint type to NONE',
|
||||||
|
dict(url='/browser/column/obj/',
|
||||||
|
col_data_type='bigint',
|
||||||
|
server_min_version=100000,
|
||||||
|
create_identity_column=True,
|
||||||
|
skip_msg='Identity column are not supported by EPAS/PG 10.0 '
|
||||||
|
'and below.',
|
||||||
|
data={'colconstype': 'n'})
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -66,9 +88,7 @@ class ColumnPutTestCase(BaseTestGenerator):
|
|||||||
raise Exception("Could not connect to server to add "
|
raise Exception("Could not connect to server to add "
|
||||||
"a table.")
|
"a table.")
|
||||||
if server_con["data"]["version"] < self.server_min_version:
|
if server_con["data"]["version"] < self.server_min_version:
|
||||||
message = "Identity columns are not supported by " \
|
self.skipTest(self.skip_msg)
|
||||||
"PPAS/PG 10.0 and below."
|
|
||||||
self.skipTest(message)
|
|
||||||
|
|
||||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
self.server_id, self.db_id)
|
self.server_id, self.db_id)
|
||||||
@ -86,12 +106,16 @@ class ColumnPutTestCase(BaseTestGenerator):
|
|||||||
self.schema_name,
|
self.schema_name,
|
||||||
self.table_name)
|
self.table_name)
|
||||||
self.column_name = "test_column_put_%s" % (str(uuid.uuid4())[1:8])
|
self.column_name = "test_column_put_%s" % (str(uuid.uuid4())[1:8])
|
||||||
self.column_id = columns_utils.create_column(self.server,
|
|
||||||
self.db_name,
|
if hasattr(self, 'create_identity_column') and \
|
||||||
self.schema_name,
|
self.create_identity_column:
|
||||||
self.table_name,
|
self.column_id = columns_utils.create_identity_column(
|
||||||
self.column_name,
|
self.server, self.db_name, self.schema_name,
|
||||||
self.col_data_type)
|
self.table_name, self.column_name, self.col_data_type)
|
||||||
|
else:
|
||||||
|
self.column_id = columns_utils.create_column(
|
||||||
|
self.server, self.db_name, self.schema_name,
|
||||||
|
self.table_name, self.column_name, self.col_data_type)
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
"""This function will update the column under table node."""
|
"""This function will update the column under table node."""
|
||||||
@ -99,14 +123,11 @@ class ColumnPutTestCase(BaseTestGenerator):
|
|||||||
self.column_name)
|
self.column_name)
|
||||||
if not col_response:
|
if not col_response:
|
||||||
raise Exception("Could not find the column to update.")
|
raise Exception("Could not find the column to update.")
|
||||||
data = {
|
self.data.update({
|
||||||
"attnum": self.column_id,
|
'attnum': self.column_id,
|
||||||
"name": self.column_name,
|
'name': self.column_name,
|
||||||
"attnotnull": True,
|
})
|
||||||
"description": "This is test comment for column"
|
|
||||||
}
|
|
||||||
if hasattr(self, 'identity_opt'):
|
|
||||||
data.update(self.identity_opt)
|
|
||||||
response = self.tester.put(
|
response = self.tester.put(
|
||||||
self.url + str(utils.SERVER_GROUP) + '/' +
|
self.url + str(utils.SERVER_GROUP) + '/' +
|
||||||
str(self.server_id) + '/' +
|
str(self.server_id) + '/' +
|
||||||
@ -114,7 +135,7 @@ class ColumnPutTestCase(BaseTestGenerator):
|
|||||||
str(self.schema_id) + '/' +
|
str(self.schema_id) + '/' +
|
||||||
str(self.table_id) + '/' +
|
str(self.table_id) + '/' +
|
||||||
str(self.column_id),
|
str(self.column_id),
|
||||||
data=json.dumps(data),
|
data=json.dumps(self.data),
|
||||||
follow_redirects=True)
|
follow_redirects=True)
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
|
|
||||||
|
@ -63,6 +63,55 @@ def create_column(server, db_name, schema_name, table_name, col_name,
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create_identity_column(server, db_name, schema_name, table_name,
|
||||||
|
col_name, col_data_type='bigint'):
|
||||||
|
"""
|
||||||
|
This function creates a column under provided table.
|
||||||
|
:param server: server details
|
||||||
|
:type server: dict
|
||||||
|
:param db_name: database name
|
||||||
|
:type db_name: str
|
||||||
|
:param schema_name: schema name
|
||||||
|
:type schema_name: str
|
||||||
|
:param table_name: table name
|
||||||
|
:type table_name: str
|
||||||
|
:param col_name: column name
|
||||||
|
:type col_name: str
|
||||||
|
:param col_data_type: column data type
|
||||||
|
:type col_data_type: str
|
||||||
|
:return table_id: table id
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
connection = utils.get_db_connection(db_name,
|
||||||
|
server['username'],
|
||||||
|
server['db_password'],
|
||||||
|
server['host'],
|
||||||
|
server['port'],
|
||||||
|
server['sslmode'])
|
||||||
|
old_isolation_level = connection.isolation_level
|
||||||
|
connection.set_isolation_level(0)
|
||||||
|
pg_cursor = connection.cursor()
|
||||||
|
query = "ALTER TABLE %s.%s ADD COLUMN %s %s " \
|
||||||
|
"GENERATED ALWAYS AS IDENTITY" % \
|
||||||
|
(schema_name, table_name, col_name, col_data_type)
|
||||||
|
pg_cursor.execute(query)
|
||||||
|
connection.set_isolation_level(old_isolation_level)
|
||||||
|
connection.commit()
|
||||||
|
# Get column position of newly added column
|
||||||
|
pg_cursor.execute("select attnum from pg_attribute where"
|
||||||
|
" attname='%s'" % col_name)
|
||||||
|
col = pg_cursor.fetchone()
|
||||||
|
col_pos = ''
|
||||||
|
if col:
|
||||||
|
col_pos = col[0]
|
||||||
|
connection.close()
|
||||||
|
return col_pos
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def verify_column(server, db_name, col_name):
|
def verify_column(server, db_name, col_name):
|
||||||
"""
|
"""
|
||||||
This function verifies table exist in database or not.
|
This function verifies table exist in database or not.
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
|
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
|
||||||
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
|
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
|
||||||
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none %}
|
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none and data.defval != '' %}
|
||||||
DEFAULT {{data.defval}}{% endif %}{% if data.attidentity and data.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif data.attidentity and data.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
DEFAULT {{data.defval}}{% endif %}{% if data.colconstype == 'i' %}{% if data.attidentity and data.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif data.attidentity and data.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
||||||
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %} ( {% endif %}
|
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %} ( {% endif %}
|
||||||
{% if data.seqincrement is defined and data.seqcycle %}
|
{% if data.seqcycle is defined and data.seqcycle %}
|
||||||
CYCLE {% endif %}{% if data.seqincrement is defined and data.seqincrement|int(-1) > -1 %}
|
CYCLE {% endif %}{% if data.seqincrement is defined and data.seqincrement|int(-1) > -1 %}
|
||||||
INCREMENT {{data.seqincrement|int}} {% endif %}{% if data.seqstart is defined and data.seqstart|int(-1) > -1%}
|
INCREMENT {{data.seqincrement|int}} {% endif %}{% if data.seqstart is defined and data.seqstart|int(-1) > -1%}
|
||||||
START {{data.seqstart|int}} {% endif %}{% if data.seqmin is defined and data.seqmin|int(-1) > -1%}
|
START {{data.seqstart|int}} {% endif %}{% if data.seqmin is defined and data.seqmin|int(-1) > -1%}
|
||||||
@ -18,7 +18,7 @@ MINVALUE {{data.seqmin|int}} {% endif %}{% if data.seqmax is defined and data.se
|
|||||||
MAXVALUE {{data.seqmax|int}} {% endif %}{% if data.seqcache is defined and data.seqcache|int(-1) > -1%}
|
MAXVALUE {{data.seqmax|int}} {% endif %}{% if data.seqcache is defined and data.seqcache|int(-1) > -1%}
|
||||||
CACHE {{data.seqcache|int}} {% endif %}
|
CACHE {{data.seqcache|int}} {% endif %}
|
||||||
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %}){% endif %}
|
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %}){% endif %}
|
||||||
{% endif %};
|
{% endif %}{% endif %};
|
||||||
|
|
||||||
{### Add comments ###}
|
{### Add comments ###}
|
||||||
{% if data and data.description %}
|
{% if data and data.description %}
|
||||||
|
@ -19,6 +19,7 @@ SELECT att.attname as name, att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.
|
|||||||
EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk,
|
EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk,
|
||||||
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS seclabels,
|
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS seclabels,
|
||||||
(CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column,
|
(CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column,
|
||||||
|
(CASE WHEN (att.attidentity in ('a', 'd')) THEN 'i' ELSE 'n' END) AS colconstype,
|
||||||
seq.*
|
seq.*
|
||||||
FROM pg_attribute att
|
FROM pg_attribute att
|
||||||
JOIN pg_type ty ON ty.oid=atttypid
|
JOIN pg_type ty ON ty.oid=atttypid
|
||||||
|
@ -33,11 +33,11 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
|||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{### Alter column - add identity ###}
|
{### Alter column - add identity ###}
|
||||||
{% if 'attidentity' in data and o_data.attidentity == '' and data.attidentity != o_data.attidentity %}
|
{% if data.colconstype == 'i' and 'attidentity' in data and o_data.attidentity == '' and data.attidentity != o_data.attidentity %}
|
||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} {% if data.attidentity == 'a' %}ADD GENERATED ALWAYS AS IDENTITY{% else%}ADD GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} {% if data.attidentity == 'a' %}ADD GENERATED ALWAYS AS IDENTITY{% else%}ADD GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
||||||
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %} ( {% endif %}
|
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %} ( {% endif %}
|
||||||
{% if data.seqincrement is defined and data.seqcycle %}
|
{% if data.seqcycle is defined and data.seqcycle %}
|
||||||
CYCLE {% endif %}{% if data.seqincrement is defined and data.seqincrement|int(-1) > -1 %}
|
CYCLE {% endif %}{% if data.seqincrement is defined and data.seqincrement|int(-1) > -1 %}
|
||||||
INCREMENT {{data.seqincrement|int}} {% endif %}{% if data.seqstart is defined and data.seqstart|int(-1) > -1%}
|
INCREMENT {{data.seqincrement|int}} {% endif %}{% if data.seqstart is defined and data.seqstart|int(-1) > -1%}
|
||||||
START {{data.seqstart|int}} {% endif %}{% if data.seqmin is defined and data.seqmin|int(-1) > -1%}
|
START {{data.seqstart|int}} {% endif %}{% if data.seqmin is defined and data.seqmin|int(-1) > -1%}
|
||||||
@ -52,10 +52,8 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
|||||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET GENERATED {% if data.attidentity == 'a' %}ALWAYS{% else%}BY DEFAULT{% endif %};
|
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET GENERATED {% if data.attidentity == 'a' %}ALWAYS{% else%}BY DEFAULT{% endif %};
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{### Alter column - change identity - sequence options ###}
|
{### Alter column - change identity - sequence options ###}
|
||||||
{% if 'attidentity' not in data and (data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache) %}
|
{% if 'attidentity' not in data and (data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache) %}
|
||||||
|
|
||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}} {% else %}{{conn|qtTypeIdent(o_data.name)}} {% endif %}
|
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}} {% else %}{{conn|qtTypeIdent(o_data.name)}} {% endif %}
|
||||||
{% if data.seqcycle %}
|
{% if data.seqcycle %}
|
||||||
@ -65,11 +63,10 @@ SET START {{data.seqstart|int}} {% endif %}{% if data.seqmin is defined and data
|
|||||||
SET MINVALUE {{data.seqmin|int}} {% endif %}{% if data.seqmax is defined and data.seqmax|int(-1) > -1%}
|
SET MINVALUE {{data.seqmin|int}} {% endif %}{% if data.seqmax is defined and data.seqmax|int(-1) > -1%}
|
||||||
SET MAXVALUE {{data.seqmax|int}} {% endif %}{% if data.seqcache is defined and data.seqcache|int(-1) > -1%}
|
SET MAXVALUE {{data.seqmax|int}} {% endif %}{% if data.seqcache is defined and data.seqcache|int(-1) > -1%}
|
||||||
SET CACHE {{data.seqcache|int}} {% endif %};
|
SET CACHE {{data.seqcache|int}} {% endif %};
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{### Alter column - drop identity when column constraint is changed###}
|
||||||
|
{% if 'colconstype' in data and data.colconstype == 'n' and 'colconstype' in o_data and o_data.colconstype == 'i' %}
|
||||||
{### Alter column - drop identity ###}
|
|
||||||
{% if 'attidentity' in data and data.attidentity == '' and o_data.attidentity != '' and data.attidentity != o_data.attidentity %}
|
|
||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} DROP IDENTITY;
|
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} DROP IDENTITY;
|
||||||
|
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
{% import 'columns/macros/security.macros' as SECLABEL %}
|
||||||
|
{% import 'columns/macros/privilege.macros' as PRIVILEGE %}
|
||||||
|
{% import 'macros/variable.macros' as VARIABLE %}
|
||||||
|
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
|
||||||
|
{### Add column ###}
|
||||||
|
{% if data.name and data.cltype %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
|
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
|
||||||
|
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
|
||||||
|
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none and data.defval != '' and data.colconstype != 'g' %}
|
||||||
|
DEFAULT {{data.defval}}{% endif %}{% if data.colconstype == 'i' %}{% if data.attidentity and data.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif data.attidentity and data.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
||||||
|
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %} ( {% endif %}
|
||||||
|
{% if data.seqcycle is defined and data.seqcycle %}
|
||||||
|
CYCLE {% endif %}{% if data.seqincrement is defined and data.seqincrement|int(-1) > -1 %}
|
||||||
|
INCREMENT {{data.seqincrement|int}} {% endif %}{% if data.seqstart is defined and data.seqstart|int(-1) > -1%}
|
||||||
|
START {{data.seqstart|int}} {% endif %}{% if data.seqmin is defined and data.seqmin|int(-1) > -1%}
|
||||||
|
MINVALUE {{data.seqmin|int}} {% endif %}{% if data.seqmax is defined and data.seqmax|int(-1) > -1%}
|
||||||
|
MAXVALUE {{data.seqmax|int}} {% endif %}{% if data.seqcache is defined and data.seqcache|int(-1) > -1%}
|
||||||
|
CACHE {{data.seqcache|int}} {% endif %}
|
||||||
|
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %}){% endif %}
|
||||||
|
{% endif %}{% endif %}{% if data.colconstype == 'g' and data.genexpr and data.genexpr != '' %} GENERATED ALWAYS AS ({{data.genexpr}}) STORED{% endif %};
|
||||||
|
|
||||||
|
{### Add comments ###}
|
||||||
|
{% if data and data.description %}
|
||||||
|
COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
|
||||||
|
IS {{data.description|qtLiteral}};
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{### Add variables to column ###}
|
||||||
|
{% if data.attoptions %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
|
{{ VARIABLE.SET(conn, 'COLUMN', data.name, data.attoptions) }}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{### ACL ###}
|
||||||
|
{% if data.attacl %}
|
||||||
|
{% for priv in data.attacl %}
|
||||||
|
{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{### Security Lables ###}
|
||||||
|
{% if data.seclabels %}
|
||||||
|
{% for r in data.seclabels %}
|
||||||
|
{{ SECLABEL.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
@ -0,0 +1,48 @@
|
|||||||
|
SELECT att.attname as name, att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
|
||||||
|
CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray,
|
||||||
|
format_type(ty.oid,NULL) AS typname,
|
||||||
|
format_type(ty.oid,att.atttypmod) AS displaytypname,
|
||||||
|
CASE WHEN ty.typelem > 0 THEN ty.typelem ELSE ty.oid END as elemoid,
|
||||||
|
tn.nspname as typnspname, et.typname as elemtypname,
|
||||||
|
ty.typstorage AS defaultstorage, cl.relname, na.nspname,
|
||||||
|
concat(quote_ident(na.nspname) ,'.', quote_ident(cl.relname)) AS parent_tbl,
|
||||||
|
att.attstattarget, description, cs.relname AS sername,
|
||||||
|
ns.nspname AS serschema,
|
||||||
|
(SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup,
|
||||||
|
indkey, coll.collname, nspc.nspname as collnspname , attoptions,
|
||||||
|
-- Start pgAdmin4, added to save time on client side parsing
|
||||||
|
CASE WHEN length(coll.collname) > 0 AND length(nspc.nspname) > 0 THEN
|
||||||
|
concat(quote_ident(nspc.nspname),'.',quote_ident(coll.collname))
|
||||||
|
ELSE '' END AS collspcname,
|
||||||
|
format_type(ty.oid,att.atttypmod) AS cltype,
|
||||||
|
-- End pgAdmin4
|
||||||
|
EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk,
|
||||||
|
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS seclabels,
|
||||||
|
(CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column,
|
||||||
|
(CASE WHEN (att.attidentity in ('a', 'd')) THEN 'i' WHEN (att.attgenerated in ('s')) THEN 'g' ELSE 'n' END) AS colconstype,
|
||||||
|
(CASE WHEN (att.attgenerated in ('s')) THEN pg_catalog.pg_get_expr(def.adbin, def.adrelid) END) AS genexpr,
|
||||||
|
seq.*
|
||||||
|
FROM pg_attribute att
|
||||||
|
JOIN pg_type ty ON ty.oid=atttypid
|
||||||
|
JOIN pg_namespace tn ON tn.oid=ty.typnamespace
|
||||||
|
JOIN pg_class cl ON cl.oid=att.attrelid
|
||||||
|
JOIN pg_namespace na ON na.oid=cl.relnamespace
|
||||||
|
LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem
|
||||||
|
LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
|
||||||
|
LEFT OUTER JOIN pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
|
||||||
|
LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON classid='pg_class'::regclass AND objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
|
||||||
|
LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace
|
||||||
|
LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
|
||||||
|
LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid
|
||||||
|
LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
|
||||||
|
LEFT OUTER JOIN pg_sequence seq ON cs.oid=seq.seqrelid
|
||||||
|
WHERE att.attrelid = {{tid}}::oid
|
||||||
|
{% if clid %}
|
||||||
|
AND att.attnum = {{clid}}::int
|
||||||
|
{% endif %}
|
||||||
|
{### To show system objects ###}
|
||||||
|
{% if not show_sys_objects %}
|
||||||
|
AND att.attnum > 0
|
||||||
|
{% endif %}
|
||||||
|
AND att.attisdropped IS FALSE
|
||||||
|
ORDER BY att.attnum;
|
@ -7,7 +7,7 @@
|
|||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||||
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
|
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
|
||||||
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
|
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
|
||||||
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none %}
|
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none and data.defval != '' %}
|
||||||
DEFAULT {{data.defval}}{% endif %};
|
DEFAULT {{data.defval}}{% endif %};
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -42,11 +42,11 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
|
|||||||
{% if data.columns and data.columns|length > 0 %}
|
{% if data.columns and data.columns|length > 0 %}
|
||||||
{% for c in data.columns %}
|
{% for c in data.columns %}
|
||||||
{% if c.name and c.cltype %}
|
{% if c.name and c.cltype %}
|
||||||
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
|
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}
|
||||||
{% if c.attidentity and c.attidentity != '' %}
|
{% if c.colconstype == 'i' and c.attidentity and c.attidentity != '' %}
|
||||||
{% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
{% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
||||||
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %}
|
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %}
|
||||||
{% if c.seqincrement is defined and c.seqcycle %}
|
{% if c.seqcycle is defined and c.seqcycle %}
|
||||||
CYCLE {% endif %}{% if c.seqincrement is defined and c.seqincrement|int(-1) > -1 %}
|
CYCLE {% endif %}{% if c.seqincrement is defined and c.seqincrement|int(-1) > -1 %}
|
||||||
INCREMENT {{c.seqincrement|int}} {% endif %}{% if c.seqstart is defined and c.seqstart|int(-1) > -1%}
|
INCREMENT {{c.seqincrement|int}} {% endif %}{% if c.seqstart is defined and c.seqstart|int(-1) > -1%}
|
||||||
START {{c.seqstart|int}} {% endif %}{% if c.seqmin is defined and c.seqmin|int(-1) > -1%}
|
START {{c.seqstart|int}} {% endif %}{% if c.seqmin is defined and c.seqmin|int(-1) > -1%}
|
||||||
|
@ -46,11 +46,11 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
|
|||||||
{% if data.columns and data.columns|length > 0 %}
|
{% if data.columns and data.columns|length > 0 %}
|
||||||
{% for c in data.columns %}
|
{% for c in data.columns %}
|
||||||
{% if c.name and c.cltype %}
|
{% if c.name and c.cltype %}
|
||||||
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
|
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' and c.colconstype != 'g' %} DEFAULT {{c.defval}}{% endif %}
|
||||||
{% if c.attidentity and c.attidentity != '' %}
|
{% if c.colconstype == 'i' and c.attidentity and c.attidentity != '' %}
|
||||||
{% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
{% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
|
||||||
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %}
|
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %}
|
||||||
{% if c.seqincrement is defined and c.seqcycle %}
|
{% if c.seqcycle is defined and c.seqcycle %}
|
||||||
CYCLE {% endif %}{% if c.seqincrement is defined and c.seqincrement|int(-1) > -1 %}
|
CYCLE {% endif %}{% if c.seqincrement is defined and c.seqincrement|int(-1) > -1 %}
|
||||||
INCREMENT {{c.seqincrement|int}} {% endif %}{% if c.seqstart is defined and c.seqstart|int(-1) > -1%}
|
INCREMENT {{c.seqincrement|int}} {% endif %}{% if c.seqstart is defined and c.seqstart|int(-1) > -1%}
|
||||||
START {{c.seqstart|int}} {% endif %}{% if c.seqmin is defined and c.seqmin|int(-1) > -1%}
|
START {{c.seqstart|int}} {% endif %}{% if c.seqmin is defined and c.seqmin|int(-1) > -1%}
|
||||||
@ -59,6 +59,7 @@ MAXVALUE {{c.seqmax|int}} {% endif %}{% if c.seqcache is defined and c.seqcache|
|
|||||||
CACHE {{c.seqcache|int}} {% endif %}
|
CACHE {{c.seqcache|int}} {% endif %}
|
||||||
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %}){% endif %}
|
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %}){% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if c.colconstype == 'g' and c.genexpr and c.genexpr != '' %} GENERATED ALWAYS AS ({{c.genexpr}}) STORED{% endif %}
|
||||||
{% if not loop.last %},
|
{% if not loop.last %},
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -42,7 +42,7 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
|
|||||||
{% if data.columns and data.columns|length > 0 %}
|
{% if data.columns and data.columns|length > 0 %}
|
||||||
{% for c in data.columns %}
|
{% for c in data.columns %}
|
||||||
{% if c.name and c.cltype %}
|
{% if c.name and c.cltype %}
|
||||||
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
|
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}
|
||||||
{% if not loop.last %},
|
{% if not loop.last %},
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -42,7 +42,7 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
|
|||||||
{% if data.columns and data.columns|length > 0 %}
|
{% if data.columns and data.columns|length > 0 %}
|
||||||
{% for c in data.columns %}
|
{% for c in data.columns %}
|
||||||
{% if c.name and c.cltype %}
|
{% if c.name and c.cltype %}
|
||||||
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
|
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none and c.defval != '' %} DEFAULT {{c.defval}}{% endif %}
|
||||||
{% if not loop.last %},
|
{% if not loop.last %},
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -18,6 +18,7 @@ from pgadmin.utils import server_utils as server_utils
|
|||||||
from pgadmin.utils.route import BaseTestGenerator
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
from regression import parent_node_dict
|
from regression import parent_node_dict
|
||||||
from regression.python_test_utils import test_utils as utils
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
from . import utils as tables_utils
|
||||||
|
|
||||||
|
|
||||||
class TableAddTestCase(BaseTestGenerator):
|
class TableAddTestCase(BaseTestGenerator):
|
||||||
@ -28,7 +29,9 @@ class TableAddTestCase(BaseTestGenerator):
|
|||||||
('Create Range partitioned table with 2 partitions',
|
('Create Range partitioned table with 2 partitions',
|
||||||
dict(url='/browser/table/obj/',
|
dict(url='/browser/table/obj/',
|
||||||
server_min_version=100000,
|
server_min_version=100000,
|
||||||
partition_type='range'
|
partition_type='range',
|
||||||
|
skip_msg='Partitioned table are not supported by '
|
||||||
|
'PPAS/PG 10.0 and below.'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
('Create Range partitioned table with 1 default and 2'
|
('Create Range partitioned table with 1 default and 2'
|
||||||
@ -36,21 +39,104 @@ class TableAddTestCase(BaseTestGenerator):
|
|||||||
dict(url='/browser/table/obj/',
|
dict(url='/browser/table/obj/',
|
||||||
server_min_version=110000,
|
server_min_version=110000,
|
||||||
partition_type='range',
|
partition_type='range',
|
||||||
is_default=True
|
is_default=True,
|
||||||
|
skip_msg='Partitioned table are not supported by '
|
||||||
|
'PPAS/PG 10.0 and below.'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
('Create List partitioned table with 2 partitions',
|
('Create List partitioned table with 2 partitions',
|
||||||
dict(url='/browser/table/obj/',
|
dict(url='/browser/table/obj/',
|
||||||
server_min_version=100000,
|
server_min_version=100000,
|
||||||
partition_type='list'
|
partition_type='list',
|
||||||
|
skip_msg='Partitioned table are not supported by '
|
||||||
|
'PPAS/PG 10.0 and below.'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
('Create Hash partitioned table with 2 partitions',
|
('Create Hash partitioned table with 2 partitions',
|
||||||
dict(url='/browser/table/obj/',
|
dict(url='/browser/table/obj/',
|
||||||
server_min_version=110000,
|
server_min_version=110000,
|
||||||
partition_type='hash'
|
partition_type='hash',
|
||||||
|
skip_msg='Hash Partition are not supported by '
|
||||||
|
'PPAS/PG 11.0 and below.'
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
('Create Table with Identity columns',
|
||||||
|
dict(url='/browser/table/obj/',
|
||||||
|
server_min_version=100000,
|
||||||
|
skip_msg='Identity columns are not supported by '
|
||||||
|
'PPAS/PG 10.0 and below.',
|
||||||
|
columns=[{
|
||||||
|
'name': 'iden_always',
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attnotnull': True,
|
||||||
|
'attlen': None,
|
||||||
|
'attprecision': None,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': [],
|
||||||
|
'colconstype': 'i',
|
||||||
|
'attidentity': 'a',
|
||||||
|
'seqincrement': 1,
|
||||||
|
'seqstart': 1,
|
||||||
|
'seqmin': 1,
|
||||||
|
'seqmax': 10,
|
||||||
|
'seqcache': 1,
|
||||||
|
'seqcycle': True
|
||||||
|
}, {
|
||||||
|
'name': 'iden_default',
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attnotnull': True,
|
||||||
|
'attlen': None,
|
||||||
|
'attprecision': None,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': [],
|
||||||
|
'colconstype': 'i',
|
||||||
|
'attidentity': 'd',
|
||||||
|
'seqincrement': 2,
|
||||||
|
'seqstart': 2,
|
||||||
|
'seqmin': 2,
|
||||||
|
'seqmax': 2000,
|
||||||
|
'seqcache': 1,
|
||||||
|
'seqcycle': True
|
||||||
|
}])
|
||||||
|
),
|
||||||
|
('Create Table with Generated columns',
|
||||||
|
dict(url='/browser/table/obj/',
|
||||||
|
server_min_version=120000,
|
||||||
|
skip_msg='Generated columns are not supported by '
|
||||||
|
'PPAS/PG 12.0 and below.',
|
||||||
|
columns=[{
|
||||||
|
'name': 'm1',
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': []
|
||||||
|
}, {
|
||||||
|
'name': 'm2',
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': []
|
||||||
|
}, {
|
||||||
|
'name': 'genrated',
|
||||||
|
'cltype': 'bigint',
|
||||||
|
'attacl': [],
|
||||||
|
'is_primary_key': False,
|
||||||
|
'attnotnull': True,
|
||||||
|
'attlen': None,
|
||||||
|
'attprecision': None,
|
||||||
|
'attoptions': [],
|
||||||
|
'seclabels': [],
|
||||||
|
'colconstype': 'g',
|
||||||
|
'genexpr': 'm1*m2'
|
||||||
|
}])
|
||||||
)
|
)
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -70,145 +156,48 @@ class TableAddTestCase(BaseTestGenerator):
|
|||||||
if not schema_response:
|
if not schema_response:
|
||||||
raise Exception("Could not find the schema to add a table.")
|
raise Exception("Could not find the schema to add a table.")
|
||||||
|
|
||||||
self.is_partition = False
|
|
||||||
if hasattr(self, 'server_min_version'):
|
if hasattr(self, 'server_min_version'):
|
||||||
server_con = server_utils.connect_server(self, self.server_id)
|
server_con = server_utils.connect_server(self, self.server_id)
|
||||||
if not server_con["info"] == "Server connected.":
|
if not server_con["info"] == "Server connected.":
|
||||||
raise Exception("Could not connect to server to add "
|
raise Exception("Could not connect to server to add "
|
||||||
"partitioned table.")
|
"partitioned table.")
|
||||||
if server_con["data"]["version"] < self.server_min_version:
|
if server_con["data"]["version"] < self.server_min_version:
|
||||||
message = "Partitioned table are not supported by " \
|
self.skipTest(self.skip_msg)
|
||||||
"PPAS/PG 10.0 and below."
|
|
||||||
self.skipTest(message)
|
|
||||||
else:
|
|
||||||
self.is_partition = True
|
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
""" This function will add table under schema node. """
|
""" This function will add table under schema node. """
|
||||||
db_user = self.server["username"]
|
db_user = self.server["username"]
|
||||||
self.table_name = "test_table_add_%s" % (str(uuid.uuid4())[1:8])
|
self.table_name = "test_table_add_%s" % (str(uuid.uuid4())[1:8])
|
||||||
data = {
|
# Get the common data
|
||||||
"check_constraint": [],
|
data = tables_utils.get_table_common_data()
|
||||||
"coll_inherits": "[]",
|
data.update({
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "empno",
|
|
||||||
"cltype": "numeric",
|
|
||||||
"attacl": [],
|
|
||||||
"is_primary_key": False,
|
|
||||||
"attoptions": [],
|
|
||||||
"seclabels": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "empname",
|
|
||||||
"cltype": "character[]",
|
|
||||||
"attacl": [],
|
|
||||||
"is_primary_key": False,
|
|
||||||
"attoptions": [],
|
|
||||||
"seclabels": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "DOJ",
|
|
||||||
"cltype": "date",
|
|
||||||
"attacl": [],
|
|
||||||
"is_primary_key": False,
|
|
||||||
"attoptions": [],
|
|
||||||
"seclabels": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"exclude_constraint": [],
|
|
||||||
"fillfactor": "",
|
|
||||||
"hastoasttable": True,
|
|
||||||
"like_constraints": True,
|
|
||||||
"like_default_value": True,
|
|
||||||
"like_relation": "pg_catalog.pg_namespace",
|
|
||||||
"name": self.table_name,
|
"name": self.table_name,
|
||||||
"primary_key": [],
|
|
||||||
"relacl": [
|
|
||||||
{
|
|
||||||
"grantee": db_user,
|
|
||||||
"grantor": db_user,
|
|
||||||
"privileges":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"privilege_type": "a",
|
|
||||||
"privilege": True,
|
|
||||||
"with_grant": True
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"privilege_type": "r",
|
|
||||||
"privilege": True,
|
|
||||||
"with_grant": False
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"privilege_type": "w",
|
|
||||||
"privilege": True,
|
|
||||||
"with_grant": False
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"relhasoids": True,
|
|
||||||
"relowner": db_user,
|
"relowner": db_user,
|
||||||
"schema": self.schema_name,
|
"schema": self.schema_name,
|
||||||
"seclabels": [],
|
"relacl": [{
|
||||||
"spcname": "pg_default",
|
"grantee": db_user,
|
||||||
"unique_constraint": [],
|
"grantor": db_user,
|
||||||
"vacuum_table": [
|
"privileges": [{
|
||||||
{
|
"privilege_type": "a",
|
||||||
"name": "autovacuum_analyze_scale_factor"
|
"privilege": True,
|
||||||
},
|
"with_grant": True
|
||||||
{
|
}, {
|
||||||
"name": "autovacuum_analyze_threshold"
|
"privilege_type": "r",
|
||||||
},
|
"privilege": True,
|
||||||
{
|
"with_grant": False
|
||||||
"name": "autovacuum_freeze_max_age"
|
}, {
|
||||||
},
|
"privilege_type": "w",
|
||||||
{
|
"privilege": True,
|
||||||
"name": "autovacuum_vacuum_cost_delay"
|
"with_grant": False
|
||||||
},
|
}]
|
||||||
{
|
}]
|
||||||
"name": "autovacuum_vacuum_cost_limit"
|
})
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_vacuum_scale_factor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_vacuum_threshold"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_freeze_min_age"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_freeze_table_age"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"vacuum_toast": [
|
|
||||||
{
|
|
||||||
"name": "autovacuum_freeze_max_age"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_vacuum_cost_delay"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_vacuum_cost_limit"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_vacuum_scale_factor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_vacuum_threshold"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_freeze_min_age"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "autovacuum_freeze_table_age"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.is_partition:
|
# If column is provided in the scenario then use those columns
|
||||||
|
if hasattr(self, 'columns'):
|
||||||
|
data['columns'] = self.columns
|
||||||
|
|
||||||
|
if hasattr(self, 'partition_type'):
|
||||||
data['partition_type'] = self.partition_type
|
data['partition_type'] = self.partition_type
|
||||||
data['is_partitioned'] = True
|
data['is_partitioned'] = True
|
||||||
if self.partition_type == 'range':
|
if self.partition_type == 'range':
|
||||||
|
@ -242,3 +242,81 @@ def set_partition_data(server, db_name, schema_name, table_name,
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_table_common_data():
|
||||||
|
"""
|
||||||
|
This function will return the common data used to create a table
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"check_constraint": [],
|
||||||
|
"coll_inherits": "[]",
|
||||||
|
"columns": [{
|
||||||
|
"name": "empno",
|
||||||
|
"cltype": "numeric",
|
||||||
|
"attacl": [],
|
||||||
|
"is_primary_key": False,
|
||||||
|
"attoptions": [],
|
||||||
|
"seclabels": []
|
||||||
|
}, {
|
||||||
|
"name": "empname",
|
||||||
|
"cltype": "character[]",
|
||||||
|
"attacl": [],
|
||||||
|
"is_primary_key": False,
|
||||||
|
"attoptions": [],
|
||||||
|
"seclabels": []
|
||||||
|
}, {
|
||||||
|
"name": "DOJ",
|
||||||
|
"cltype": "date",
|
||||||
|
"attacl": [],
|
||||||
|
"is_primary_key": False,
|
||||||
|
"attoptions": [],
|
||||||
|
"seclabels": []
|
||||||
|
}],
|
||||||
|
"exclude_constraint": [],
|
||||||
|
"fillfactor": "",
|
||||||
|
"hastoasttable": True,
|
||||||
|
"like_constraints": True,
|
||||||
|
"like_default_value": True,
|
||||||
|
"like_relation": "pg_catalog.pg_namespace",
|
||||||
|
"primary_key": [],
|
||||||
|
"relhasoids": True,
|
||||||
|
"seclabels": [],
|
||||||
|
"spcname": "pg_default",
|
||||||
|
"unique_constraint": [],
|
||||||
|
"vacuum_table": [{
|
||||||
|
"name": "autovacuum_analyze_scale_factor"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_analyze_threshold"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_freeze_max_age"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_cost_delay"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_cost_limit"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_scale_factor"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_threshold"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_freeze_min_age"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_freeze_table_age"
|
||||||
|
}],
|
||||||
|
"vacuum_toast": [{
|
||||||
|
"name": "autovacuum_freeze_max_age"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_cost_delay"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_cost_limit"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_scale_factor"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_vacuum_threshold"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_freeze_min_age"
|
||||||
|
}, {
|
||||||
|
"name": "autovacuum_freeze_table_age"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
@ -448,11 +448,11 @@ define([
|
|||||||
template: _.template([
|
template: _.template([
|
||||||
'<label class="<%=controlLabelClassName%>"><%=label%></label>',
|
'<label class="<%=controlLabelClassName%>"><%=label%></label>',
|
||||||
'<div class="<%=controlsClassName%> <%=extraClasses.join(\' \')%>">',
|
'<div class="<%=controlsClassName%> <%=extraClasses.join(\' \')%>">',
|
||||||
' <div class="btn-group pgadmin-controls-radio-none" data-toggle="buttons">',
|
' <div class="btn-group pgadmin-controls-radio-none<% if (disabled) {%> disabled <%}%>" data-toggle="buttons">',
|
||||||
' <% for (var i=0; i < options.length; i++) { %>',
|
' <% for (var i=0; i < options.length; i++) { %>',
|
||||||
' <% var option = options[i]; %>',
|
' <% var option = options[i]; %>',
|
||||||
' <label class="btn btn-primary<% if (option.value == value) { %> active<%}%>" tabindex="0">',
|
' <label class="btn btn-primary<% if (option.value == value) { %> active<%}%><% if (!option.disabled && !disabled) { %>" tabindex="0"<% } else { %> disabled"<% } %>>',
|
||||||
' <input type="radio" name="<%=name%>" autocomplete="off" value=<%-formatter.fromRaw(option.value)%> <% if (option.value == value) { %> checked<%}%> > <%-option.label%>',
|
' <input type="radio" name="<%=name%>" autocomplete="off" value=<%-formatter.fromRaw(option.value)%> <% if (option.value == value) { %> checked<%}%> <% if (option.disabled || disabled) { %> disabled <%}%>> <%-option.label%>',
|
||||||
' </label>',
|
' </label>',
|
||||||
' <% } %>',
|
' <% } %>',
|
||||||
' </div>',
|
' </div>',
|
||||||
@ -466,7 +466,37 @@ define([
|
|||||||
return this.formatter.toRaw(this.$el.find('input[type="radio"]:checked').attr('value'), this.model);
|
return this.formatter.toRaw(this.$el.find('input[type="radio"]:checked').attr('value'), this.model);
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
Backform.RadioControl.prototype.render.apply(this, arguments);
|
var field = _.defaults(this.field.toJSON(), this.defaults),
|
||||||
|
attributes = this.model.toJSON(),
|
||||||
|
attrArr = field.name.split('.'),
|
||||||
|
name = attrArr.shift(),
|
||||||
|
path = attrArr.join('.'),
|
||||||
|
rawValue = this.keyPathAccessor(attributes[name], path),
|
||||||
|
data = _.extend(field, {
|
||||||
|
rawValue: rawValue,
|
||||||
|
value: this.formatter.fromRaw(rawValue, this.model),
|
||||||
|
attributes: attributes,
|
||||||
|
formatter: this.formatter,
|
||||||
|
}),
|
||||||
|
// Evaluate the disabled, visible, and required option
|
||||||
|
evalF = function evalF(f, d, m) {
|
||||||
|
return _.isFunction(f) ? !!f.apply(d, [m]) : !!f;
|
||||||
|
};
|
||||||
|
|
||||||
|
_.extend(data, {
|
||||||
|
disabled: evalF(data.disabled, data, this.model),
|
||||||
|
visible: evalF(data.visible, data, this.model),
|
||||||
|
required: evalF(data.required, data, this.model),
|
||||||
|
}); // Clean up first
|
||||||
|
|
||||||
|
data.options = _.isFunction(data.options) ?
|
||||||
|
data.options.apply(data, [this.model]) : data.options;
|
||||||
|
|
||||||
|
this.$el.removeClass(Backform.hiddenClassName);
|
||||||
|
if (!data.visible) this.$el.addClass(Backform.hiddenClassName);
|
||||||
|
this.$el.html(this.template(data)).addClass(field.name);
|
||||||
|
this.updateInvalid();
|
||||||
|
|
||||||
this.$el.find('.btn').on('keyup', (e)=>{
|
this.$el.find('.btn').on('keyup', (e)=>{
|
||||||
switch(e.keyCode) {
|
switch(e.keyCode) {
|
||||||
case 32: /* Spacebar click */
|
case 32: /* Spacebar click */
|
||||||
|
@ -315,3 +315,11 @@ td.switch-cell > div.toggle {
|
|||||||
background-color: $color-primary-light;
|
background-color: $color-primary-light;
|
||||||
color: $color-primary;
|
color: $color-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-group.pgadmin-controls-radio-none.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group.pgadmin-controls-radio-none > label.btn.btn-primary.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|