Fix creation of tables and columns in GPDB. Fixes #3099

This commit is contained in:
Joao Pedro De Almeida Pereira
2018-02-19 10:40:10 +00:00
committed by Dave Page
parent 1a958a3951
commit 15862e903a
20 changed files with 304 additions and 25 deletions

View File

@@ -20,6 +20,7 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \
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 config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
@@ -189,7 +190,11 @@ class CollationView(PGChildNodeView):
)
self.conn = self.manager.connection(did=kwargs['did'])
# Set the template path for the SQL scripts
self.template_path = 'collation/sql/#{0}#'.format(self.manager.version)
self.template_path = compile_template_path(
'collation/sql/',
self.manager.server_type,
self.manager.version
)
return f(*args, **kwargs)
return wrap

View File

@@ -0,0 +1,6 @@
SELECT 'pg_catalog.' || quote_ident(collate_setting.value) AS copy_collation
FROM (
SELECT setting AS value
FROM pg_settings
WHERE name='lc_collate'
) collate_setting;

View File

@@ -22,6 +22,7 @@ from pgadmin.browser.server_groups.servers.databases.utils import \
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 config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
@@ -267,7 +268,11 @@ class DomainView(PGChildNodeView, DataTypeReader):
self.qtIdent = driver.qtIdent
# we will set template path for sql scripts
self.template_path = 'domains/sql/#{0}#'.format(self.manager.version)
self.template_path = compile_template_path(
'domains/sql/',
self.manager.server_type,
self.manager.version
)
return f(*args, **kwargs)

View File

@@ -0,0 +1,6 @@
SELECT 'pg_catalog.' || quote_ident(collate_setting.value) AS copy_collation
FROM (
SELECT setting AS value
FROM pg_settings
WHERE name='lc_collate'
) collate_setting;

View File

@@ -27,6 +27,7 @@ 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 config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
@@ -344,7 +345,11 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
# Set template path for sql scripts depending
# on the server version.
self.template_path = 'foreign_tables/sql/#{0}#'.format(self.manager.version)
self.template_path = compile_template_path(
'foreign_tables/sql/',
self.manager.server_type,
self.manager.version
)
return f(*args, **kwargs)
return wrap

View File

@@ -0,0 +1,6 @@
SELECT 'pg_catalog.' || quote_ident(collate_setting.value) AS copy_collation
FROM (
SELECT setting AS value
FROM pg_settings
WHERE name='lc_collate'
) collate_setting;

View File

@@ -618,7 +618,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
show_system_objects=self.blueprint.show_system_objects
)
status, types = self.get_types(self.conn, condition, True)
status, types = self.get_types(self.conn, condition, True, sid)
if not status:
return internal_server_error(errormsg=types)

View File

@@ -20,6 +20,7 @@ from pgadmin.browser.server_groups.servers.databases.schemas.tables.partitions i
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 config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
@@ -249,7 +250,11 @@ class IndexesView(PGChildNodeView):
kwargs['did'] in self.manager.db_info else 0
# we will set template path for sql scripts
self.template_path = 'index/sql/#{0}#'.format(self.manager.version)
self.template_path = compile_template_path(
'index/sql/',
self.manager.server_type,
self.manager.version
)
# We need parent's name eg table name and schema name
# when we create new index in update we can fetch it using

View File

@@ -0,0 +1,23 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import * as _ from 'underscore';
function isServerGreenPlum(tableModel) {
return !_.isUndefined(tableModel.node_info) &&
!_.isUndefined(tableModel.node_info.server) &&
tableModel.node_info.server.server_type === 'gpdb';
}
export function show_advanced_tab(tableModel) {
if (isServerGreenPlum(tableModel)) {
return false;
}
return true;
}

View File

