mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-22 00:37:36 -06:00
This commit is contained in:
parent
5736e173ea
commit
3cd547f879
Binary file not shown.
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 88 KiB |
@ -10,11 +10,10 @@
|
||||
"""Implements the Foreign Table Module."""
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
from functools import wraps
|
||||
|
||||
import json
|
||||
from flask import render_template, make_response, request, jsonify, \
|
||||
from flask import render_template, request, jsonify, \
|
||||
current_app
|
||||
from flask_babel import gettext
|
||||
|
||||
@ -29,10 +28,11 @@ 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
|
||||
|
||||
|
||||
class ForeignTableModule(SchemaChildModule):
|
||||
@ -88,6 +88,10 @@ class ForeignTableModule(SchemaChildModule):
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||
constraints import blueprint as module
|
||||
self.submodules.append(module)
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas. \
|
||||
foreign_tables.foreign_table_columns import \
|
||||
foreign_table_column_blueprint as module
|
||||
self.submodules.append(module)
|
||||
super().register(app, options)
|
||||
|
||||
|
||||
@ -216,6 +220,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
'get_foreign_servers': [{'get': 'get_foreign_servers'},
|
||||
{'get': 'get_foreign_servers'}],
|
||||
'get_tables': [{'get': 'get_tables'}, {'get': 'get_tables'}],
|
||||
'set_trigger': [{'put': 'enable_disable_triggers'}],
|
||||
'get_columns': [{'get': 'get_columns'}, {'get': 'get_columns'}],
|
||||
'select_sql': [{'get': 'select_sql'}],
|
||||
'insert_sql': [{'get': 'insert_sql'}],
|
||||
@ -451,7 +456,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-foreign_table",
|
||||
description=row['description']
|
||||
description=row['description'],
|
||||
tigger_count=row['triggercount'],
|
||||
has_enable_triggers=row['has_enable_triggers'],
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@ -1160,15 +1167,14 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
"""
|
||||
cols = []
|
||||
for c in columns:
|
||||
if len(c) > 0:
|
||||
if '[]' in c['datatype']:
|
||||
c['datatype'] = c['datatype'].replace('[]', '')
|
||||
if len(c) > 0 and 'cltype' in c:
|
||||
if '[]' in c['cltype']:
|
||||
c['cltype'] = c['cltype'].replace('[]', '')
|
||||
c['isArrayType'] = True
|
||||
else:
|
||||
c['isArrayType'] = False
|
||||
cols.append(c)
|
||||
|
||||
return cols
|
||||
return cols if cols else columns
|
||||
|
||||
def _fetch_properties(self, gid, sid, did, scid, foid, inherits=False, ):
|
||||
"""
|
||||
@ -1238,18 +1244,44 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
if not status:
|
||||
return False, internal_server_error(errormsg=cols)
|
||||
|
||||
self._get_datatype_precision(cols)
|
||||
# Fetch length and precision data
|
||||
for col in cols['rows']:
|
||||
column_utils.fetch_length_precision(col)
|
||||
|
||||
self._get_edit_types(cols['rows'])
|
||||
|
||||
if cols and 'rows' in cols:
|
||||
data['columns'] = cols['rows']
|
||||
|
||||
# Get Inherited table names from their OID
|
||||
is_error, errmsg = self._get_inherited_table_name(data, inherits)
|
||||
|
||||
if is_error:
|
||||
return False, internal_server_error(errormsg=errmsg)
|
||||
|
||||
return True, data
|
||||
|
||||
def _get_edit_types(self, cols):
|
||||
edit_types = {}
|
||||
for col in cols:
|
||||
edit_types[col['atttypid']] = []
|
||||
|
||||
if len(cols) > 0:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'edit_mode_types_multi.sql']),
|
||||
type_ids=",".join(map(lambda x: str(x),
|
||||
edit_types.keys())))
|
||||
status, res = self.conn.execute_2darray(SQL)
|
||||
for row in res['rows']:
|
||||
edit_types[row['main_oid']] = sorted(row['edit_types'])
|
||||
|
||||
for column in cols:
|
||||
edit_type_list = edit_types[column['atttypid']]
|
||||
edit_type_list.append(column['fulltype'])
|
||||
column['edit_types'] = sorted(edit_type_list)
|
||||
column['cltype'] = \
|
||||
DataTypeReader.parse_type_name(column['cltype'])
|
||||
|
||||
def _get_datatype_precision(self, cols):
|
||||
"""
|
||||
The Length and the precision of the Datatype should be separated.
|
||||
@ -1262,11 +1294,11 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
substr = self.extract_type_length_precision(c)
|
||||
typlen = substr.split(",")
|
||||
if len(typlen) > 1:
|
||||
c['typlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['precision'] = self.convert_precision_to_int(typlen)
|
||||
c['attlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['attprecision'] = self.convert_precision_to_int(typlen)
|
||||
else:
|
||||
c['typlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['precision'] = None
|
||||
c['attlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['attprecision'] = None
|
||||
|
||||
# Get formatted Column Options
|
||||
if 'attfdwoptions' in c and c['attfdwoptions'] != '':
|
||||
@ -1393,7 +1425,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
|
||||
columns = []
|
||||
for c in data['columns']:
|
||||
columns.append(self.qtIdent(self.conn, c['attname']))
|
||||
columns.append(self.qtIdent(self.conn, c['name']))
|
||||
|
||||
if len(columns) > 0:
|
||||
columns = ", ".join(columns)
|
||||
@ -1434,7 +1466,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
# Now we have all list of columns which we need
|
||||
if 'columns' in data:
|
||||
for c in data['columns']:
|
||||
columns.append(self.qtIdent(self.conn, c['attname']))
|
||||
columns.append(self.qtIdent(self.conn, c['name']))
|
||||
values.append('?')
|
||||
|
||||
if len(columns) > 0:
|
||||
@ -1475,7 +1507,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
# Now we have all list of columns which we need
|
||||
if 'columns' in data:
|
||||
for c in data['columns']:
|
||||
columns.append(self.qtIdent(self.conn, c['attname']))
|
||||
columns.append(self.qtIdent(self.conn, c['name']))
|
||||
|
||||
if len(columns) > 0:
|
||||
if len(columns) == 1:
|
||||
@ -1676,6 +1708,66 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
|
||||
data['ftoptions'] = tmp_ftoptions
|
||||
|
||||
@check_precondition
|
||||
def enable_disable_triggers(self, gid, sid, did, scid, foid):
|
||||
"""
|
||||
This function will enable/disable trigger(s) on the table object
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
did: Database ID
|
||||
scid: Schema ID
|
||||
tid: Table ID
|
||||
"""
|
||||
# Below will decide if it's simple drop or drop with cascade call
|
||||
data = request.form if request.form else json.loads(
|
||||
request.data
|
||||
)
|
||||
# Convert str 'true' to boolean type
|
||||
is_enable_trigger = data['is_enable_trigger']
|
||||
|
||||
try:
|
||||
if foid is not None:
|
||||
status, data = self._fetch_properties(
|
||||
gid, sid, did, scid, foid, inherits=True)
|
||||
if not status:
|
||||
return data
|
||||
elif not data:
|
||||
return gone(self.not_found_error_msg())
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'enable_disable_trigger.sql']),
|
||||
data=data, is_enable_trigger=is_enable_trigger
|
||||
)
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'get_enabled_triggers.sql']),
|
||||
tid=foid
|
||||
)
|
||||
|
||||
status, trigger_res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext("Trigger(s) have been disabled")
|
||||
if is_enable_trigger == 'D'
|
||||
else gettext("Trigger(s) have been enabled"),
|
||||
data={
|
||||
'id': foid,
|
||||
'scid': scid,
|
||||
'has_enable_triggers': trigger_res
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, ForeignTableView)
|
||||
ForeignTableView.register_node_view(blueprint)
|
||||
|
@ -5,9 +5,10 @@ foreign tables.
|
||||
Do not remove these imports as they will be automatically imported by the view
|
||||
module as its children
|
||||
"""
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.columns \
|
||||
import blueprint as columns_module
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.triggers \
|
||||
import blueprint as triggers_modules
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||
constraints import blueprint as constraints_modules
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.\
|
||||
foreign_tables.foreign_table_columns import foreign_table_column_blueprint\
|
||||
as foreign_tables_columns_modules
|
||||
|
@ -0,0 +1,97 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
""" Implements Column Node for foreign table """
|
||||
import pgadmin.browser.server_groups.servers.databases as database
|
||||
from flask_babel import gettext
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.columns \
|
||||
import ColumnsView
|
||||
|
||||
|
||||
class ForeignTableColumnsModule(CollectionNodeModule):
|
||||
"""
|
||||
class ColumnsModule(CollectionNodeModule)
|
||||
|
||||
A module class for Column node derived from CollectionNodeModule.
|
||||
|
||||
Methods:
|
||||
-------
|
||||
* __init__(*args, **kwargs)
|
||||
- Method is used to initialize the Column and it's base module.
|
||||
|
||||
* get_nodes(gid, sid, did, scid, tid)
|
||||
- Method is used to generate the browser collection node.
|
||||
|
||||
* node_inode()
|
||||
- Method is overridden from its base class to make the node as leaf node.
|
||||
|
||||
* script_load()
|
||||
- Load the module script for schema, when any of the server node is
|
||||
initialized.
|
||||
"""
|
||||
|
||||
_NODE_TYPE = 'foreign_table_column'
|
||||
_COLLECTION_LABEL = gettext("Columns")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Method is used to initialize the ColumnModule and it's base module.
|
||||
|
||||
Args:
|
||||
*args:
|
||||
**kwargs:
|
||||
"""
|
||||
self.min_ver = None
|
||||
self.max_ver = None
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_nodes(self, gid, sid, did, scid, foid, **kwargs):
|
||||
"""
|
||||
Generate the collection node
|
||||
"""
|
||||
if self.has_nodes(
|
||||
sid, did, scid=scid, tid=foid,
|
||||
base_template_path=ForeignTableColumnsView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(foid)
|
||||
|
||||
@property
|
||||
def script_load(self):
|
||||
"""
|
||||
Load the module script for server, when any of the server-group node is
|
||||
initialized.
|
||||
"""
|
||||
return database.DatabaseModule.node_type
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
"""
|
||||
Load the module node as a leaf node
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def module_use_template_javascript(self):
|
||||
"""
|
||||
Returns whether Jinja2 template is used for generating the javascript
|
||||
module.
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
foreign_table_column_blueprint = ForeignTableColumnsModule(__name__)
|
||||
|
||||
|
||||
class ForeignTableColumnsView(ColumnsView):
|
||||
node_type = foreign_table_column_blueprint.node_type
|
||||
node_label = "Column"
|
||||
|
||||
|
||||
ForeignTableColumnsView.register_node_view(foreign_table_column_blueprint)
|
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#e1fff9;}.cls-2{fill:none;stroke:#aecec8;stroke-linejoin:round;stroke-width:0.75px;}.cls-3{fill:#16a085;}</style></defs><title>coll-column</title><g id="_2" data-name="2"><rect class="cls-1" x="4.15" y="1.95" width="5.5" height="9.9" rx="1" ry="1"/><line class="cls-2" x1="4.7" y1="6.9" x2="9.1" y2="6.9"/><line class="cls-2" x1="4.7" y1="9.1" x2="9.1" y2="9.1"/><path class="cls-3" d="M4.9,5.18l4,0v5.55a.35.35,0,0,1-.35.35H5.25a.35.35,0,0,1-.35-.35V5.18m-.75-.75v6.32a1.1,1.1,0,0,0,1.1,1.1h3.3a1.1,1.1,0,0,0,1.1-1.1V4.46l-5.5,0Z"/><path class="cls-3" d="M8.55,2.7A.35.35,0,0,1,8.9,3V4.5h-4V3a.35.35,0,0,1,.35-.35h3.3m0-.75H5.25A1.1,1.1,0,0,0,4.15,3v2.2h5.5V3A1.1,1.1,0,0,0,8.55,2Z"/><rect class="cls-1" x="6.35" y="4.15" width="5.5" height="9.9" rx="1" ry="1"/><line class="cls-2" x1="6.9" y1="9.1" x2="11.3" y2="9.1"/><line class="cls-2" x1="6.9" y1="11.3" x2="11.3" y2="11.3"/><path class="cls-3" d="M7.1,7.38l4,0V13a.35.35,0,0,1-.35.35H7.45A.35.35,0,0,1,7.1,13V7.38m-.75-.75V13A1.1,1.1,0,0,0,7.45,14h3.3a1.1,1.1,0,0,0,1.1-1.1V6.66l-5.5,0Z"/><path class="cls-3" d="M10.75,4.9a.35.35,0,0,1,.35.35V6.7h-4V5.25a.35.35,0,0,1,.35-.35h3.3m0-.75H7.45a1.1,1.1,0,0,0-1.1,1.1v2.2h5.5V5.25a1.1,1.1,0,0,0-1.1-1.1Z"/></g></svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="20" height="20"><defs><style>.cls-1{fill:#e1fff9;}.cls-2{fill:none;stroke:#aecec8;stroke-linejoin:round;stroke-width:0.75px;}.cls-3{fill:#16a085;}</style></defs><title>column</title><g id="_2" data-name="2"><rect class="cls-1" x="5.3" y="2.15" width="5.4" height="11.7" rx="1" ry="1"/><line class="cls-2" x1="5.75" y1="8" x2="10.25" y2="8"/><line class="cls-2" x1="5.75" y1="10.7" x2="10.25" y2="10.7"/><path class="cls-3" d="M6,5.83l3.9,0V13a.15.15,0,0,1-.15.15H6.2A.15.15,0,0,1,6,13V5.83M5.3,5.08V13a.9.9,0,0,0,.9.9H9.8a.9.9,0,0,0,.9-.9V5.1l-5.4,0Z"/><path class="cls-3" d="M9.8,2.9A.15.15,0,0,1,10,3V5H6V3A.15.15,0,0,1,6.2,2.9H9.8m0-.75H6.2a.9.9,0,0,0-.9.9v2.7h5.4V3a.9.9,0,0,0-.9-.9Z"/></g></svg>
|
After Width: | Height: | Size: 768 B |
@ -0,0 +1,70 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { getNodeColumnSchema } from '../../../static/js/foreign_table.ui';
|
||||
|
||||
define('pgadmin.node.foreign_table_column', [
|
||||
'sources/gettext', 'sources/url_for', 'pgadmin.browser',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, pgBrowser
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-foreign_table_column']) {
|
||||
pgBrowser.Nodes['coll-foreign_table_column'] =
|
||||
pgBrowser.Collection.extend({
|
||||
node: 'foreign_table_column',
|
||||
label: gettext('Columns'),
|
||||
type: 'coll-foreign_table_column',
|
||||
columns: ['name', 'cltype', 'description']
|
||||
});
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['foreign_table_column']) {
|
||||
pgBrowser.Nodes['foreign_table_column'] = pgBrowser.Node.extend({
|
||||
// Foreign table is added in parent_type to support triggers on
|
||||
// foreign table where we need column information.
|
||||
parent_type: ['foreign_table'],
|
||||
collection_type: ['coll-foreign_table'],
|
||||
type: 'foreign_table_column',
|
||||
label: gettext('Column'),
|
||||
hasSQL: true,
|
||||
sqlAlterHelp: 'sql-altertable.html',
|
||||
sqlCreateHelp: 'sql-altertable.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'column_dialog.html'}),
|
||||
canDrop: true,
|
||||
canDropCascade: false,
|
||||
hasDepends: true,
|
||||
hasStatistics: true,
|
||||
Init: function() {
|
||||
/* Avoid multiple registration of menus */
|
||||
if (this.initialized)
|
||||
return;
|
||||
|
||||
this.initialized = true;
|
||||
pgBrowser.add_menus([{
|
||||
name: 'create_column_on_coll', node: 'coll-foreign_table_column', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Column...'),
|
||||
data: {action: 'create'}, enable: 'canCreate',
|
||||
},{
|
||||
name: 'create_column_onTable', node: 'foreign_table', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Column...'),
|
||||
data: {action: 'create'}, enable: 'canCreate',
|
||||
},
|
||||
]);
|
||||
},
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return getNodeColumnSchema(treeNodeInfo, itemNodeData, pgBrowser);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return pgBrowser.Nodes['foreign_table_column'];
|
||||
});
|
@ -0,0 +1,8 @@
|
||||
ALTER FOREIGN TABLE public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" TYPE time(10) with time zone ;
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" DROP NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment modification';
|
@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_3_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time(6) with time zone DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment modification';
|
@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#" OPTIONS (SET column_name 'test_options_update');
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=111);
|
@ -0,0 +1,13 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_4_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options_update') NOT NULL GENERATED ALWAYS AS ((1000 + 1)) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=111);
|
@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time with time zone NOT NULL DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_3_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time with time zone NOT NULL DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
@ -0,0 +1,9 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options') NOT NULL GENERATED ALWAYS AS (1000+1) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=1);
|
@ -0,0 +1,13 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_4_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options') NOT NULL GENERATED ALWAYS AS ((1000 + 1)) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=1);
|
@ -0,0 +1,213 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FDW for foreign table",
|
||||
"endpoint": "NODE-foreign_data_wrapper.obj",
|
||||
"sql_endpoint": "NODE-foreign_data_wrapper.sql_id",
|
||||
"data": {
|
||||
"name": "test_fdw_for_foreign_table_columns",
|
||||
"fdwacl": [],
|
||||
"fdwoptions": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create foreign server for foreign table",
|
||||
"endpoint": "NODE-foreign_server.obj",
|
||||
"sql_endpoint": "NODE-foreign_server.sql_id",
|
||||
"data": {
|
||||
"name":"test_fs_for_foreign_table_column"
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Foreign Table for testing column node.",
|
||||
"endpoint": "NODE-foreign_table.obj",
|
||||
"sql_endpoint": "NODE-foreign_table.sql_id",
|
||||
"data": {
|
||||
"name": "foreign_table_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"columns": [],
|
||||
"schema": "public",
|
||||
"basensp": "public",
|
||||
"ftsrvname": "test_fs_for_foreign_table_column",
|
||||
"owner": "postgres",
|
||||
"ftoptions": [],
|
||||
"inherits": [],
|
||||
"relacl": [],
|
||||
"seclabels": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"expected_sql_file": "create_column_numeric.sql",
|
||||
"expected_msql_file": "create_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 1,
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for alter",
|
||||
"cltype": "real",
|
||||
"coloptions":{"added":[{"option":"column_name","value":"test"}]}
|
||||
},
|
||||
"expected_sql_file": "alter_column_numeric.sql",
|
||||
"expected_msql_file": "alter_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with text & default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "text",
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "'xyz'"
|
||||
},
|
||||
"expected_sql_file": "create_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "create_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 2,
|
||||
"defval": "'changed default value'"
|
||||
},
|
||||
"expected_sql_file": "alter_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "alter_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with time with time zone & default value using function",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_3_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "time with time zone",
|
||||
"attacl": [],
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "now()"
|
||||
},
|
||||
"expected_sql_file": "create_column_timestamp_with_default_value_using_function.sql",
|
||||
"expected_msql_file": "create_column_timestamp_with_default_value_using_function.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with time with time zone & update length",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attlen": "10",
|
||||
"attnotnull": false,
|
||||
"attnum":3,
|
||||
"description": "test comment modification"
|
||||
},
|
||||
"expected_sql_file": "alter_column_timestamp_with_default_value_using_function.sql",
|
||||
"expected_msql_file": "alter_column_timestamp_with_default_value_using_function.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column with time with time zone",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_3_$%{}[]()&*^!@\"'`\\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with integer & generated always with expression, column option, variables",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {"name":"col_4_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description":"test comment",
|
||||
"cltype":"bigint",
|
||||
"attnotnull":true,
|
||||
"coloptions":[{"option":"column_name","value":"test_options"}],
|
||||
"colconstype":"g",
|
||||
"is_tlength":false,
|
||||
"is_precision":false,
|
||||
"genexpr":"1000+1",
|
||||
"attoptions":[{"name":"n_distinct","value":"1"}]},
|
||||
"expected_sql_file": "create_column_with_integer_generated_always_column_option_variables.sql",
|
||||
"expected_msql_file": "create_column_with_integer_generated_always_column_option_variables.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with integer & generated always with expression, column option, variables",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data":{
|
||||
"attoptions":{
|
||||
"changed":[{"name":"n_distinct","value":"111"}]},
|
||||
"coloptions":{"changed":[{"option":"column_name","value":"test_options_update"}]},
|
||||
"attnum":4},
|
||||
"expected_sql_file": "alter_column_with_integer_generated_always_column_option_variables.sql",
|
||||
"expected_msql_file": "alter_column_with_integer_generated_always_column_option_variables.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column with time with time zone",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_columnn.sql_id",
|
||||
"data": {
|
||||
"name":"col_4_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}
|
||||
]}
|
@ -0,0 +1,16 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
|
||||
|
||||
class ForeignTableGeneratorTestCase(BaseTestGenerator):
|
||||
|
||||
def runTest(self):
|
||||
return []
|
@ -0,0 +1,154 @@
|
||||
{
|
||||
"column_create": [
|
||||
{
|
||||
"name": "Create: Add FT column with valid data",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {
|
||||
"name": "test_ft_column_add_",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"coloptions":[],
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create: Add FT column with valid data while server down",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {
|
||||
"name": "test_column_add_",
|
||||
"cltype": "\"char\"",
|
||||
"attacl": [],
|
||||
"is_primary_key": false,
|
||||
"attnotnull": false,
|
||||
"attlen": null,
|
||||
"attprecision": null,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"description": {
|
||||
"comment": "jsoncomment"
|
||||
}
|
||||
},
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_scalar",
|
||||
"return_value": "[(False, 'Mocked Internal Server Error'),(True,True)]"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500,
|
||||
"error_msg": "Mocked Internal Server Error",
|
||||
"test_result_data": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"column_delete": [
|
||||
{
|
||||
"name": "Delete: Existing FT column",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
},
|
||||
{
|
||||
"name": "Delete: Multiple existing FT column",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": true
|
||||
},
|
||||
{
|
||||
"name": "Delete: Non-existing FT column",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {
|
||||
"column_id": 9999999
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": "Error: Object not found.",
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
},
|
||||
{
|
||||
"name": "Delete: Existing FT column while server down",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_dict",
|
||||
"return_value": "[(False,'Mocked Internal Server Error')]"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500,
|
||||
"error_msg": "Mocked Internal Server Error",
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
}
|
||||
],
|
||||
"column_get": [
|
||||
{
|
||||
"name": "Get details: For existing FT column",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
},
|
||||
{
|
||||
"name": "Get details: For existing FT column while server down",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_dict",
|
||||
"return_value": "[(False,'Mocked Internal Server Error')]"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500,
|
||||
"error_msg": "Mocked Internal Server Error",
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
RENAME "col_1_$%{}[]()&*^!@""'`\/#" TO "new_col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
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 COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" TYPE real;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for alter';
|
@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "new_col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" real OPTIONS (column_name 'test') NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for alter';
|
@ -0,0 +1,2 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_2_$%{}[]()&*^!@""'`\/#" SET DEFAULT 'changed default value';
|
@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_2_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_2_$%{}[]()&*^!@""'`\/#" text COLLATE pg_catalog."default" NOT NULL DEFAULT 'changed default value'::text;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_1_$%{}[]()&*^!@""'`\/#" numeric(10, 5) NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for create';
|
@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_1_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_1_$%{}[]()&*^!@""'`\/#" numeric(10,5) NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for create';
|
@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_2_$%{}[]()&*^!@""'`\/#" text NOT NULL DEFAULT 'xyz';
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_2_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_2_$%{}[]()&*^!@""'`\/#" text COLLATE pg_catalog."default" NOT NULL DEFAULT 'xyz'::text;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
@ -0,0 +1,130 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FDW for foreign table",
|
||||
"endpoint": "NODE-foreign_data_wrapper.obj",
|
||||
"sql_endpoint": "NODE-foreign_data_wrapper.sql_id",
|
||||
"data": {
|
||||
"name": "test_fdw_for_foreign_table_columns",
|
||||
"fdwacl": [],
|
||||
"fdwoptions": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create foreign server for foreign table",
|
||||
"endpoint": "NODE-foreign_server.obj",
|
||||
"sql_endpoint": "NODE-foreign_server.sql_id",
|
||||
"data": {
|
||||
"name":"test_fs_for_foreign_table_column"
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Foreign Table for testing column node.",
|
||||
"endpoint": "NODE-foreign_table.obj",
|
||||
"sql_endpoint": "NODE-foreign_table.sql_id",
|
||||
"data": {
|
||||
"name": "foreign_table_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"columns": [],
|
||||
"schema": "public",
|
||||
"basensp": "public",
|
||||
"ftsrvname": "test_fs_for_foreign_table_column",
|
||||
"owner": "postgres",
|
||||
"ftoptions": [],
|
||||
"inherits": [],
|
||||
"relacl": [],
|
||||
"seclabels": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"coloptions":[],
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"expected_sql_file": "create_column_numeric.sql",
|
||||
"expected_msql_file": "create_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 1,
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for alter",
|
||||
"cltype": "real",
|
||||
"coloptions":{"added":[{"option":"column_name","value":"test"}]}
|
||||
},
|
||||
"expected_sql_file": "alter_column_numeric.sql",
|
||||
"expected_msql_file": "alter_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with text & default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "text",
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "'xyz'"
|
||||
},
|
||||
"expected_sql_file": "create_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "create_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 2,
|
||||
"defval": "'changed default value'"
|
||||
},
|
||||
"expected_sql_file": "alter_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "alter_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}
|
||||
]}
|
@ -0,0 +1,111 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
from unittest.mock import patch
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.foreign_tables.\
|
||||
tests import utils as ft_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||
utils as schema_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||
database_utils
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.foreign_tables.\
|
||||
foreign_table_columns. tests import utils as columns_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
|
||||
foreign_servers.tests import utils as fsrv_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
|
||||
tests import utils as fdw_utils
|
||||
|
||||
|
||||
class ColumnAddTestCase(BaseTestGenerator):
|
||||
"""This class will add new column under table node."""
|
||||
url = '/browser/foreign_table_column/obj/'
|
||||
|
||||
# Generates scenarios
|
||||
scenarios = utils.generate_scenarios("column_create",
|
||||
columns_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Load test data
|
||||
self.data = self.test_data
|
||||
|
||||
# Get parent schema info
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
self.schema_info = parent_node_dict['schema'][-1]
|
||||
self.server_id = self.schema_info['server_id']
|
||||
self.db_id = self.schema_info['db_id']
|
||||
|
||||
# Create db connection
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception("Could not connect to database to add a table.")
|
||||
|
||||
# Create schema
|
||||
self.schema_name = self.schema_info['schema_name']
|
||||
self.schema_id = self.schema_info['schema_id']
|
||||
schema_response = schema_utils.verify_schemas(self.server,
|
||||
self.db_name,
|
||||
self.schema_name)
|
||||
if not schema_response:
|
||||
raise Exception("Could not find the schema to add a table.")
|
||||
|
||||
# Create FDW, server & table
|
||||
self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.ft_name = "ft_%s" % (str(uuid.uuid4())[1:8])
|
||||
|
||||
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
|
||||
self.fdw_name)
|
||||
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
|
||||
self.fsrv_name, self.fdw_name)
|
||||
self.ft_id = ft_utils.create_foreign_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.fsrv_name,
|
||||
self.ft_name)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will add column under table node."""
|
||||
if "name" in self.data:
|
||||
self.data["name"] = self.data["name"] + (str(uuid.uuid4())[1:8])
|
||||
|
||||
if self.is_positive_test:
|
||||
response = columns_utils.api_create(self)
|
||||
|
||||
# Assert response
|
||||
utils.assert_status_code(self, response)
|
||||
|
||||
# Verify in backend
|
||||
self.assertIsNotNone(columns_utils.verify_column
|
||||
(self.server, self.db_name,
|
||||
self.data["name"]),
|
||||
"Column not found")
|
||||
else:
|
||||
if self.mocking_required:
|
||||
with patch(self.mock_data["function_name"],
|
||||
side_effect=eval(self.mock_data["return_value"])):
|
||||
response = columns_utils.api_create(self)
|
||||
else:
|
||||
if 'table_id' in self.data:
|
||||
self.table_id = self.data['table_id']
|
||||
|
||||
response = columns_utils.api_create(self)
|
||||
|
||||
# Assert response
|
||||
utils.assert_status_code(self, response)
|
||||
utils.assert_error_message(self, response)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,132 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
from unittest.mock import patch
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||
utils as schema_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||
database_utils
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.foreign_tables.\
|
||||
foreign_table_columns. tests import utils as columns_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
|
||||
foreign_servers.tests import utils as fsrv_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
|
||||
tests import utils as fdw_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.foreign_tables.\
|
||||
tests import utils as ft_utils
|
||||
|
||||
|
||||
class ColumnDeleteTestCase(BaseTestGenerator):
|
||||
"""This class will delete column under table node."""
|
||||
url = '/browser/foreign_table_column/obj/'
|
||||
|
||||
# Generates scenarios
|
||||
scenarios = utils.generate_scenarios("column_delete",
|
||||
columns_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Load test data
|
||||
self.data = self.test_data
|
||||
|
||||
# Get parent schema info
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
self.schema_info = parent_node_dict['schema'][-1]
|
||||
self.server_id = self.schema_info['server_id']
|
||||
self.db_id = self.schema_info['db_id']
|
||||
|
||||
# Create db connection
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception("Could not connect to database to add a table.")
|
||||
|
||||
# Create schema
|
||||
self.schema_name = self.schema_info['schema_name']
|
||||
self.schema_id = self.schema_info['schema_id']
|
||||
schema_response = schema_utils.verify_schemas(self.server,
|
||||
self.db_name,
|
||||
self.schema_name)
|
||||
if not schema_response:
|
||||
raise Exception("Could not find the schema to add a table.")
|
||||
|
||||
# Create FDW, server & table
|
||||
self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.ft_name = "ft_%s" % (str(uuid.uuid4())[1:8])
|
||||
|
||||
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
|
||||
self.fdw_name)
|
||||
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
|
||||
self.fsrv_name, self.fdw_name)
|
||||
self.ft_id = ft_utils.create_foreign_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.fsrv_name,
|
||||
self.ft_name)
|
||||
|
||||
# Create column
|
||||
self.column_name = "test_column_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.column_id = columns_utils.create_column(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.ft_name,
|
||||
self.column_name)
|
||||
|
||||
self.column_name_1 = "test_column_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
|
||||
self.column_id_1 = columns_utils.create_column(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.ft_name,
|
||||
self.column_name_1)
|
||||
# Verify column creation
|
||||
col_response = columns_utils.verify_column(self.server, self.db_name,
|
||||
self.column_name)
|
||||
if not col_response:
|
||||
raise Exception("Could not find the column to drop.")
|
||||
|
||||
col_response = columns_utils.verify_column(self.server, self.db_name,
|
||||
self.column_name_1)
|
||||
if not col_response:
|
||||
raise Exception("Could not find the column to drop.")
|
||||
|
||||
def runTest(self):
|
||||
"""This function will drop column under table node."""
|
||||
|
||||
if self.is_positive_test:
|
||||
if self.is_list:
|
||||
self.data["ids"] = [self.column_id, self.column_id_1]
|
||||
response = columns_utils.api_delete(self, "")
|
||||
else:
|
||||
response = columns_utils.api_delete(self)
|
||||
|
||||
# Assert response
|
||||
utils.assert_status_code(self, response)
|
||||
else:
|
||||
if self.mocking_required:
|
||||
with patch(self.mock_data["function_name"],
|
||||
side_effect=eval(self.mock_data["return_value"])):
|
||||
response = columns_utils.api_delete(self)
|
||||
else:
|
||||
if 'column_id' in self.data:
|
||||
self.column_id = self.data['column_id']
|
||||
response = columns_utils.api_delete(self)
|
||||
|
||||
# Assert response
|
||||
utils.assert_status_code(self, response)
|
||||
utils.assert_error_message(self, response)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,125 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
from unittest.mock import patch
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||
utils as schema_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||
database_utils
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
from . import utils as columns_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.foreign_tables.\
|
||||
foreign_table_columns. tests import utils as columns_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
|
||||
foreign_servers.tests import utils as fsrv_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
|
||||
tests import utils as fdw_utils
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.foreign_tables.\
|
||||
tests import utils as ft_utils
|
||||
|
||||
|
||||
class ColumnGetTestCase(BaseTestGenerator):
|
||||
"""This class will get column under table node."""
|
||||
url = '/browser/foreign_table_column/obj/'
|
||||
|
||||
# Generates scenarios
|
||||
scenarios = utils.generate_scenarios("column_get",
|
||||
columns_utils.test_cases)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Load test data
|
||||
self.data = self.test_data
|
||||
|
||||
# Get parent schema info
|
||||
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||
self.schema_info = parent_node_dict['schema'][-1]
|
||||
self.server_id = self.schema_info['server_id']
|
||||
self.db_id = self.schema_info['db_id']
|
||||
|
||||
# Create db connection
|
||||
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id)
|
||||
if not db_con['data']["connected"]:
|
||||
raise Exception("Could not connect to database to add a table.")
|
||||
|
||||
# Create schema
|
||||
self.schema_name = self.schema_info['schema_name']
|
||||
self.schema_id = self.schema_info['schema_id']
|
||||
schema_response = schema_utils.verify_schemas(self.server,
|
||||
self.db_name,
|
||||
self.schema_name)
|
||||
if not schema_response:
|
||||
raise Exception("Could not find the schema to add a table.")
|
||||
|
||||
# Create FDW, server & table
|
||||
self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.ft_name = "ft_%s" % (str(uuid.uuid4())[1:8])
|
||||
|
||||
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
|
||||
self.fdw_name)
|
||||
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
|
||||
self.fsrv_name, self.fdw_name)
|
||||
self.ft_id = ft_utils.create_foreign_table(self.server, self.db_name,
|
||||
self.schema_name,
|
||||
self.fsrv_name,
|
||||
self.ft_name)
|
||||
|
||||
# Create column
|
||||
self.column_name = "test_column_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||
self.column_id = columns_utils.create_column(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.ft_name,
|
||||
self.column_name)
|
||||
if self.is_list:
|
||||
# Create column
|
||||
self.column_name_1 = "test_column_delete_%s" % \
|
||||
(str(uuid.uuid4())[1:8])
|
||||
self.column_id_1 = columns_utils.create_column(self.server,
|
||||
self.db_name,
|
||||
self.schema_name,
|
||||
self.ft_name,
|
||||
self.column_name_1)
|
||||
|
||||
def runTest(self):
|
||||
"""This function will fetch the column under table node."""
|
||||
if self.is_positive_test:
|
||||
if self.is_list:
|
||||
response = columns_utils.api_get(self, "")
|
||||
else:
|
||||
response = columns_utils.api_get(self)
|
||||
|
||||
# Assert response
|
||||
utils.assert_status_code(self, response)
|
||||
else:
|
||||
if self.mocking_required:
|
||||
with patch(self.mock_data["function_name"],
|
||||
side_effect=eval(self.mock_data["return_value"])):
|
||||
if self.is_list:
|
||||
response = columns_utils.api_get(self, "")
|
||||
else:
|
||||
response = columns_utils.api_get(self)
|
||||
else:
|
||||
if 'column_id' in self.data:
|
||||
self.column_id = self.data['column_id']
|
||||
response = columns_utils.api_get(self)
|
||||
|
||||
# Assert response
|
||||
utils.assert_status_code(self, response)
|
||||
utils.assert_error_message(self, response)
|
||||
|
||||
def tearDown(self):
|
||||
# Disconnect the database
|
||||
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,203 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import os
|
||||
import json
|
||||
from urllib.parse import urlencode
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
# Load test data from json file.
|
||||
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
with open(CURRENT_PATH + "/column_test_data.json") as data_file:
|
||||
test_cases = json.load(data_file)
|
||||
|
||||
|
||||
# api method calls
|
||||
def api_create(self):
|
||||
return self.tester.post("{0}{1}/{2}/{3}/{4}/{5}/".
|
||||
format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id,
|
||||
self.schema_id, self.ft_id),
|
||||
data=json.dumps(self.data),
|
||||
content_type='html/json'
|
||||
)
|
||||
|
||||
|
||||
def api_delete(self, column_id=None):
|
||||
if column_id is None:
|
||||
column_id = self.column_id
|
||||
return self.tester.delete("{0}{1}/{2}/{3}/{4}/{5}/{6}".
|
||||
format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id,
|
||||
self.schema_id, self.ft_id, column_id),
|
||||
data=json.dumps(self.data),
|
||||
follow_redirects=True
|
||||
)
|
||||
|
||||
|
||||
def api_get(self, column_id=None):
|
||||
if column_id is None:
|
||||
column_id = self.column_id
|
||||
return self.tester.get("{0}{1}/{2}/{3}/{4}/{5}/{6}".
|
||||
format(self.url, utils.SERVER_GROUP,
|
||||
self.server_id, self.db_id, self.schema_id,
|
||||
self.ft_id, column_id),
|
||||
data=json.dumps(self.data),
|
||||
follow_redirects=True
|
||||
)
|
||||
|
||||
|
||||
def api_get_msql(self, url_encode_data):
|
||||
return self.tester.get("{0}{1}/{2}/{3}/{4}/{5}/{6}?{7}".
|
||||
format(self.url, utils.SERVER_GROUP, self.server_id,
|
||||
self.db_id,
|
||||
self.schema_id, self.ft_id,
|
||||
self.column_id,
|
||||
urlencode(url_encode_data)),
|
||||
follow_redirects=True
|
||||
)
|
||||
|
||||
|
||||
def api_put(self):
|
||||
return self.tester.put("{0}{1}/{2}/{3}/{4}/{5}/{6}".
|
||||
format(self.url, utils.SERVER_GROUP, self.server_id,
|
||||
self.db_id, self.schema_id, self.ft_id,
|
||||
self.column_id),
|
||||
data=json.dumps(self.data),
|
||||
follow_redirects=True)
|
||||
|
||||
|
||||
def create_column(server, db_name, schema_name, table_name, col_name,
|
||||
col_data_type='char'):
|
||||
"""
|
||||
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 ft_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
|
||||
utils.set_isolation_level(connection, 0)
|
||||
pg_cursor = connection.cursor()
|
||||
query = "ALTER FOREIGN TABLE %s.%s ADD COLUMN %s %s" % \
|
||||
(schema_name, table_name, col_name, col_data_type)
|
||||
pg_cursor.execute(query)
|
||||
utils.set_isolation_level(connection, 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 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
|
||||
utils.set_isolation_level(connection, 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)
|
||||
utils.set_isolation_level(connection, 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):
|
||||
"""
|
||||
This function verifies table exist in database or not.
|
||||
:param server: server details
|
||||
:type server: dict
|
||||
:param db_name: database name
|
||||
:type db_name: str
|
||||
:param col_name: column name
|
||||
:type col_name: str
|
||||
:return table: table record from database
|
||||
:rtype: tuple
|
||||
"""
|
||||
try:
|
||||
connection = utils.get_db_connection(db_name,
|
||||
server['username'],
|
||||
server['db_password'],
|
||||
server['host'],
|
||||
server['port'],
|
||||
server['sslmode'])
|
||||
pg_cursor = connection.cursor()
|
||||
pg_cursor.execute("select * from pg_attribute where attname='%s'" %
|
||||
col_name)
|
||||
col = pg_cursor.fetchone()
|
||||
connection.close()
|
||||
return col
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
raise
|
@ -11,15 +11,16 @@ import { getNodeVariableSchema } from '../../../../../static/js/variable.ui';
|
||||
import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui';
|
||||
import ForeignTableSchema from './foreign_table.ui';
|
||||
import _ from 'lodash';
|
||||
import Notify from '../../../../../../../../static/js/helpers/Notifier';
|
||||
|
||||
/* Create and Register Foreign Table Collection and Node. */
|
||||
define('pgadmin.node.foreign_table', [
|
||||
define('pgadmin.node.foreign_table', ['pgadmin.tables.js/enable_disable_triggers',
|
||||
'sources/gettext', 'sources/url_for', 'pgadmin.browser',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection','pgadmin.node.column',
|
||||
'pgadmin.node.constraints'
|
||||
], function(
|
||||
gettext, url_for, pgBrowser, schemaChild, schemaChildTreeNode
|
||||
tableFunctions, gettext, url_for, pgBrowser, schemaChild, schemaChildTreeNode,
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-foreign_table']) {
|
||||
@ -69,9 +70,54 @@ define('pgadmin.node.foreign_table', [
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Foreign Table...'),
|
||||
data: {action: 'create', check: false}, enable: 'canCreate',
|
||||
},
|
||||
},{
|
||||
// To enable/disable all triggers for the table
|
||||
name: 'enable_all_triggers', node: 'foreign_table', module: this,
|
||||
applies: ['object', 'context'], callback: 'enable_triggers_on_table',
|
||||
category: gettext('Trigger(s)'), priority: 4, label: gettext('Enable All'),
|
||||
enable : 'canCreate_with_trigger_enable',
|
||||
data: {
|
||||
data_disabled: gettext('The selected tree node does not support this option.'),
|
||||
action: 'create'
|
||||
},
|
||||
},{
|
||||
name: 'disable_all_triggers', node: 'foreign_table', module: this,
|
||||
applies: ['object', 'context'], callback: 'disable_triggers_on_table',
|
||||
category: gettext('Trigger(s)'), priority: 4, label: gettext('Disable All'),
|
||||
enable : 'canCreate_with_trigger_disable',
|
||||
data: {
|
||||
data_disabled: gettext('The selected tree node does not support this option.'),
|
||||
action: 'create'
|
||||
}}
|
||||
]);
|
||||
|
||||
},
|
||||
callbacks: {
|
||||
/* Enable trigger(s) on table */
|
||||
enable_triggers_on_table: function(args) {
|
||||
tableFunctions.enableTriggers(
|
||||
pgBrowser.tree,
|
||||
Notify,
|
||||
this.generate_url.bind(this),
|
||||
args
|
||||
);
|
||||
},
|
||||
/* Disable trigger(s) on table */
|
||||
disable_triggers_on_table: function(args) {
|
||||
tableFunctions.disableTriggers(
|
||||
pgBrowser.tree,
|
||||
Notify,
|
||||
this.generate_url.bind(this),
|
||||
args
|
||||
);
|
||||
},
|
||||
},
|
||||
// Check to whether table has disable trigger(s)
|
||||
canCreate_with_trigger_enable: function(itemData) {
|
||||
return itemData.tigger_count > 0 && (itemData.has_enable_triggers == 0 || itemData.has_enable_triggers < itemData.tigger_count);
|
||||
},
|
||||
// Check to whether table has enable trigger(s)
|
||||
canCreate_with_trigger_disable: function(itemData) {
|
||||
return itemData.tigger_count > 0 && itemData.has_enable_triggers > 0;
|
||||
},
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return new ForeignTableSchema(
|
||||
|
@ -12,6 +12,7 @@ import SecLabelSchema from '../../../../../static/js/sec_label.ui';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import OptionsSchema from '../../../../../static/js/options.ui';
|
||||
import { isEmptyString } from 'sources/validators';
|
||||
import VariableSchema from 'top/browser/server_groups/servers/static/js/variable.ui';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui';
|
||||
@ -167,7 +168,7 @@ export default class ForeignTableSchema extends BaseUISchema {
|
||||
id: 'columns', label: gettext('Columns'), cell: 'text',
|
||||
type: 'collection', group: gettext('Columns'), mode: ['edit', 'create'],
|
||||
schema: this.columnsObj,
|
||||
canAdd: true, canDelete: true, canEdit: true, columns: ['attname', 'datatype', 'inheritedfrom'],
|
||||
canAdd: true, canDelete: true, canEdit: true, columns: ['name', 'cltype', 'attprecision', 'attlen', 'inheritedfrom'],
|
||||
// For each row edit/delete button enable/disable
|
||||
canEditRow: this.canEditDeleteRowColumns,
|
||||
canDeleteRow: this.canEditDeleteRowColumns,
|
||||
@ -256,27 +257,28 @@ export function getNodeColumnSchema(treeNodeInfo, itemNodeData, pgBrowser) {
|
||||
export class ColumnSchema extends BaseUISchema {
|
||||
constructor(initValues, getPrivilegeRoleSchema, nodeInfo, datatypeOptions, collspcnameOptions) {
|
||||
super({
|
||||
attname: undefined,
|
||||
datatype: undefined,
|
||||
typlen: undefined,
|
||||
precision: undefined,
|
||||
typdefault: undefined,
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
atttypid: undefined,
|
||||
cltype: undefined,
|
||||
edit_types: undefined,
|
||||
attlen: undefined,
|
||||
attprecision: undefined,
|
||||
defval: undefined,
|
||||
attnotnull: undefined,
|
||||
collname: undefined,
|
||||
collspcname: undefined,
|
||||
attstattarget:undefined,
|
||||
attnum: undefined,
|
||||
inheritedfrom: undefined,
|
||||
inheritedid: undefined,
|
||||
attstattarget: undefined,
|
||||
coloptions: [],
|
||||
colconstype: 'n',
|
||||
});
|
||||
|
||||
this.getPrivilegeRoleSchema = getPrivilegeRoleSchema;
|
||||
this.nodeInfo = nodeInfo;
|
||||
this.datatypeOptions = datatypeOptions;
|
||||
this.cltypeOptions = datatypeOptions;
|
||||
this.collspcnameOptions = collspcnameOptions;
|
||||
|
||||
this.datatypes = [];
|
||||
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
@ -287,43 +289,93 @@ export class ColumnSchema extends BaseUISchema {
|
||||
return (_.isUndefined(state.inheritedid) || _.isNull(state.inheritedid) || _.isUndefined(state.inheritedfrom) || _.isNull(state.inheritedfrom)) ? true : false;
|
||||
}
|
||||
|
||||
// Check whether the column is a generated column
|
||||
isTypeGenerated(state) {
|
||||
let colconstype = state.colconstype;
|
||||
return (!_.isUndefined(colconstype) && !_.isNull(colconstype) && colconstype == 'g');
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'attname', label: gettext('Name'), cell: 'text',
|
||||
id: 'name', label: gettext('Name'), cell: 'text',
|
||||
type: 'text', editable: obj.editable_check_for_column, noEmpty: true,
|
||||
minWidth: 115,
|
||||
disabled: (state)=>{
|
||||
return state.is_inherited;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'datatype', label: gettext('Data type'), minWidth: 150,
|
||||
group: gettext('Definition'), noEmpty: true,
|
||||
id: 'description', label: gettext('Comment'), cell: 'text',
|
||||
type: 'multiline', mode: ['properties', 'create', 'edit'],
|
||||
},
|
||||
{
|
||||
id: 'cltype',
|
||||
label: gettext('Data type'),
|
||||
minWidth: 150,
|
||||
group: gettext('Definition'),
|
||||
noEmpty: true,
|
||||
editable: obj.editable_check_for_column,
|
||||
options: obj.datatypeOptions,
|
||||
disabled: (state)=>{
|
||||
return state.is_inherited;
|
||||
},
|
||||
options: obj.cltypeOptions,
|
||||
optionsLoaded: (options)=>{
|
||||
obj.datatypes = options;
|
||||
obj.type_options = options;
|
||||
},
|
||||
cell: 'select',
|
||||
cell: (row)=>{
|
||||
return {
|
||||
cell: 'select',
|
||||
options: this.cltypeOptions,
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
filter: (options)=>{
|
||||
let result = options;
|
||||
let edit_types = row?.edit_types || [];
|
||||
if(!obj.isNew(row) && !this.inErd) {
|
||||
result = _.filter(options, (o)=>edit_types.indexOf(o.value) > -1);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
type: (state)=>{
|
||||
return {
|
||||
type: 'select',
|
||||
options: this.cltypeOptions,
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
filter: (options)=>{
|
||||
let result = options;
|
||||
let edit_types = state?.edit_types || [];
|
||||
if(!obj.isNew(state) && !this.inErd) {
|
||||
result = _.filter(options, (o)=>edit_types.indexOf(o.value) > -1);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
},
|
||||
type: 'select'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'inheritedfrom', label: gettext('Inherited From'), cell: 'label',
|
||||
type: 'label', readonly: true, editable: false, mode: ['properties', 'edit'],
|
||||
type: 'label', readonly: true, editable: false, mode: ['create','properties', 'edit'],
|
||||
},
|
||||
{
|
||||
id: 'attnum', label: gettext('Position'), cell: 'text',
|
||||
type: 'text', disabled: obj.inCatalog(), mode: ['properties'],
|
||||
},
|
||||
{
|
||||
id: 'typlen', label: gettext('Length'), cell: 'int',
|
||||
deps: ['datatype'], type: 'int', group: gettext('Definition'), width: 120, minWidth: 120,
|
||||
id: 'attlen', label: gettext('Length'), cell: 'int',
|
||||
deps: ['cltype'], type: 'int', group: gettext('Definition'), minWidth: 60,
|
||||
disabled: (state) => {
|
||||
let val = state.typlen;
|
||||
let val = state.attlen;
|
||||
// We will store type from selected from combobox
|
||||
if(!(_.isUndefined(state.inheritedid)
|
||||
|| _.isNull(state.inheritedid)
|
||||
@ -331,12 +383,12 @@ export class ColumnSchema extends BaseUISchema {
|
||||
|| _.isNull(state.inheritedfrom))) {
|
||||
|
||||
if (!_.isUndefined(val)) {
|
||||
state.typlen = undefined;
|
||||
state.attlen = undefined;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let of_type = state.datatype,
|
||||
let of_type = state.cltype,
|
||||
has_length = false;
|
||||
if(obj.type_options) {
|
||||
state.is_tlength = false;
|
||||
@ -358,34 +410,34 @@ export class ColumnSchema extends BaseUISchema {
|
||||
});
|
||||
|
||||
if (!has_length && !_.isUndefined(val)) {
|
||||
state.typlen = undefined;
|
||||
state.attlen = undefined;
|
||||
}
|
||||
|
||||
return !(state.is_tlength);
|
||||
}
|
||||
if (!has_length && !_.isUndefined(val)) {
|
||||
state.typlen = undefined;
|
||||
state.attlen = undefined;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'precision', label: gettext('Precision'), cell: 'int', minWidth: 60,
|
||||
deps: ['datatype'], type: 'int', group: gettext('Definition'),
|
||||
id: 'attprecision', label: gettext('Scale'), cell: 'int', minWidth: 60,
|
||||
deps: ['cltype'], type: 'int', group: gettext('Definition'),
|
||||
disabled: (state) => {
|
||||
let val = state.precision;
|
||||
let val = state.attprecision;
|
||||
if(!(_.isUndefined(state.inheritedid)
|
||||
|| _.isNull(state.inheritedid)
|
||||
|| _.isUndefined(state.inheritedfrom)
|
||||
|| _.isNull(state.inheritedfrom))) {
|
||||
|
||||
if (!_.isUndefined(val)) {
|
||||
state.precision = undefined;
|
||||
state.attprecision = undefined;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let of_type = state.datatype,
|
||||
let of_type = state.cltype,
|
||||
has_precision = false;
|
||||
|
||||
if(obj.type_options) {
|
||||
@ -406,34 +458,16 @@ export class ColumnSchema extends BaseUISchema {
|
||||
}
|
||||
});
|
||||
if (!has_precision && !_.isUndefined(val)) {
|
||||
state.precision = undefined;
|
||||
state.attprecision = undefined;
|
||||
}
|
||||
return !(state.is_precision);
|
||||
}
|
||||
if (!has_precision && !_.isUndefined(val)) {
|
||||
state.precision = undefined;
|
||||
state.attprecision = undefined;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'typdefault', label: gettext('Default'), cell: 'text',
|
||||
type: 'text', group: gettext('Definition'),
|
||||
controlProps: {placeholder: gettext('Enter an expression or a value.')},
|
||||
editable: (state) => {
|
||||
if(!(_.isUndefined(state.inheritedid)
|
||||
|| _.isNull(state.inheritedid)
|
||||
|| _.isUndefined(state.inheritedfrom)
|
||||
|| _.isNull(state.inheritedfrom))) { return false; }
|
||||
|
||||
return obj.nodeInfo.server.version >= 90300;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'attnotnull', label: gettext('Not NULL?'), cell: 'switch',
|
||||
type: 'switch', minWidth: 80,
|
||||
group: gettext('Definition'), editable: obj.editable_check_for_column,
|
||||
},
|
||||
{
|
||||
id: 'attstattarget', label: gettext('Statistics'), cell: 'text',
|
||||
type: 'text', disabled: (state) => {
|
||||
@ -451,9 +485,103 @@ export class ColumnSchema extends BaseUISchema {
|
||||
group: gettext('Definition'),
|
||||
},
|
||||
{
|
||||
id: 'collname', label: gettext('Collation'), cell: 'select',
|
||||
id: 'attstorage', label: gettext('Storage'), group: gettext('Definition'),
|
||||
type: 'select', mode: ['properties', 'edit'],
|
||||
cell: 'select', readonly: obj.inSchemaWithColumnCheck,
|
||||
controlProps: { placeholder: gettext('Select storage'),
|
||||
allowClear: false,
|
||||
},
|
||||
options: [
|
||||
{label: 'PLAIN', value: 'p'},
|
||||
{label: 'MAIN', value: 'm'},
|
||||
{label: 'EXTERNAL', value: 'e'},
|
||||
{label: 'EXTENDED', value: 'x'},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'defval',
|
||||
label: gettext('Default'),
|
||||
cell: 'text',
|
||||
type: 'text',
|
||||
group: gettext('Constraints'),
|
||||
editable: (state) => {
|
||||
if(!(_.isUndefined(state.inheritedid)
|
||||
|| _.isNull(state.inheritedid)
|
||||
|| _.isUndefined(state.inheritedfrom)
|
||||
|| _.isNull(state.inheritedfrom))) { return false; }
|
||||
|
||||
return obj.nodeInfo.server.version >= 90300;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'attnotnull',
|
||||
label: gettext('Not NULL?'),
|
||||
cell: 'switch',
|
||||
type: 'switch',
|
||||
minWidth: 80,
|
||||
group: gettext('Constraints'),
|
||||
editable: obj.editable_check_for_column,
|
||||
},
|
||||
{
|
||||
id: 'colconstype',
|
||||
label: gettext('Type'),
|
||||
cell: 'text',
|
||||
group: gettext('Constraints'),
|
||||
type: (state)=>{
|
||||
let options = [
|
||||
{
|
||||
'label': gettext('NONE'),
|
||||
'value': 'n'},
|
||||
]; // You can't change the existing column to Generated column.
|
||||
if (this.isNew(state)) {
|
||||
options.push({
|
||||
'label': gettext('GENERATED'),
|
||||
'value': 'g',
|
||||
});
|
||||
} else {
|
||||
options.push({
|
||||
'label': gettext('GENERATED'),
|
||||
'value': 'g',
|
||||
'disabled': true,
|
||||
});
|
||||
}
|
||||
return {
|
||||
type: 'toggle',
|
||||
options: options,
|
||||
};
|
||||
},
|
||||
disabled: function(state) {
|
||||
return (!this.isNew(state) && state.colconstype == 'g');
|
||||
},
|
||||
min_version: 120000,
|
||||
},
|
||||
{
|
||||
id: 'genexpr',
|
||||
label: gettext('Expression'),
|
||||
type: 'text',
|
||||
mode: ['properties', 'create', 'edit'],
|
||||
group: gettext('Constraints'),
|
||||
min_version: 120000,
|
||||
deps: ['colconstype'],
|
||||
visible: this.isTypeGenerated,
|
||||
readonly: function(state) {
|
||||
return !this.isNew(state);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'attoptions', label: gettext('Variables'), type: 'collection',
|
||||
group: gettext('Variables'),
|
||||
schema: new VariableSchema([
|
||||
{label: 'n_distinct', value: 'n_distinct', vartype: 'string'},
|
||||
{label: 'n_distinct_inherited', value: 'n_distinct_inherited', vartype: 'string'}
|
||||
], null, null, ['name', 'value']),
|
||||
uniqueCol : ['name'], mode: ['edit', 'create'],
|
||||
canAdd: true, canEdit: false, canDelete: true,
|
||||
},
|
||||
{
|
||||
id: 'collspcname', label: gettext('Collation'), cell: 'select',
|
||||
type: 'select', group: gettext('Definition'),
|
||||
deps: ['datatype'], options: obj.collspcnameOptions,
|
||||
deps: ['cltype'], options: obj.collspcnameOptions,
|
||||
disabled: (state)=>{
|
||||
if (!(_.isUndefined(obj.isNew)) && !obj.isNew(state)) { return false; }
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
{% 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 FOREIGN TABLE IF EXISTS {{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 %}
|
||||
{### Add coloptions to column ###}
|
||||
{% if data.coloptions %}{% for o in data.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 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 == 'g' and data.genexpr and data.genexpr != '' %}
|
||||
GENERATED ALWAYS AS ({{data.genexpr}}) STORED{% endif %}{% endif %};
|
||||
|
||||
{### Add comments ###}
|
||||
{% if data and data.description and data.description != None %}
|
||||
COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
|
||||
IS {{data.description|qtLiteral(conn)}};
|
||||
{% endif %}
|
||||
|
||||
{### Add variables to column ###}
|
||||
{% if data.attoptions %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
{{ VARIABLE.SET(conn, 'COLUMN', data.name, data.attoptions) }}
|
||||
{% endif %}
|
||||
|
||||
{### Alter column statistics value ###}
|
||||
{% if data.attstattarget is defined and data.attstattarget > -1 %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {{conn|qtTypeIdent(data.name)}} SET STATISTICS {{data.attstattarget}};
|
||||
{% endif %}
|
||||
|
||||
{### Alter column storage value ###}
|
||||
{% if data.attstorage is defined and data.attstorage != data.defaultstorage %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {{conn|qtTypeIdent(data.name)}} SET STORAGE {%if data.attstorage == 'p' %}
|
||||
PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
|
||||
EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
|
||||
{% endif %}
|
@ -0,0 +1 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}} DROP COLUMN IF EXISTS {{conn|qtIdent(data.name)}};
|
@ -0,0 +1,110 @@
|
||||
{% import 'macros/variable.macros' as VARIABLE %}
|
||||
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
|
||||
{### Rename column name ###}
|
||||
{% if data.name and data.name != o_data.name %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
RENAME {{conn|qtIdent(o_data.name)}} TO {{conn|qtIdent(data.name)}};
|
||||
|
||||
{% endif %}
|
||||
{### Add/Update column options ###}
|
||||
{% if 'coloptions' in data and data.coloptions != None and data.coloptions|length > 0 %}
|
||||
{% set coloptions = data.coloptions %}
|
||||
{% if data.name %}
|
||||
{% 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 %});
|
||||
{% 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 %});
|
||||
{% 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 %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{### Alter column type and collation ###}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname) or data.col_type_conversion is defined %}
|
||||
{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
|
||||
-- WARNING:
|
||||
-- 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 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 %};
|
||||
|
||||
{% endif %}
|
||||
{### Alter column default value ###}
|
||||
{% if is_view_only and data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %}
|
||||
ALTER VIEW {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}};
|
||||
{% elif data.defval is defined and data.defval is not none and data.defval != '' and data.defval != o_data.defval %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET DEFAULT {{data.defval}};
|
||||
|
||||
{% endif %}
|
||||
{### Drop column default value ###}
|
||||
{% if data.defval is defined and (data.defval == '' or data.defval is none) and data.defval != o_data.defval %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} DROP DEFAULT;
|
||||
|
||||
{% endif %}
|
||||
{### Alter column not null value ###}
|
||||
{% if 'attnotnull' in data and data.attnotnull != o_data.attnotnull %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} {% if data.attnotnull %}SET{% else %}DROP{% endif %} NOT NULL;
|
||||
|
||||
{% endif %}
|
||||
{### Alter column statistics value ###}
|
||||
{% if data.attstattarget is defined and data.attstattarget != o_data.attstattarget %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET STATISTICS {{data.attstattarget}};
|
||||
|
||||
{% endif %}
|
||||
{### Alter column storage value ###}
|
||||
{% if data.attstorage is defined and data.attstorage != o_data.attstorage %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} SET STORAGE {%if data.attstorage == 'p' %}
|
||||
PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
|
||||
EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
|
||||
|
||||
{% endif %}
|
||||
{% if data.description is defined and data.description != None %}
|
||||
{% if data.name %}
|
||||
COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
|
||||
{% else %}
|
||||
COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, o_data.name)}}
|
||||
{% endif %}
|
||||
IS {{data.description|qtLiteral(conn)}};
|
||||
|
||||
{% endif %}
|
||||
{### Update column variables ###}
|
||||
{% if 'attoptions' in data and data.attoptions != None and data.attoptions|length > 0 %}
|
||||
{% set variables = data.attoptions %}
|
||||
{% if 'deleted' in variables and variables.deleted|length > 0 %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
{% if data.name %}
|
||||
{{ VARIABLE.UNSET(conn, 'COLUMN', data.name, variables.deleted) }}
|
||||
{% else %}
|
||||
{{ VARIABLE.UNSET(conn, 'COLUMN', o_data.name, variables.deleted) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if 'added' in variables and variables.added|length > 0 %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
{% if data.name %}
|
||||
{{ VARIABLE.SET(conn, 'COLUMN', data.name, variables.added) }}
|
||||
{% else %}
|
||||
{{ VARIABLE.SET(conn, 'COLUMN', o_data.name, variables.added) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if 'changed' in variables and variables.changed|length > 0 %}
|
||||
ALTER FOREIGN TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
|
||||
{% if data.name %}
|
||||
{{ VARIABLE.SET(conn, 'COLUMN', data.name, variables.changed) }}
|
||||
{% else %}
|
||||
{{ VARIABLE.SET(conn, 'COLUMN', o_data.name, variables.changed) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
@ -7,12 +7,12 @@ CREATE FOREIGN TABLE{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ c
|
||||
{% for c in data.columns %}
|
||||
{% if (not c.inheritedfrom or c.inheritedfrom =='' or c.inheritedfrom == None or c.inheritedfrom == 'None' ) %}
|
||||
{% if is_columns.append('1') %}{% endif %}
|
||||
{{conn|qtIdent(c.attname)}} {% if is_sql %}{{ c.fulltype }}{% else %}{{c.datatype }}{% if c.typlen %}({{c.typlen}}{% if c.precision %}, {{c.precision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %}{% endif %}{% if c.coloptions %}
|
||||
{{conn|qtIdent(c.name)}} {% if is_sql %}{{ c.fulltype }}{% else %}{{c.cltype }}{% if c.attlen %}({{c.attlen}}{% if c.attprecision %}, {{c.attprecision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %}{% 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.typdefault is defined and c.typdefault is not none %} DEFAULT {{c.typdefault}}{% 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 %},
|
||||
{% endif %}
|
||||
@ -51,7 +51,7 @@ COMMENT ON FOREIGN TABLE {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
{% for c in data.columns %}
|
||||
{% if c.description %}
|
||||
|
||||
COMMENT ON COLUMN {{conn|qtIdent(data.basensp, data.name, c.attname)}}
|
||||
COMMENT ON COLUMN {{conn|qtIdent(data.basensp, data.name, c.name)}}
|
||||
IS {{c.description|qtLiteral(conn)}};
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
@ -0,0 +1,13 @@
|
||||
SELECT t.main_oid, pg_catalog.ARRAY_AGG(t.typname) as edit_types
|
||||
FROM
|
||||
(SELECT pc.castsource AS main_oid, pg_catalog.format_type(tt.oid,NULL) AS typname
|
||||
FROM pg_catalog.pg_type tt
|
||||
JOIN pg_catalog.pg_cast pc ON tt.oid=pc.casttarget
|
||||
WHERE pc.castsource IN ({{type_ids}})
|
||||
AND pc.castcontext IN ('i', 'a')
|
||||
UNION
|
||||
SELECT tt.typbasetype AS main_oid, pg_catalog.format_type(tt.oid,NULL) AS typname
|
||||
FROM pg_catalog.pg_type tt
|
||||
WHERE tt.typbasetype IN ({{type_ids}})
|
||||
) t
|
||||
GROUP BY t.main_oid;
|
@ -0,0 +1,3 @@
|
||||
{% set enable_map = {'O':'ENABLE', 'D':'DISABLE'} %}
|
||||
ALTER FOREIGN TABLE {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
{{ enable_map[is_enable_trigger] }} TRIGGER ALL;
|
@ -16,7 +16,7 @@ CREATE FOREIGN TABLE {{ conn|qtIdent(o_data.basensp, o_data.name) }}(
|
||||
{% for c in columns %}
|
||||
{% if (not c.inheritedfrom or c.inheritedfrom =='' or c.inheritedfrom == None or c.inheritedfrom == 'None' ) %}
|
||||
{% if is_columns.append('1') %}{% endif %}
|
||||
{{conn|qtIdent(c.attname)}} {% if is_sql %}{{ c.fulltype }}{% else %}{{c.datatype }}{% if c.typlen %}({{c.typlen}}{% if c.precision %}, {{c.precision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %}{% endif %}{% if c.coloptions %}
|
||||
{{conn|qtIdent(c.name)}} {% if is_sql %}{{ c.fulltype }}{% else %}{{c.cltype }}{% if c.attlen %}({{c.attlen}}{% if c.attprecision %}, {{c.attprecision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %}{% 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 %}
|
||||
|
@ -1,6 +1,6 @@
|
||||
WITH INH_TABLES AS
|
||||
(SELECT
|
||||
distinct on (at.attname) attname, ph.inhparent AS inheritedid, ph.inhseqno,
|
||||
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
|
||||
@ -13,9 +13,12 @@ WITH INH_TABLES AS
|
||||
GROUP BY at.attname, ph.inhparent, ph.inhseqno, inheritedfrom
|
||||
ORDER BY at.attname, ph.inhparent, ph.inhseqno, inheritedfrom
|
||||
)
|
||||
SELECT INH.inheritedfrom, INH.inheritedid, att.attoptions, attfdwoptions,
|
||||
att.attname, att.attndims, att.atttypmod, pg_catalog.format_type(t.oid,NULL) AS datatype,
|
||||
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,
|
||||
CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END as elemoid,
|
||||
(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,
|
||||
@ -25,7 +28,7 @@ SELECT INH.inheritedfrom, INH.inheritedid, att.attoptions, attfdwoptions,
|
||||
FROM
|
||||
pg_catalog.pg_attribute att
|
||||
LEFT JOIN
|
||||
INH_TABLES as INH ON att.attname = INH.attname
|
||||
INH_TABLES as INH ON att.attname = INH.name
|
||||
JOIN
|
||||
pg_catalog.pg_type t ON t.oid=atttypid
|
||||
JOIN
|
||||
|
@ -0,0 +1 @@
|
||||
SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid={{tid}} AND tgisinternal = FALSE AND tgenabled = 'O'
|
@ -1,6 +1,6 @@
|
||||
{% if attrelid %}
|
||||
SELECT
|
||||
a.attname, pg_catalog.format_type(a.atttypid, NULL) AS datatype,
|
||||
a.attname as name, pg_catalog.format_type(a.atttypid, NULL) AS cltype,
|
||||
pg_catalog.quote_ident(n.nspname)||'.'||quote_ident(c.relname) as inheritedfrom,
|
||||
c.oid as inheritedid
|
||||
FROM
|
||||
|
@ -1,6 +1,8 @@
|
||||
SELECT
|
||||
c.oid, c.relname AS name, pg_catalog.pg_get_userbyid(relowner) AS owner,
|
||||
ftoptions, nspname as basensp, description
|
||||
ftoptions, nspname as basensp, description,
|
||||
(SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=c.oid AND tgisinternal = FALSE) AS triggercount,
|
||||
(SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=c.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers
|
||||
FROM
|
||||
pg_catalog.pg_class c
|
||||
JOIN
|
||||
|
@ -17,41 +17,42 @@ ALTER FOREIGN TABLE IF EXISTS {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
{% 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.attname)}};
|
||||
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.attname)}} {{ c.datatype }}{% if c.typlen %}({{c.typlen}}{% if c.precision %}, {{c.precision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %}
|
||||
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.typdefault is defined and c.typdefault is not none %} DEFAULT {{c.typdefault}}{% 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]['attname'] %}
|
||||
{% if c.attname != o_data['columns'][c.attnum]['attname'] %}
|
||||
{% set col_name = c.attname %}
|
||||
{% 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]['attname'])}} TO {{conn|qtIdent(c.attname)}};
|
||||
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.datatype != o_data['columns'][c.attnum]['datatype'] or c.typlen != o_data['columns'][c.attnum]['typlen'] or
|
||||
c.precision != o_data['columns'][c.attnum]['precision'] %}
|
||||
{% 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.datatype }}{% if c.typlen %}({{c.typlen}}{% if c.precision %}, {{c.precision}}{% endif %}){% endif %}{% if c.isArrayType %}[]{% endif %};
|
||||
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'] %}
|
||||
@ -83,7 +84,7 @@ 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 -%}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if data.inherits and data.inherits|length > 0%}
|
||||
|
@ -9,8 +9,8 @@
|
||||
"basensp": "schema_name",
|
||||
"columns": [
|
||||
{
|
||||
"attname": "ename",
|
||||
"datatype": "text",
|
||||
"name": "ename",
|
||||
"cltype": "text",
|
||||
"coloptions": []
|
||||
}
|
||||
],
|
||||
@ -41,8 +41,8 @@
|
||||
"basensp": "schema_name",
|
||||
"columns": [
|
||||
{
|
||||
"attname": "ename",
|
||||
"datatype": "text",
|
||||
"name": "ename",
|
||||
"cltype": "text",
|
||||
"coloptions": []
|
||||
}
|
||||
],
|
||||
@ -72,8 +72,8 @@
|
||||
"basensp": "schema_name",
|
||||
"columns": [
|
||||
{
|
||||
"attname": "ename",
|
||||
"datatype": "text",
|
||||
"name": "ename",
|
||||
"cltype": "text",
|
||||
"coloptions": []
|
||||
}
|
||||
],
|
||||
@ -255,8 +255,8 @@
|
||||
"columns": {
|
||||
"added": [
|
||||
{
|
||||
"attname": "col2",
|
||||
"datatype": "character varying[]",
|
||||
"name": "col2",
|
||||
"cltype": "character varying[]",
|
||||
"coloptions": []
|
||||
}
|
||||
],
|
||||
@ -268,8 +268,8 @@
|
||||
"value": "OptionValue"
|
||||
}
|
||||
],
|
||||
"attname": "emp",
|
||||
"datatype": "\"char\"",
|
||||
"name": "emp",
|
||||
"cltype": "\"char\"",
|
||||
"typdefault": null,
|
||||
"attnotnull": false,
|
||||
"collname": "pg_catalog.\"default\"",
|
||||
|
@ -11,7 +11,8 @@
|
||||
"fdwoptions": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create foreign server for foreign table",
|
||||
"endpoint": "NODE-foreign_server.obj",
|
||||
@ -20,7 +21,8 @@
|
||||
"name":"test_fs_for_foreign_table"
|
||||
},
|
||||
"store_object_id": "True"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Foreign Table with all options",
|
||||
"endpoint": "NODE-foreign_table.obj",
|
||||
@ -34,12 +36,12 @@
|
||||
"description":"Test Comment",
|
||||
"ftsrvname":"test_fs_for_foreign_table",
|
||||
"columns":[{
|
||||
"attname":"col1",
|
||||
"datatype":"bigint",
|
||||
"name":"col1",
|
||||
"cltype":"bigint",
|
||||
"coloptions":[]
|
||||
},{
|
||||
"attname":"col2",
|
||||
"datatype":"text",
|
||||
"name":"col2",
|
||||
"cltype":"text",
|
||||
"coloptions":[]
|
||||
}],
|
||||
"constraints":[{
|
||||
@ -107,12 +109,12 @@
|
||||
"description":"Test Comment",
|
||||
"columns": {
|
||||
"added": [{
|
||||
"attname":"col1",
|
||||
"datatype":"bigint",
|
||||
"name":"col1",
|
||||
"cltype":"bigint",
|
||||
"coloptions":[]
|
||||
},{
|
||||
"attname":"col2",
|
||||
"datatype":"text",
|
||||
"name":"col2",
|
||||
"cltype":"text",
|
||||
"coloptions":[]
|
||||
}]
|
||||
}
|
||||
@ -182,17 +184,17 @@
|
||||
},
|
||||
"columns": {
|
||||
"changed": [{
|
||||
"attname": "col1",
|
||||
"name": "col1",
|
||||
"attnum": 1,
|
||||
"attoptions": null,
|
||||
"collname": "",
|
||||
"coloptions": [],
|
||||
"datatype": "integer",
|
||||
"cltype": "integer",
|
||||
"fulltype": "bigint"
|
||||
}],
|
||||
"deleted": [{
|
||||
"attname":"col2",
|
||||
"datatype":"text"
|
||||
"name":"col2",
|
||||
"cltype":"text"
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
@ -34,12 +34,12 @@
|
||||
"description":"Test Comment",
|
||||
"ftsrvname":"test_fs_for_foreign_table",
|
||||
"columns":[{
|
||||
"attname":"col1",
|
||||
"datatype":"bigint",
|
||||
"name":"col1",
|
||||
"cltype":"bigint",
|
||||
"coloptions":[]
|
||||
},{
|
||||
"attname":"col2",
|
||||
"datatype":"text",
|
||||
"name":"col2",
|
||||
"cltype":"text",
|
||||
"coloptions":[]
|
||||
}],
|
||||
"constraints":[{
|
||||
@ -107,12 +107,12 @@
|
||||
"description":"Test Comment",
|
||||
"columns": {
|
||||
"added": [{
|
||||
"attname":"col1",
|
||||
"datatype":"bigint",
|
||||
"name":"col1",
|
||||
"cltype":"bigint",
|
||||
"coloptions":[]
|
||||
},{
|
||||
"attname":"col2",
|
||||
"datatype":"text",
|
||||
"name":"col2",
|
||||
"cltype":"text",
|
||||
"coloptions":[]
|
||||
}]
|
||||
}
|
||||
@ -182,17 +182,17 @@
|
||||
},
|
||||
"columns": {
|
||||
"changed": [{
|
||||
"attname": "col1",
|
||||
"name": "col1",
|
||||
"attnum": 1,
|
||||
"attoptions": null,
|
||||
"collname": "",
|
||||
"coloptions": [],
|
||||
"datatype": "integer",
|
||||
"cltype": "integer",
|
||||
"fulltype": "bigint"
|
||||
}],
|
||||
"deleted": [{
|
||||
"attname":"col2",
|
||||
"datatype":"text"
|
||||
"name":"col2",
|
||||
"cltype":"text"
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
@ -25,6 +25,7 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
||||
make_response as ajax_response, gone
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||
columns import utils as column_utils
|
||||
from pgadmin.utils.compile_template_name import compile_template_path
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.utils.ajax import ColParamsJSONDecoder
|
||||
@ -214,6 +215,9 @@ class ColumnsView(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)
|
||||
|
||||
# Allowed ACL for column 'Select/Update/Insert/References'
|
||||
self.acl = ['a', 'r', 'w', 'x']
|
||||
|
||||
@ -420,7 +424,11 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
||||
column_utils.type_formatter(data['cltype'])
|
||||
data = column_utils.convert_length_precision_to_string(data)
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
# Check if node is foreign_table_column
|
||||
template_path = self.foreign_table_column_template_path \
|
||||
if self.node_type == 'foreign_table_column' else self.template_path
|
||||
|
||||
SQL = render_template("/".join([template_path,
|
||||
self._CREATE_SQL]),
|
||||
data=data, conn=self.conn)
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
@ -493,7 +501,12 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
||||
data['schema'] = self.schema
|
||||
data['table'] = self.table
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
# Check if node is foreign_table_column
|
||||
template_path = self.foreign_table_column_template_path \
|
||||
if self.node_type == 'foreign_table_column' \
|
||||
else self.template_path
|
||||
|
||||
SQL = render_template("/".join([template_path,
|
||||
self._DELETE_SQL]),
|
||||
data=data, conn=self.conn)
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
@ -649,9 +662,15 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
||||
if 'attacl' in data:
|
||||
data['attacl'] = parse_priv_to_db(data['attacl'],
|
||||
self.acl)
|
||||
|
||||
# Check if node is foreign_table_column
|
||||
template_path = self.foreign_table_column_template_path \
|
||||
if self.node_type == 'foreign_table_column' \
|
||||
else self.template_path
|
||||
|
||||
# If the request for new object which do not have did
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, self._CREATE_SQL]),
|
||||
"/".join([template_path, self._CREATE_SQL]),
|
||||
data=data, conn=self.conn, is_sql=is_sql
|
||||
)
|
||||
|
||||
@ -687,6 +706,11 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
||||
data = column_utils.convert_length_precision_to_string(data)
|
||||
|
||||
if clid is not None:
|
||||
# Check if node is foreign_table_column
|
||||
template_path = self.foreign_table_column_template_path \
|
||||
if self.node_type == 'foreign_table_column' \
|
||||
else self.template_path
|
||||
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, self._PROPERTIES_SQL]),
|
||||
tid=tid, clid=clid,
|
||||
@ -714,7 +738,7 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
||||
self._parse_acl_to_db_parsing(data, old_data)
|
||||
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, self._UPDATE_SQL]),
|
||||
"/".join([template_path, self._UPDATE_SQL]),
|
||||
data=data, o_data=old_data, conn=self.conn,
|
||||
is_view_only=is_view_only
|
||||
)
|
||||
@ -778,8 +802,12 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
||||
self.conn, data['schema'], data['table'], data['name'])
|
||||
)
|
||||
|
||||
# Join delete sql
|
||||
template_path = self.foreign_table_column_template_path \
|
||||
if self.node_type == 'foreign_table_column' \
|
||||
else self.template_path
|
||||
sql_header += render_template(
|
||||
"/".join([self.template_path, self._DELETE_SQL]),
|
||||
"/".join([template_path, self._DELETE_SQL]),
|
||||
data=data, conn=self.conn
|
||||
)
|
||||
SQL = sql_header + '\n\n' + SQL
|
||||
|
@ -155,6 +155,10 @@ def column_formatter(conn, tid, clid, data, edit_types_list=None,
|
||||
|
||||
data['seclabels'] = seclabels
|
||||
|
||||
# Get formatted Column Options
|
||||
if 'attfdwoptions' in data and 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']),
|
||||
tid=tid, clid=clid)
|
||||
@ -186,12 +190,44 @@ def column_formatter(conn, tid, clid, data, edit_types_list=None,
|
||||
# We will need present type in edit mode
|
||||
edit_types_list.append(data['typname'])
|
||||
data['edit_types'] = sorted(edit_types_list)
|
||||
|
||||
data['cltype'] = DataTypeReader.parse_type_name(data['cltype'])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def _parse_options_for_column(db_variables):
|
||||
"""
|
||||
Function to format the output for variables.
|
||||
|
||||
Args:
|
||||
db_variables: Variable object
|
||||
|
||||
Expected Object Format:
|
||||
['option1=value1', ..]
|
||||
where:
|
||||
user_name and database are optional
|
||||
Returns:
|
||||
Variable Object in below format:
|
||||
{
|
||||
'variables': [
|
||||
{'name': 'var_name', 'value': 'var_value',
|
||||
'user_name': 'user_name', 'database': 'database_name'},
|
||||
...]
|
||||
}
|
||||
where:
|
||||
user_name and database are optional
|
||||
"""
|
||||
variables_lst = []
|
||||
|
||||
if db_variables is not None:
|
||||
for row in db_variables:
|
||||
# The value may contain equals in string, split on
|
||||
# first equals only
|
||||
var_name, var_value = row.split("=", 1)
|
||||
var_dict = {'option': var_name, 'value': var_value}
|
||||
variables_lst.append(var_dict)
|
||||
return variables_lst
|
||||
|
||||
|
||||
@get_template_path
|
||||
def get_formatted_columns(conn, tid, data, other_columns,
|
||||
table_or_type, template_path=None):
|
||||
|
@ -1,5 +1,5 @@
|
||||
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.attstattarget,
|
||||
att.atttypmod, att.attacl, att.attnotnull, att.attoptions, att.attfdwoptions, att.attstattarget,
|
||||
att.attstorage, att.attidentity,
|
||||
pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
|
||||
pg_catalog.format_type(ty.oid,NULL) AS typname,
|
||||
|
@ -1,5 +1,5 @@
|
||||
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.attstattarget,
|
||||
att.atttypmod, att.attacl, att.attnotnull, att.attoptions, att.attfdwoptions, att.attstattarget,
|
||||
att.attstorage, att.attidentity,
|
||||
pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
|
||||
pg_catalog.format_type(ty.oid,NULL) AS typname,
|
||||
|
@ -1,5 +1,5 @@
|
||||
SELECT att.attname as name, att.atttypid, att.attlen, att.attnum, att.attndims,
|
||||
att.atttypmod, att.attacl, att.attnotnull, att.attoptions, att.attstattarget,
|
||||
att.atttypmod, att.attacl, att.attnotnull, att.attoptions, att.attfdwoptions, att.attstattarget,
|
||||
att.attstorage, att.attidentity,
|
||||
pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
|
||||
pg_catalog.format_type(ty.oid,NULL) AS typname,
|
||||
|
@ -228,20 +228,6 @@ describe('ForeignTableColumnSchema', ()=>{
|
||||
mount(getEditView(schemaObj, getInitData));
|
||||
});
|
||||
|
||||
it('column editable', ()=>{
|
||||
let state = {};
|
||||
let editable = _.find(schemaObj.fields, (f)=>f.id=='attname').editable;
|
||||
let status = editable(state);
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
it('typdefault editable', ()=>{
|
||||
let state = {};
|
||||
let editable = _.find(schemaObj.fields, (f)=>f.id=='typdefault').editable;
|
||||
let status = editable(state);
|
||||
expect(status).toBe(true);
|
||||
});
|
||||
|
||||
it('typdefault_edit', ()=>{
|
||||
let defaultSchemaObj = new ForeignTableSchema(
|
||||
()=>new MockSchema(),
|
||||
|
@ -710,6 +710,8 @@ class ReverseEngineeredSQLTestCases(BaseTestGenerator):
|
||||
self.parent_ids['fsid'] = object_id
|
||||
elif endpoint.__contains__("NODE-role.obj"):
|
||||
object_name = object_data['rolname']
|
||||
elif endpoint.__contains__("NODE-foreign_table"):
|
||||
self.parent_ids['tid'] = object_id
|
||||
|
||||
# Store object id with object name
|
||||
self.all_object_ids[object_name] = object_id
|
||||
|
@ -480,6 +480,7 @@ module.exports = [{
|
||||
'pure|pgadmin.node.user_mapping',
|
||||
'pure|pgadmin.node.schema',
|
||||
'pure|pgadmin.node.catalog',
|
||||
'pure|pgadmin.node.foreign_table_column',
|
||||
'pure|pgadmin.node.catalog_object',
|
||||
'pure|pgadmin.node.collation',
|
||||
'pure|pgadmin.node.domain',
|
||||
|
@ -115,6 +115,7 @@ let webpackShimConfig = {
|
||||
'pgadmin.node.foreign_key': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/js/foreign_key'),
|
||||
'pgadmin.node.foreign_server': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/js/foreign_server'),
|
||||
'pgadmin.node.foreign_table': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/static/js/foreign_table'),
|
||||
'pgadmin.node.foreign_table_column': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/foreign_table_columns/static/js/foreign_table_column'),
|
||||
'pgadmin.node.fts_configuration': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/static/js/fts_configuration'),
|
||||
'pgadmin.node.fts_dictionary': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/static/js/fts_dictionary'),
|
||||
'pgadmin.node.fts_parser': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/fts_parsers/static/js/fts_parser'),
|
||||
|
Loading…
Reference in New Issue
Block a user