Fixed issues reported while testing foreign table node. #640

pull/6837/head
Yogesh Mahajan 2023-10-06 12:28:40 +05:30 committed by GitHub
parent 078a959e3d
commit 7ce07f7dcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 424 additions and 281 deletions

View File

@ -10,6 +10,7 @@
"""Implements the Foreign Table Module."""
import sys
import re
from functools import wraps
import json
@ -28,11 +29,14 @@ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.compile_template_name import compile_template_path
from pgadmin.utils.driver import get_driver
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
columns import utils as column_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
triggers import utils as trigger_utils
class ForeignTableModule(SchemaChildModule):
@ -188,6 +192,8 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
node_type = blueprint.node_type
node_label = "Foreign Table"
BASE_TEMPLATE_PATH = 'foreign_tables/sql/#{0}#'
double_newline = '\n\n'
pattern = '\n{2,}'
parent_ids = [
{'type': 'int', 'id': 'gid'},
@ -403,6 +409,17 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
self.template_path = \
self.BASE_TEMPLATE_PATH.format(self.manager.version)
self.foreign_table_column_template_path = compile_template_path(
'foreign_table_columns/sql', self.manager.version)
self.column_template_path = compile_template_path(
'columns/sql', self.manager.version)
# Template for trigger node
self.trigger_template_path = \
'triggers/sql/{0}/#{1}#'.format(self.manager.server_type,
self.manager.version)
return f(*args, **kwargs)
return wrap
@ -918,6 +935,11 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
SQL = sql_header + SQL
trigger_sql = self._get_resql_for_triggers(
foid, data['basensp'], data['name'])
SQL = SQL + trigger_sql
return ajax_response(response=SQL.strip('\n'))
@check_precondition
@ -1012,9 +1034,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
:return:
"""
for c in data['columns']['changed']:
old_col_options = c['attfdwoptions'] = []
if 'attfdwoptions' in c and c['attfdwoptions']:
old_col_options = c['attfdwoptions']
old_col_options = []
if 'coloptions' in c and c['coloptions']:
old_col_options = c['coloptions']
old_col_frmt_options = {}
@ -1089,7 +1111,13 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
data['is_schema_diff'] = True
old_data['columns_for_schema_diff'] = old_data['columns']
self._format_columns_data(data, old_data)
# If name is not present in request data
if 'name' not in data:
data['name'] = old_data['name']
# If name if not present
if 'schema' not in data:
data['schema'] = old_data['basensp']
# Parse Privileges
ForeignTableView._parse_privileges(data)
@ -1109,6 +1137,37 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
"/".join([self.template_path, self._UPDATE_SQL]),
data=data, o_data=old_data, conn=self.conn
)
# Removes trailing new lines
if sql:
sql = sql.strip('\n') + self.double_newline
# Parse/Format columns & create sql
if 'columns' in data:
# Parse the data coming from client
data = column_utils.parse_format_columns(data, mode='edit')
columns = data['columns']
column_sql = '\n'
# If column(s) is/are deleted
column_sql = self._check_for_column_delete(columns, data,
column_sql)
# If column(s) is/are changed
column_sql = self._check_for_column_update(columns, data,
column_sql, foid)
# If column(s) is/are added
column_sql = self._check_for_column_add(columns, data,
column_sql)
# Combine all the SQL together
sql += column_sql.strip('\n')
sql = re.sub(self.pattern, self.double_newline, sql)
sql = sql.strip('\n')
return sql, data['name'] if 'name' in data else old_data['name']
else:
data['columns'] = self._format_columns(data['columns'])
@ -1123,6 +1182,83 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
conn=self.conn)
return sql, data['name']
def _check_for_column_delete(self, columns, data, column_sql):
# If column(s) is/are deleted
if 'deleted' in columns:
for c in columns['deleted']:
c['schema'] = data['schema']
c['table'] = data['name']
# Sql for drop column
if 'inheritedfrom' not in c:
column_sql += render_template("/".join(
[self.foreign_table_column_template_path,
self._DELETE_SQL]),
data=c, conn=self.conn).strip('\n') + \
self.double_newline
return column_sql
def _check_for_column_update(self, columns, data, column_sql, tid):
# Here we will be needing previous properties of column
# so that we can compare & update it
if 'changed' in columns:
for c in columns['changed']:
c['schema'] = data['schema']
c['table'] = data['name']
properties_sql = render_template(
"/".join([self.column_template_path,
self._PROPERTIES_SQL]),
tid=tid,
clid=c['attnum'] if 'attnum' in c else None,
show_sys_objects=self.blueprint.show_system_objects
)
status, res = self.conn.execute_dict(properties_sql)
if not status:
return internal_server_error(errormsg=res)
old_col_data = res['rows'][0]
old_col_data['cltype'], \
old_col_data['hasSqrBracket'] = \
column_utils.type_formatter(old_col_data['cltype'])
old_col_data = \
column_utils.convert_length_precision_to_string(
old_col_data)
old_col_data = column_utils.fetch_length_precision(
old_col_data)
old_col_data['cltype'] = \
DataTypeReader.parse_type_name(
old_col_data['cltype'])
# Sql for alter column
if 'inheritedfrom' not in c and \
'inheritedfromtable' not in c:
column_sql += render_template("/".join(
[self.foreign_table_column_template_path,
self._UPDATE_SQL]),
data=c, o_data=old_col_data, conn=self.conn
).strip('\n') + self.double_newline
return column_sql
def _check_for_column_add(self, columns, data, column_sql):
# If column(s) is/are added
if 'added' in columns:
for c in columns['added']:
c['schema'] = data['schema']
c['table'] = data['name']
c = column_utils.convert_length_precision_to_string(c)
if 'inheritedfrom' not in c and \
'inheritedfromtable' not in c:
column_sql += render_template("/".join(
[self.foreign_table_column_template_path,
self._CREATE_SQL]),
data=c, conn=self.conn).strip('\n') + \
self.double_newline
return column_sql
@check_precondition
def dependents(self, gid, sid, did, scid, foid):
"""
@ -1248,6 +1384,14 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
for col in cols['rows']:
column_utils.fetch_length_precision(col)
if 'attoptions' in col and col['attoptions'] != '':
col['attoptions'] = column_utils.parse_column_variables(
col['attoptions'])
if 'attfdwoptions' in col and col['attfdwoptions'] != '':
col['coloptions'] = column_utils.parse_options_for_column(
col['attfdwoptions'])
self._get_edit_types(cols['rows'])
if cols and 'rows' in cols:
@ -1768,6 +1912,32 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
except Exception as e:
return internal_server_error(errormsg=str(e))
def _get_resql_for_triggers(self, tid, schema,
table):
"""
########################################
# Reverse engineered sql for TRIGGERS
########################################
"""
sql = render_template("/".join([self.trigger_template_path,
self._NODES_SQL]), tid=tid)
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
trigger_sql = ''
for row in rset['rows']:
trigger_sql = trigger_utils.get_reverse_engineered_sql(
self.conn, schema=schema, table=table, tid=tid,
trid=row['oid'], datlastsysoid=self._DATABASE_LAST_SYSTEM_OID,
show_system_objects=self.blueprint.show_system_objects,
template_path=None)
trigger_sql = "\n" + trigger_sql
trigger_sql = re.sub(self.pattern, self.double_newline,
trigger_sql)
return trigger_sql
SchemaDiffRegistry(blueprint.node_type, ForeignTableView)
ForeignTableView.register_node_view(blueprint)

View File

@ -1,4 +1,4 @@
ALTER FOREIGN TABLE public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" TYPE time(10) with time zone ;
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"

View File

@ -3,7 +3,7 @@ ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" OPTIONS (ADD column_name 'test');
ALTER FOREIGN TABLE public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" TYPE real;
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"

View File

@ -1,4 +1,4 @@
ALTER FOREIGN TABLE public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" TYPE time(10) with time zone ;
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"

View File

@ -3,7 +3,7 @@ ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" OPTIONS (ADD column_name 'test');
ALTER FOREIGN TABLE public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" TYPE real;
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"

View File

@ -62,6 +62,25 @@ export default class ForeignTableSchema extends BaseUISchema {
return isEmptyString(colstate.inheritedfrom);
}
inSchemaWithColumnCheck(state) {
if(this.nodeInfo && ('schema' in this.nodeInfo)) {
if(this.isNew(state)) {
return false;
}
// We will disable control if it's system columns
// inheritedfrom check is useful when we use this schema in table node
// inheritedfrom has value then we should disable it
if (!isEmptyString(state.inheritedfrom)){
return true;
}
// ie: it's position is less than 1
return !(!_.isUndefined(state.attnum) && state.attnum > 0);
}
return false;
}
getTableOid(tabId) {
// Here we will fetch the table oid from table name
// iterate over list to find table oid
@ -265,7 +284,7 @@ export class ColumnSchema extends BaseUISchema {
attlen: undefined,
attprecision: undefined,
defval: undefined,
attnotnull: undefined,
attnotnull: false,
collspcname: undefined,
attstattarget:undefined,
attnum: undefined,
@ -279,6 +298,8 @@ export class ColumnSchema extends BaseUISchema {
this.nodeInfo = nodeInfo;
this.cltypeOptions = datatypeOptions;
this.collspcnameOptions = collspcnameOptions;
this.datatypes = [];
}
get idAttribute() {
@ -295,6 +316,28 @@ export class ColumnSchema extends BaseUISchema {
return (!_.isUndefined(colconstype) && !_.isNull(colconstype) && colconstype == 'g');
}
attlenRange(state) {
for(let o of this.datatypes) {
if ( state.cltype == o.value ) {
if(o.length) return {min: o.min_val || 0, max: o.max_val};
}
}
return null;
}
attprecisionRange(state) {
for(let o of this.datatypes) {
if ( state.cltype == o.value ) {
if(o.precision) return {min: o.min_val || 0, max: o.max_val};
}
}
return null;
}
attCell(state) {
return { cell: this.attlenRange(state) ? 'int' : '' };
}
get baseFields() {
let obj = this;
@ -323,7 +366,7 @@ export class ColumnSchema extends BaseUISchema {
},
options: obj.cltypeOptions,
optionsLoaded: (options)=>{
obj.type_options = options;
obj.datatypes = options;
},
cell: (row)=>{
return {
@ -364,124 +407,91 @@ export class ColumnSchema extends BaseUISchema {
}
},
{
id: 'inheritedfrom', label: gettext('Inherited From'), cell: 'label',
type: 'label', readonly: true, editable: false, mode: ['create','properties', 'edit'],
id: 'inheritedfrom', label: gettext('Inherited from'), cell: 'label', type: 'text',
readonly: true, editable: false, mode: ['create','properties', 'edit'],
},
{
id: 'attnum', label: gettext('Position'), cell: 'text',
type: 'text', disabled: obj.inCatalog(), mode: ['properties'],
},
{
id: 'attlen', label: gettext('Length'), cell: 'int',
deps: ['cltype'], type: 'int', group: gettext('Definition'), minWidth: 60,
disabled: (state) => {
let val = state.attlen;
// We will store type from selected from combobox
if(!(_.isUndefined(state.inheritedid)
|| _.isNull(state.inheritedid)
|| _.isUndefined(state.inheritedfrom)
|| _.isNull(state.inheritedfrom))) {
if (!_.isUndefined(val)) {
state.attlen = undefined;
}
return true;
}
let of_type = state.cltype,
has_length = false;
if(obj.type_options) {
state.is_tlength = false;
// iterating over all the types
_.each(obj.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
has_length = true;
state.is_tlength = true;
state.min_val = o.min_val;
state.max_val = o.max_val;
}
}
});
if (!has_length && !_.isUndefined(val)) {
state.attlen = undefined;
}
return !(state.is_tlength);
}
if (!has_length && !_.isUndefined(val)) {
state.attlen = undefined;
}
return true;
id: 'attlen',
label: gettext('Length'),
group: gettext('Definition'),
deps: ['cltype'],
type: 'int',
minWidth: 60,
cell: (state)=>{
return obj.attCell(state);
},
},
{
id: 'attprecision', label: gettext('Scale'), cell: 'int', minWidth: 60,
depChange: (state)=>{
let range = this.attlenRange(state);
if(range) {
return {
...state, min_val_attlen: range.min, max_val_attlen: range.max,
};
} else {
return {
...state, attlen: null,
};
}
},
disabled: function(state) {
return !obj.attlenRange(state);
},
editable: function(state) {
// inheritedfrom has value then we should disable it
if (!isEmptyString(state.inheritedfrom)) {
return false;
}
return Boolean(obj.attlenRange(state));
},
},{
id: 'min_val_attlen', skipChange: true, visible: false, type: '',
},{
id: 'max_val_attlen', skipChange: true, visible: false, type: '',
},{
id: 'attprecision', label: gettext('Scale'), width: 60, disableResizing: true,
deps: ['cltype'], type: 'int', group: gettext('Definition'),
disabled: (state) => {
let val = state.attprecision;
if(!(_.isUndefined(state.inheritedid)
|| _.isNull(state.inheritedid)
|| _.isUndefined(state.inheritedfrom)
|| _.isNull(state.inheritedfrom))) {
if (!_.isUndefined(val)) {
state.attprecision = undefined;
}
return true;
}
let of_type = state.cltype,
has_precision = false;
if(obj.type_options) {
state.is_precision = false;
// iterating over all the types
_.each(obj.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)
{
has_precision = true;
// set the values in model
state.is_precision = true;
state.min_val = o.min_val;
state.max_val = o.max_val;
}
}
});
if (!has_precision && !_.isUndefined(val)) {
state.attprecision = undefined;
}
return !(state.is_precision);
}
if (!has_precision && !_.isUndefined(val)) {
state.attprecision = undefined;
}
return true;
cell: (state)=>{
return obj.attCell(state);
},
depChange: (state)=>{
let range = this.attprecisionRange(state);
if(range) {
return {
...state, min_val_attprecision: range.min, max_val_attprecision: range.max,
};
} else {
return {
...state, attprecision: null,
};
}
},
disabled: function(state) {
return !this.attprecisionRange(state);
},
editable: function(state) {
// inheritedfrom has value then we should disable it
if (!isEmptyString(state.inheritedfrom)) {
return false;
}
return Boolean(this.attprecisionRange(state));
},
},{
id: 'min_val_attprecision', skipChange: true, visible: false, type: '',
},{
id: 'max_val_attprecision', skipChange: true, visible: false, type: '',
},
{
id: 'attstattarget', label: gettext('Statistics'), cell: 'text',
type: 'text', disabled: (state) => {
if (obj.isNew()) {
return false;
}
if (obj.nodeInfo.server.version < 90200) {
return false;
}
return (_.isUndefined(state.inheritedid) || _.isNull(state.inheritedid) ||
_.isUndefined(state.inheritedfrom) || _.isNull(state.inheritedfrom)) ? true : false;
}, mode: ['properties', 'edit'],
id: 'attstattarget',
label: gettext('Statistics'),
cell: 'text',
type: 'text',
readonly: obj.inSchemaWithColumnCheck,
mode: ['properties', 'edit'],
group: gettext('Definition'),
},
{
@ -529,10 +539,9 @@ export class ColumnSchema extends BaseUISchema {
group: gettext('Constraints'),
type: (state)=>{
let options = [
{
'label': gettext('NONE'),
'value': 'n'},
]; // You can't change the existing column to Generated column.
{ 'label': gettext('NONE'), 'value': 'n'},
];
// You can't change the existing column to Generated column.
if (this.isNew(state)) {
options.push({
'label': gettext('GENERATED'),
@ -585,8 +594,10 @@ export class ColumnSchema extends BaseUISchema {
disabled: (state)=>{
if (!(_.isUndefined(obj.isNew)) && !obj.isNew(state)) { return false; }
return (_.isUndefined(state.inheritedid) || _.isNull(state.inheritedid) ||
_.isUndefined(state.inheritedfrom) || _.isNull(state.inheritedfrom)) ? true : false;
return (_.isUndefined(state.inheritedid)
|| _.isNull(state.inheritedid) ||
_.isUndefined(state.inheritedfrom) ||
_.isNull(state.inheritedfrom));
}
},
{

View File

@ -10,18 +10,21 @@ ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
{% if 'coloptions' in data and data.coloptions != None and data.coloptions|length > 0 %}
{% set coloptions = data.coloptions %}
{% if data.name %}
{% set colname = data.name %}
{% else %}
{% set colname = o_data.name %}
{% endif %}
{% if 'added' in coloptions and coloptions.added|length > 0 %}
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
ALTER COLUMN {{conn|qtIdent(data.name)}} OPTIONS (ADD {% for opt in coloptions.added %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(opt.option) }} {{ opt.value|qtLiteral(conn) }}{% endfor %});
ALTER COLUMN {{conn|qtIdent(colname)}} OPTIONS (ADD {% for opt in coloptions.added %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(opt.option) }} {{ opt.value|qtLiteral(conn) }}{% endfor %});
{% endif %}
{% if 'changed' in coloptions and coloptions.changed|length > 0 %}
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
ALTER COLUMN {{conn|qtIdent(data.name)}} OPTIONS (SET {% for opt in coloptions.changed %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(opt.option) }} {{ opt.value|qtLiteral(conn) }}{% endfor %});
ALTER COLUMN {{conn|qtIdent(colname)}} OPTIONS (SET {% for opt in coloptions.changed %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(opt.option) }} {{ opt.value|qtLiteral(conn) }}{% endfor %});
{% endif %}
{% if 'deleted' in coloptions and coloptions.deleted|length > 0 %}
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
ALTER COLUMN {{conn|qtIdent(data.name)}} OPTIONS (DROP {% for opt in coloptions.deleted %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(opt.option) }}{% endfor %});
{% endif %}
ALTER COLUMN {{conn|qtIdent(colname)}} OPTIONS (DROP {% for opt in coloptions.deleted %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(opt.option) }}{% endfor %});
{% endif %}
{% endif %}
{### Alter column type and collation ###}
@ -31,7 +34,7 @@ ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
-- The SQL statement below would normally be used to alter the cltype for the {{o_data.name}} column, however,
-- the current datatype cannot be cast to the target cltype so this conversion cannot be made automatically.
{% endif %}
{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}ALTER FOREIGN TABLE {{conn|qtIdent(data.schema, data.table)}}
{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %} ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %};

View File

@ -11,7 +11,7 @@ CREATE FOREIGN TABLE{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ c
{% for o in c.coloptions %}{% if o.option is defined and o.value is defined %}
{% if loop.first %} OPTIONS ({% endif %}{% if not loop.first %}, {% endif %}{{o.option}} {{o.value|qtLiteral(conn)}}{% if loop.last %}){% endif %}{% endif %}
{% endfor %}{% endif %}
{% if c.attnotnull %} NOT NULL{% else %} NULL{% endif %}
{% if c.attnotnull %} NOT NULL{% endif %}
{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
{% if c.collname %} COLLATE {{c.collname}}{% endif %}
{% if not loop.last %},

View File

@ -20,7 +20,7 @@ CREATE FOREIGN TABLE {{ conn|qtIdent(o_data.basensp, o_data.name) }}(
{% for o in c.coloptions %}{% if o.option is defined and o.value is defined %}
{% if loop.first %} OPTIONS ({% endif %}{% if not loop.first %}, {% endif %}{{o.option}} {{o.value|qtLiteral(conn)}}{% if loop.last %}){% endif %}{% endif %}
{% endfor %}{% endif %}
{% if c.attnotnull %} NOT NULL{% else %} NULL{% endif %}
{% if c.attnotnull %} NOT NULL{% endif %}
{% if c.typdefault is defined and c.typdefault is not none %} DEFAULT {{c.typdefault}}{% endif %}
{% if c.collname %} COLLATE {{c.collname}}{% endif %}
{% if not loop.last %},

View File

@ -15,14 +15,16 @@ WITH INH_TABLES AS
)
SELECT INH.inheritedfrom, INH.inheritedid, att.attoptions, att.atttypid, attfdwoptions,
att.attname as name, att.attndims, att.atttypmod, pg_catalog.format_type(t.oid,NULL) AS cltype,
att.attnotnull, att.attstattarget, att.attnum, pg_catalog.format_type(t.oid, att.atttypmod) AS fulltype,
att.attnotnull, att.attstorage, att.attstattarget, att.attnum, pg_catalog.format_type(t.oid, att.atttypmod) AS fulltype,
CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END as elemoid,
(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,
(SELECT nspname FROM pg_catalog.pg_namespace WHERE oid = t.typnamespace) as typnspname,
pg_catalog.format_type(t.oid,NULL) AS typname,
CASE WHEN length(cn.nspname::text) > 0 AND length(cl.collname::text) > 0 THEN
pg_catalog.concat(cn.nspname, '."', cl.collname,'"')
ELSE '' END AS collname,
pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS typdefault,
pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
(SELECT COUNT(1) from pg_catalog.pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup,
des.description
FROM

View File

@ -12,80 +12,6 @@ ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, o_data.name) }}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
OWNER TO {{ conn|qtIdent(data.owner) }};
{% endif %}
{% if data.columns %}
{% for c in data.columns.deleted %}
{% if (not c.inheritedfrom or c.inheritedfrom =='' or c.inheritedfrom == None or c.inheritedfrom == 'None' ) %}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
DROP COLUMN {{conn|qtIdent(c.name)}};
{% endif %}
{% endfor -%}
{% for c in data.columns.added %}
{% if (not c.inheritedfrom or c.inheritedfrom =='' or c.inheritedfrom == None or c.inheritedfrom == 'None' ) %}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ADD COLUMN {{conn|qtIdent(c.name)}} {{ c.cltype }}{% if c.attlen %}({{c.attlen}}{% if c.attprecision %}, {{c.attprecision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %}
{% if c.coloptions %}
{% for o in c.coloptions %}{% if o.option is defined and o.value is defined %}
{% if loop.first %} OPTIONS ({% endif %}{% if not loop.first %}, {% endif %}{{o.option}} {{o.value|qtLiteral(conn)}}{% if loop.last %}){% endif %}{% endif %}
{% endfor %}{% endif %}
{% if c.attnotnull %} NOT NULL{% else %} NULL{% endif %}
{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
{% if c.collname %} COLLATE {{c.collname}}{% endif %};
{% endif %}
{% endfor -%}
{% for c in data.columns.changed %}
{% set col_name = o_data['columns'][c.attnum]['name'] %}
{% if c.name %}{% if c.name != o_data['columns'][c.attnum]['name'] %}
{% set col_name = c.name %}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
RENAME COLUMN {{conn|qtIdent(o_data['columns'][c.attnum]['name'])}} TO {{conn|qtIdent(c.name)}};
{% endif %}
{% endif %}
{% if c.attnotnull != o_data['columns'][c.attnum]['attnotnull'] %}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}}{% if c.attnotnull %} SET{% else %} DROP{% endif %} NOT NULL;
{% endif %}
{% if c.cltype != o_data['columns'][c.attnum]['cltype'] or c.attlen != o_data['columns'][c.attnum]['attlen'] or
c.attprecision != o_data['columns'][c.attnum]['attprecision'] %}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}} TYPE {{ c.cltype }}{% if c.attlen %}({{c.attlen}}{% if c.attprecision %}, {{c.attprecision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %};
{% endif %}
{% if c.typdefault is defined and c.typdefault != o_data['columns'][c.attnum]['typdefault'] %}
ALTER FOREIGN TABLE {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}}{% if c.typdefault is defined and c.typdefault != '' %} SET DEFAULT {{c.typdefault}}{% else %} DROP DEFAULT{% endif %};
{% endif %}
{% if c.attstattarget != o_data['columns'][c.attnum]['attstattarget'] %}
ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}} SET STATISTICS {% if c.attstattarget %}{{c.attstattarget}}{% else %}-1{% endif %};
{% endif %}
{% if c.coloptions_updated %}
{% for o in c.coloptions_updated.deleted %}
{% if o.option %}
{% if loop.first %}ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}} OPTIONS (DROP {% endif %}{% if not loop.first %}, {% endif %}{{o.option}}{% if loop.last %}){% endif %};
{% endif %}
{% endfor %}
{% for o in c.coloptions_updated.added %}
{% if o.option is defined and o.value is defined %}
{% if loop.first %}ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}} OPTIONS (ADD {% endif %}{% if not loop.first %}, {% endif %}{{o.option}} {{o.value|qtLiteral(conn)}}{% if loop.last %});{% endif %}
{% endif %}
{% endfor %}
{% for o in c.coloptions_updated.changed %}
{% if o.option is defined and o.value is defined %}
{% if loop.first %}ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
ALTER COLUMN {{conn|qtIdent(col_name)}} OPTIONS (SET {% endif %}{% if not loop.first %}, {% endif %}{{o.option}} {{o.value|qtLiteral(conn)}}{% if loop.last %});{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% if data.inherits and data.inherits|length > 0%}
{% if o_data.inherits == None or o_data.inherits == 'None' %}