@@ -2,10 +2,12 @@ define('pgadmin.node.table', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.backgrid',
'pgadmin.tables.js/show_advanced_tab',
'pgadmin.browser.collection', 'pgadmin.node.column',
'pgadmin.node.constraints', 'pgadmin.browser.table.partition.utils',
], function(
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Alertify, Backform, Backgrid
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Alertify, Backform, Backgrid,
ShowAdvancedTab
) {
if (!pgBrowser.Nodes['coll-table']) {
@@ -501,12 +503,15 @@ define('pgadmin.node.table', [
return tbl_oid;
},
}),
},{
}, {
id: 'advanced', label: gettext('Advanced'), type: 'group',
visible: ShowAdvancedTab.show_advanced_tab,
}, {
id: 'coll_inherits', label: gettext('Inherited from table(s)'),
type: 'text', group: gettext('Advanced'), mode: ['properties'],
type: 'text', group: 'advanced', mode: ['properties'],
},{
id: 'inherited_tables_cnt', label: gettext('Inherited tables count'),
type: 'text', mode: ['properties'], group: gettext('Advanced'),
type: 'text', mode: ['properties'], group: 'advanced',
disabled: 'inSchema',
},{
// Tab control for columns
@@ -749,7 +754,7 @@ define('pgadmin.node.table', [
},{
id: 'typname', label: gettext('Of type'), type: 'text',
mode: ['properties', 'create', 'edit'],
disabled: 'checkOfType', url: 'get_oftype', group: gettext('Advanced'),
disabled: 'checkOfType', url: 'get_oftype', group: 'advanced',
deps: ['coll_inherits'], transform: function(data, cell) {
var control = cell || this,
m = control.model;
@@ -802,27 +807,27 @@ define('pgadmin.node.table', [
},{
id: 'fillfactor', label: gettext('Fill factor'), type: 'int',
mode: ['create', 'edit'], min: 10, max: 100,
disabled: 'inSchema',group: gettext('Advanced'),
disabled: 'inSchema',group: 'advanced',
},{
id: 'relhasoids', label: gettext('Has OIDs?'), cell: 'switch',
type: 'switch', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema', group: gettext('Advanced'),
disabled: 'inSchema', group: 'advanced',
},{
id: 'relpersistence', label: gettext('Unlogged?'), cell: 'switch',
type: 'switch', mode: ['properties', 'create', 'edit'],
disabled: 'inSchemaWithModelCheck',
group: gettext('Advanced'),
group: 'advanced',
},{
id: 'conname', label: gettext('Primary key'), cell: 'string',
type: 'text', mode: ['properties'], group: gettext('Advanced'),
type: 'text', mode: ['properties'], group: 'advanced',
disabled: 'inSchema',
},{
id: 'reltuples', label: gettext('Rows (estimated)'), cell: 'string',
type: 'text', mode: ['properties'], group: gettext('Advanced'),
type: 'text', mode: ['properties'], group: 'advanced',
disabled: 'inSchema',
},{
id: 'rows_cnt', label: gettext('Rows (counted)'), cell: 'string',
type: 'text', mode: ['properties'], group: gettext('Advanced'),
type: 'text', mode: ['properties'], group: 'advanced',
disabled: 'inSchema', control: Backform.InputControl.extend({
formatter: {
fromRaw: function (rawData) {
@@ -844,7 +849,7 @@ define('pgadmin.node.table', [
}),
},{
id: 'relhassubclass', label: gettext('Inherits tables?'), cell: 'switch',
type: 'switch', mode: ['properties'], group: gettext('Advanced'),
type: 'switch', mode: ['properties'], group: 'advanced',
disabled: 'inSchema',
},{
id: 'is_sys_table', label: gettext('System table?'), cell: 'switch',
@@ -852,7 +857,7 @@ define('pgadmin.node.table', [
disabled: 'inSchema',
},{
type: 'nested', control: 'fieldset', label: gettext('Like'),
group: gettext('Advanced'),
group: 'advanced',
schema:[{
id: 'like_relation', label: gettext('Relation'),
type: 'text', mode: ['create', 'edit'], deps: ['typname'],
@@ -1122,7 +1127,7 @@ define('pgadmin.node.table', [
group: 'security', canDelete: true, control: 'unique-col-collection',
},{
id: 'vacuum_settings_str', label: gettext('Storage settings'),
type: 'multiline', group: gettext('Advanced'), mode: ['properties'],
type: 'multiline', group: 'advanced', mode: ['properties'],
}],
validate: function() {
var msg,

View File

@@ -0,0 +1,6 @@
SELECT 'pg_catalog.' || quote_ident(collate_setting.value) AS copy_collation
FROM (
SELECT setting AS value
FROM pg_settings
WHERE name='lc_collate'
) collate_setting;

View File

@@ -0,0 +1,6 @@
SELECT 'pg_catalog.' || quote_ident(collate_setting.value) AS copy_collation
FROM (
SELECT setting AS value
FROM pg_settings
WHERE name='lc_collate'
) collate_setting

View File

@@ -92,10 +92,13 @@ TABLESPACE {{ conn|qtIdent(data.spcname) }}
{### SQL for Distribution ###}
{% if data.distribution %}
DISTRIBUTED BY ({% for attrnum in data.distribution %}{% if loop.index != 1 %}, {% endif %}{{ data.columns[attrnum-1].name }}{% endfor %})
{% elif data.primary_key|length > 0 %}
DISTRIBUTED BY ({% for c in data.primary_key[0].columns%}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.column)}}{% endfor %})
{% else %}
DISTRIBUTED RANDOMLY
{% endif %}
{% if data.is_partitioned %} PARTITION BY {{ data.partition_scheme }}; {% endif %}
;
{### Alter SQL for Owner ###}
{% if data.relowner %}

View File

@@ -0,0 +1,122 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import os
import re
from flask import Flask, render_template
from jinja2 import FileSystemLoader, ChoiceLoader
from config import PG_DEFAULT_DRIVER
from pgadmin import VersionedTemplateLoader
from pgadmin.utils.driver import get_driver
from pgadmin.utils.route import BaseTestGenerator
class TestTemplateCreate(BaseTestGenerator):
scenarios = [
(
'When rendering GreenPlum 5.3 template, '
'when no distribution is present, '
'when no primary key is present, '
'it returns "DISTRIBUTED RANDOMLY"',
dict(
template_path=os.path.join('table', 'sql', 'gpdb_5.0_plus', 'create.sql'),
input_parameters=dict(
data=dict()
),
expected_in_return_value='DISTRIBUTED RANDOMLY',
expected_not_in_return_value='DISTRIBUTED BY '
)
),
(
'When rendering GreenPlum 5.3 template, '
'when no distribution is present, '
'when primary key is present, '
'it returns "DISTRIBUTED BY (attr_primary_key)"',
dict(
template_path=os.path.join('table', 'sql', 'gpdb_5.0_plus', 'create.sql'),
input_parameters=dict(
data=dict(
primary_key=[
dict(
columns=[dict(
column='attr_primary_key_column_1'
), dict(
column='attr_primary_key_column_2'
)]
)
]
)
),
expected_in_return_value='DISTRIBUTED BY (attr_primary_key_column_1, attr_primary_key_column_2)',
expected_not_in_return_value='DISTRIBUTED RANDOMLY'
)
),
(
'When rendering GreenPlum 5.3 template, '
'when distribution is present, '
'it returns "DISTRIBUTED BY (attr1, attr2, attr4)"',
dict(
template_path=os.path.join('table', 'sql', 'gpdb_5.0_plus', 'create.sql'),
input_parameters=dict(
data=dict(
distribution=[1, 2, 4],
columns=[
{'name': 'attr1'},
{'name': 'attr2'},
{'name': 'attr3'},
{'name': 'attr4'},
{'name': 'attr5'},
]
)
),
expected_in_return_value='DISTRIBUTED BY (attr1, attr2, attr4)',
expected_not_in_return_value='DISTRIBUTED RANDOMLY'
)
),
]
def setUp(self):
self.loader = VersionedTemplateLoader(FakeApp())
def runTest(self):
with FakeApp().app_context():
result = render_template(self.template_path, **self.input_parameters)
result_beautified = re.sub(' +', ' ', str(result).replace("\n", " ").strip())
if hasattr(self, 'expected_return_value'):
self.assertEqual(result_beautified, self.expected_return_value)
if hasattr(self, 'expected_in_return_value'):
self.assertIn(self.expected_in_return_value, result_beautified)
if hasattr(self, 'expected_not_in_return_value'):
self.assertNotIn(self.expected_not_in_return_value, result_beautified)
class FakeApp(Flask):
def __init__(self):
super(FakeApp, self).__init__('')
driver = get_driver(PG_DEFAULT_DRIVER, self)
self.jinja_env.filters['qtLiteral'] = driver.qtLiteral
self.jinja_env.filters['qtIdent'] = driver.qtIdent
self.jinja_env.filters['qtTypeIdent'] = driver.qtTypeIdent
self.jinja_loader = ChoiceLoader([
FileSystemLoader(
os.path.dirname(os.path.realpath(__file__)) + '/../templates/'
),
FileSystemLoader(
os.path.dirname(os.path.realpath(__file__)) + '/../../templates/'
),
FileSystemLoader(
os.path.dirname(os.path.realpath(__file__)) + '/../../types/templates/'
),
FileSystemLoader(
os.path.dirname(os.path.realpath(__file__)) + '/../../../../templates/'
),
]
)

View File

@@ -15,14 +15,14 @@ FROM
(NOT (typname = 'unknown' AND nspname = 'pg_catalog'))
AND
{{ condition }}
AND (
typnamespace = {{ schema_oid }}::oid
OR nsp.nspname = 'pg_catalog'
)
{% if add_serials %}
{# Here we will add serials types manually #}
UNION SELECT 'smallserial', 0, 2, 'b', 0, 'pg_catalog', false, false
UNION SELECT 'bigserial', 0, 8, 'b', 0, 'pg_catalog', false, false
UNION SELECT 'serial', 0, 4, 'b', 0, 'pg_catalog', false, false
{% endif %}
AND (
typnamespace = {{schema_oid}}::oid
OR nsp.nspname = 'pg_catalog'
)) AS dummy
{% endif %}) AS dummy
ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1

View File

@@ -0,0 +1,6 @@
SELECT 'pg_catalog.' || quote_ident(collate_setting.value) AS copy_collation
FROM (
SELECT setting AS value
FROM pg_settings
WHERE name='lc_collate'
) collate_setting;