View File

@ -233,7 +233,7 @@
"name": "Update Foreign Table: With existing foreign table.",
"is_positive_test": true,
"inventory_data": {
"query": "\"CREATE FOREIGN TABLE %s.%s (col1 character varying(10) OPTIONS (columnoptionkey 'columnOptionVal') NULL ) SERVER %s;\" %(schema_name, foreign_table_name, fsrv_name)"
"query": "\"CREATE FOREIGN TABLE %s.%s (col1 character varying(10) OPTIONS (column_name 'columnOptionVal') NULL ) SERVER %s;\" %(schema_name, foreign_table_name, fsrv_name)"
},
"test_data": {
"description": "This is foreign table update comment",
@ -264,7 +264,7 @@
{
"coloptions": [
{
"option": "OptionKey",
"option": "column_name",
"value": "OptionValue"
}
],
@ -279,7 +279,7 @@
"attstattarget": -1,
"attoptions": null,
"attfdwoptions": [
"ColOptionKey=ColOptionValue"
"column_name=ColOptionValue"
],
"attndims": 0,
"atttypmod": -1,

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint NOT NULL,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint NOT NULL,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -3,7 +3,7 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 integer NULL
col1 integer
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'test_public', table_name 'test_table');

View File

@ -1,14 +1,13 @@
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
DROP COLUMN col2;
OPTIONS (SET schema_name 'test_public');
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN col1 DROP NOT NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS col2;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN col1 TYPE integer;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN col1 SET STATISTICS -1;
ALTER COLUMN col1 DROP NOT NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
OPTIONS (SET schema_name 'test_public');
ALTER COLUMN col1 SET STATISTICS 10;

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint NOT NULL,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table;

View File

@ -1,8 +1,8 @@
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col1 bigint NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col2 text NULL;
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col1 bigint NOT NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col2 text;

View File

@ -3,7 +3,7 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 integer NULL
col1 integer
)
SERVER test_fs_for_foreign_table
OPTIONS (table_name 'test_table');

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -1,6 +1,6 @@
CREATE FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL
col1 bigint,
col2 text
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -99,7 +99,8 @@
"ftsrvname": "test_fs_for_foreign_table",
"columns": []
}
}, {
},
{
"type": "alter",
"name": "Alter Foreign Table comment and add columns",
"endpoint": "NODE-foreign_table.obj_id",
@ -111,7 +112,8 @@
"added": [{
"name":"col1",
"cltype":"bigint",
"coloptions":[]
"coloptions":[],
"attnotnull": true
},{
"name":"col2",
"cltype":"text",
@ -121,7 +123,8 @@
},
"expected_sql_file": "alter_comment_add_columns.sql",
"expected_msql_file": "alter_comment_add_columns_msql.sql"
},{
},
{
"type": "alter",
"name": "Alter Foreign Table add constraints and options",
"endpoint": "NODE-foreign_table.obj_id",
@ -148,7 +151,8 @@
},
"expected_sql_file": "alter_add_cons_opts.sql",
"expected_msql_file": "alter_add_cons_opts_msql.sql"
}, {
},
{
"type": "alter",
"name": "Alter Foreign Table add privileges",
"endpoint": "NODE-foreign_table.obj_id",
@ -169,7 +173,8 @@
},
"expected_sql_file": "alter_add_priv.sql",
"expected_msql_file": "alter_add_priv_msql.sql"
}, {
},
{
"type": "alter",
"name": "Alter Foreign Table change option and column",
"endpoint": "NODE-foreign_table.obj_id",
@ -187,10 +192,11 @@
"name": "col1",
"attnum": 1,
"attoptions": null,
"attnotnull":false,
"attstattarget": 10,
"collname": "",
"coloptions": [],
"cltype": "integer",
"fulltype": "bigint"
"cltype": "integer"
}],
"deleted": [{
"name":"col2",
@ -200,7 +206,8 @@
},
"expected_sql_file": "alter_col_opts.sql",
"expected_msql_file": "alter_col_opts_msql.sql"
}, {
},
{
"type": "alter",
"name": "Alter Foreign Table remove option, constraint, privileges",
"endpoint": "NODE-foreign_table.obj_id",

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint NOT NULL,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint NOT NULL,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -3,7 +3,7 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 integer NULL
col1 integer
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'test_public', table_name 'test_table');

View File

@ -1,14 +1,13 @@
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
DROP COLUMN col2;
OPTIONS (SET schema_name 'test_public');
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN col1 DROP NOT NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS col2;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN col1 TYPE integer;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN col1 SET STATISTICS -1;
ALTER COLUMN col1 DROP NOT NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
OPTIONS (SET schema_name 'test_public');
ALTER COLUMN col1 SET STATISTICS 10;

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint NOT NULL,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table;

View File

@ -1,8 +1,8 @@
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col1 bigint NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col2 text NULL;
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col1 bigint NOT NULL;
ALTER FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"
ADD COLUMN col2 text;

View File

@ -3,7 +3,7 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 integer NULL
col1 integer
)
SERVER test_fs_for_foreign_table
OPTIONS (table_name 'test_table');

View File

@ -3,8 +3,8 @@
-- DROP FOREIGN TABLE IF EXISTS public."FT1_$%{}[]()&*^!@""'`\/#";
CREATE FOREIGN TABLE IF NOT EXISTS public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL COLLATE pg_catalog."default"
col1 bigint,
col2 text COLLATE pg_catalog."default"
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -1,6 +1,6 @@
CREATE FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"(
col1 bigint NULL,
col2 text NULL
col1 bigint,
col2 text
)
SERVER test_fs_for_foreign_table
OPTIONS (schema_name 'public', table_name 'test_table');

View File

@ -109,7 +109,8 @@
"added": [{
"name":"col1",
"cltype":"bigint",
"coloptions":[]
"coloptions":[],
"attnotnull": true
},{
"name":"col2",
"cltype":"text",
@ -185,10 +186,11 @@
"name": "col1",
"attnum": 1,
"attoptions": null,
"attnotnull":false,
"attstattarget": 10,
"collname": "",
"coloptions": [],
"cltype": "integer",
"fulltype": "bigint"
"cltype": "integer"
}],
"deleted": [{
"name":"col2",

View File

@ -82,16 +82,17 @@ export default class ColumnSchema extends BaseUISchema {
}
if(this.nodeInfo && ('schema' in this.nodeInfo)) {
// We will disable control if it's system columns
// inheritedfrom check is useful when we use this schema in table node
// inheritedfrom has value then we should disable it
if(!_.isUndefined(state.inheritedfrom)) {
return true;
}
if(this.isNew(state)) {
return false;
}
// We will disable control if it's system columns
// inheritedfrom check is useful when we use this schema in table node
// inheritedfrom has value then we should disable it
if (!isEmptyString(state.inheritedfrom)){
return true;
}
// ie: it's position is less than 1
return !(!_.isUndefined(state.attnum) && state.attnum > 0);
}

View File

@ -139,12 +139,7 @@ def column_formatter(conn, tid, clid, data, edit_types_list=None,
# We need to format variables according to client js collection
if 'attoptions' in data and data['attoptions'] is not None:
spcoptions = []
for spcoption in data['attoptions']:
k, v = spcoption.split('=')
spcoptions.append({'name': k, 'value': v})
data['attoptions'] = spcoptions
data['attoptions'] = parse_column_variables(data['attoptions'])
# Need to format security labels according to client js collection
if 'seclabels' in data and data['seclabels'] is not None:
@ -157,7 +152,7 @@ def column_formatter(conn, tid, clid, data, edit_types_list=None,
# Get formatted Column Options
if 'attfdwoptions' in data and data['attfdwoptions'] != '':
data['coloptions'] = _parse_options_for_column(data['attfdwoptions'])
data['coloptions'] = parse_options_for_column(data['attfdwoptions'])
# We need to parse & convert ACL coming from database to json format
SQL = render_template("/".join([template_path, 'acl.sql']),
@ -194,7 +189,7 @@ def column_formatter(conn, tid, clid, data, edit_types_list=None,
return data
def _parse_options_for_column(db_variables):
def parse_options_for_column(db_variables):
"""
Function to format the output for variables.
@ -446,3 +441,13 @@ def fetch_length_precision(data):
data['attprecision'] = None
return data
def parse_column_variables(col_variables):
# We need to format variables according to client js collection
spcoptions = []
if col_variables is not None:
for spcoption in col_variables:
k, v = spcoption.split('=')
spcoptions.append({'name': k, 'value': v})
return spcoptions

View File

@ -1,3 +1,18 @@
WITH INH_TABLES AS
(SELECT
at.attname AS name, ph.inhparent AS inheritedid, ph.inhseqno,
pg_catalog.concat(nmsp_parent.nspname, '.',parent.relname ) AS inheritedfrom
FROM
pg_catalog.pg_attribute at
JOIN
pg_catalog.pg_inherits ph ON ph.inhparent = at.attrelid AND ph.inhrelid = 33896::oid
JOIN
pg_catalog.pg_class parent ON ph.inhparent = parent.oid
JOIN
pg_catalog.pg_namespace nmsp_parent ON nmsp_parent.oid = parent.relnamespace
GROUP BY at.attname, ph.inhparent, ph.inhseqno, inheritedfrom
ORDER BY at.attname, ph.inhparent, ph.inhseqno, inheritedfrom
)
SELECT DISTINCT ON (att.attnum) att.attname as name, att.atttypid, att.attlen, att.attnum, att.attndims,
att.atttypmod, att.attacl, att.attnotnull, att.attoptions, att.attfdwoptions, att.attstattarget,
att.attstorage, att.attidentity,
@ -5,6 +20,8 @@ SELECT DISTINCT ON (att.attnum) att.attname as name, att.atttypid, att.attlen, a
pg_catalog.format_type(ty.oid,NULL) AS typname,
pg_catalog.format_type(ty.oid,att.atttypmod) AS displaytypname,
pg_catalog.format_type(ty.oid,att.atttypmod) AS cltype,
inh.inheritedfrom,
inh.inheritedid,
CASE WHEN ty.typelem > 0 THEN ty.typelem ELSE ty.oid END as elemoid,
(SELECT nspname FROM pg_catalog.pg_namespace WHERE oid = ty.typnamespace) as typnspname,
ty.typstorage AS defaultstorage,
@ -31,6 +48,7 @@ FROM pg_catalog.pg_attribute att
LEFT OUTER JOIN pg_catalog.pg_namespace nspc ON coll.collnamespace=nspc.oid
LEFT OUTER JOIN pg_catalog.pg_sequence seq ON cs.oid=seq.seqrelid
LEFT OUTER JOIN pg_catalog.pg_class tab on tab.oid = att.attrelid
LEFT OUTER join INH_TABLES as INH ON att.attname = INH.name
WHERE att.attrelid = {{tid}}::oid
{% if clid %}
AND att.attnum = {{clid}}::int