mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-01-09 23:54:09 -06:00
Display partitions in Greenplum. Fixes #3036
This commit is contained in:
parent
8df006343b
commit
678699c408
@ -733,6 +733,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
|
||||
"/".join([self.table_template_path, 'get_inherits.sql']),
|
||||
show_system_objects=self.blueprint.show_system_objects,
|
||||
tid=tid,
|
||||
scid=scid,
|
||||
server_type=self.manager.server_type
|
||||
)
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
|
@ -16,6 +16,7 @@ import pgadmin.browser.server_groups.servers.databases as database
|
||||
from flask import render_template, request, jsonify
|
||||
from flask_babel import gettext
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.partitions import backend_supported
|
||||
from pgadmin.browser.utils import PGChildNodeView
|
||||
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
||||
make_response as ajax_response, gone
|
||||
@ -74,17 +75,7 @@ class IndexesModule(CollectionNodeModule):
|
||||
|
||||
# In case of partitioned table return false.
|
||||
if 'tid' in kwargs and manager.version >= 100000:
|
||||
partition_path = 'partition/sql/#{0}#'.format(manager.version)
|
||||
SQL = render_template(
|
||||
"/".join([partition_path, 'backend_support.sql']),
|
||||
tid=kwargs['tid']
|
||||
)
|
||||
status, res = conn.execute_scalar(SQL)
|
||||
|
||||
# check if any errors
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
return not res
|
||||
return backend_supported(self, manager, **kwargs)
|
||||
|
||||
if 'vid' not in kwargs:
|
||||
return True
|
||||
|
@ -26,6 +26,21 @@ from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.browser.utils import PGChildModule
|
||||
|
||||
|
||||
def backend_supported(module, manager, **kwargs):
|
||||
if 'tid' in kwargs and CollectionNodeModule.BackendSupported(module, manager, **kwargs):
|
||||
conn = manager.connection(did=kwargs['did'])
|
||||
|
||||
template_path = 'partition/sql/{0}/#{0}#{1}#'.format(manager.server_type, manager.version)
|
||||
SQL = render_template("/".join(
|
||||
[template_path, 'backend_support.sql']), tid=kwargs['tid'])
|
||||
status, res = conn.execute_scalar(SQL)
|
||||
|
||||
# check if any errors
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
return res
|
||||
|
||||
class PartitionsModule(CollectionNodeModule):
|
||||
"""
|
||||
class PartitionsModule(CollectionNodeModule)
|
||||
@ -88,21 +103,7 @@ class PartitionsModule(CollectionNodeModule):
|
||||
"""
|
||||
Load this module if it is a partition table
|
||||
"""
|
||||
if manager.server_type == 'gpdb':
|
||||
return False
|
||||
if 'tid' in kwargs and CollectionNodeModule.BackendSupported(self, manager, **kwargs):
|
||||
conn = manager.connection(did=kwargs['did'])
|
||||
|
||||
template_path = 'partition/sql/#{0}#'.format(manager.version)
|
||||
SQL = render_template("/".join(
|
||||
[template_path, 'backend_support.sql']), tid=kwargs['tid'])
|
||||
status, res = conn.execute_scalar(SQL)
|
||||
|
||||
# check if any errors
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
return res
|
||||
return backend_supported(self, manager, **kwargs)
|
||||
|
||||
def register(self, app, options, first_registration=False):
|
||||
"""
|
||||
|
@ -0,0 +1,113 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import sys
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.partitions import PartitionsModule
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
|
||||
if sys.version_info < (3, 3):
|
||||
from mock import patch, Mock, call
|
||||
else:
|
||||
from unittest.mock import patch, Mock, call
|
||||
|
||||
|
||||
class TestBackendSupport(BaseTestGenerator):
|
||||
scenarios = [
|
||||
('when tid is not present in arguments, should return None and no query should be done',
|
||||
dict(
|
||||
manager=dict(
|
||||
server_type="",
|
||||
version=""
|
||||
),
|
||||
input_arguments=dict(did=432),
|
||||
|
||||
collection_node_active=True,
|
||||
connection_execution_return_value=[],
|
||||
|
||||
expected_return_value=None,
|
||||
expect_error_response=False,
|
||||
expected_number_calls_on_render_template=0
|
||||
)),
|
||||
('when tid is present in arguments and CollectionNodeModule does not support, '
|
||||
'should return None and no query should be done',
|
||||
dict(
|
||||
manager=dict(
|
||||
server_type="",
|
||||
version=""
|
||||
),
|
||||
input_arguments=dict(did=432, tid=123),
|
||||
|
||||
collection_node_active=False,
|
||||
connection_execution_return_value=[],
|
||||
|
||||
expected_return_value=None,
|
||||
expect_error_response=False,
|
||||
expected_number_calls_on_render_template=0
|
||||
)),
|
||||
('when table is partitioned, '
|
||||
'should return the table identifier',
|
||||
dict(
|
||||
manager=dict(
|
||||
server_type="gpdb",
|
||||
version="5"
|
||||
),
|
||||
input_arguments=dict(did=432, tid=123),
|
||||
|
||||
collection_node_active=True,
|
||||
connection_execution_return_value=[True, 123],
|
||||
|
||||
expected_return_value=123,
|
||||
expect_error_response=False,
|
||||
expected_number_calls_on_render_template=1,
|
||||
expect_render_template_to_be_called_with=call('partition/sql/gpdb/#gpdb#5#/backend_support.sql', tid=123)
|
||||
)),
|
||||
('when error happens while querying the database, '
|
||||
'should return an internal server error',
|
||||
dict(
|
||||
manager=dict(
|
||||
server_type="pg",
|
||||
version="10"
|
||||
),
|
||||
input_arguments=dict(did=432, tid=123),
|
||||
|
||||
collection_node_active=True,
|
||||
connection_execution_return_value=[False, "Some ugly error"],
|
||||
|
||||
expected_return_value=None,
|
||||
expect_error_response=True,
|
||||
expected_number_calls_on_render_template=1,
|
||||
expect_render_template_to_be_called_with=call('partition/sql/pg/#pg#10#/backend_support.sql', tid=123)
|
||||
))
|
||||
]
|
||||
|
||||
@patch('pgadmin.browser.server_groups.servers.databases.schemas.tables.partitions.internal_server_error')
|
||||
@patch('pgadmin.browser.server_groups.servers.databases.schemas.tables.partitions.CollectionNodeModule')
|
||||
@patch('pgadmin.browser.server_groups.servers.databases.schemas.tables.partitions.render_template')
|
||||
def runTest(self, render_template_mock, CollectionNodeModule_mock, internal_server_error_mock):
|
||||
module = PartitionsModule("partition")
|
||||
module.manager = Mock()
|
||||
module.manager.server_type = self.manager['server_type']
|
||||
module.manager.version = self.manager['version']
|
||||
connection_mock = Mock()
|
||||
connection_mock.execute_scalar.return_value = self.connection_execution_return_value
|
||||
module.manager.connection.return_value = connection_mock
|
||||
CollectionNodeModule_mock.BackendSupported.return_value = self.collection_node_active
|
||||
|
||||
result = module.BackendSupported(module.manager, **self.input_arguments)
|
||||
|
||||
if self.expected_number_calls_on_render_template == 0:
|
||||
render_template_mock.assert_not_called()
|
||||
else:
|
||||
render_template_mock.assert_has_calls([self.expect_render_template_to_be_called_with])
|
||||
|
||||
if self.expect_error_response:
|
||||
internal_server_error_mock.assert_called_with(errormsg=self.connection_execution_return_value[1])
|
||||
else:
|
||||
self.assertEqual(result, self.expected_return_value)
|
@ -0,0 +1,6 @@
|
||||
SELECT ct.conindid AS oid,
|
||||
ct.conname AS name,
|
||||
NOT convalidated AS convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='x' AND
|
||||
conrelid = {{tid}}::oid LIMIT 1;
|
@ -0,0 +1,10 @@
|
||||
SELECT conindid as oid,
|
||||
conname as name,
|
||||
NOT convalidated as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='x' AND
|
||||
conrelid = {{tid}}::oid
|
||||
{% if exid %}
|
||||
AND conindid = {{exid}}::oid
|
||||
{% endif %}
|
||||
ORDER BY conname
|
@ -1,6 +1,6 @@
|
||||
SELECT ct.conindid AS oid,
|
||||
ct.conname AS name,
|
||||
NOT convalidated AS convalidated
|
||||
true AS convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='x' AND
|
||||
conrelid = {{tid}}::oid LIMIT 1;
|
||||
conrelid = {{tid}}::oid LIMIT 1;
|
||||
|
@ -1,10 +1,3 @@
|
||||
SELECT conindid as oid,
|
||||
conname as name,
|
||||
NOT convalidated as convalidated
|
||||
SELECT '' AS oid, '' AS conname, '' AS convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='x' AND
|
||||
conrelid = {{tid}}::oid
|
||||
{% if exid %}
|
||||
AND conindid = {{exid}}::oid
|
||||
{% endif %}
|
||||
ORDER BY conname
|
||||
WHERE false
|
||||
|
@ -0,0 +1,5 @@
|
||||
SELECT ct.oid,
|
||||
NOT convalidated as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='f' AND
|
||||
ct.conname = {{ name|qtLiteral }};
|
@ -0,0 +1,6 @@
|
||||
SELECT ct.oid,
|
||||
ct.conname as name,
|
||||
NOT convalidated as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='f' AND
|
||||
conrelid = {{tid}}::oid LIMIT 1;
|
@ -0,0 +1,7 @@
|
||||
SELECT ct.oid,
|
||||
conname as name,
|
||||
NOT convalidated as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='f' AND
|
||||
conrelid = {{tid}}::oid
|
||||
ORDER BY conname
|
@ -1,5 +1,5 @@
|
||||
SELECT ct.oid,
|
||||
NOT convalidated as convalidated
|
||||
true as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='f' AND
|
||||
ct.conname = {{ name|qtLiteral }};
|
||||
ct.conname = {{ name|qtLiteral }};
|
||||
|
@ -1,6 +1,6 @@
|
||||
SELECT ct.oid,
|
||||
ct.conname as name,
|
||||
NOT convalidated as convalidated
|
||||
true as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='f' AND
|
||||
conrelid = {{tid}}::oid LIMIT 1;
|
||||
conrelid = {{tid}}::oid LIMIT 1;
|
||||
|
@ -1,6 +1,6 @@
|
||||
SELECT ct.oid,
|
||||
conname as name,
|
||||
NOT convalidated as convalidated
|
||||
true as convalidated
|
||||
FROM pg_constraint ct
|
||||
WHERE contype='f' AND
|
||||
conrelid = {{tid}}::oid
|
||||
|
@ -0,0 +1,9 @@
|
||||
SELECT CASE WHEN number_of_rows > 0
|
||||
THEN TRUE
|
||||
ELSE FALSE END AS ptable
|
||||
FROM (
|
||||
SELECT count(*) AS number_of_rows
|
||||
FROM pg_class
|
||||
INNER JOIN pg_partitions ON relname = tablename
|
||||
WHERE pg_class.oid = {{ tid }}::oid
|
||||
) AS number_of_partitions
|
@ -0,0 +1,39 @@
|
||||
SELECT
|
||||
table_class.oid,
|
||||
partitions.partitiontablename AS name,
|
||||
(SELECT count(*)
|
||||
FROM pg_trigger
|
||||
WHERE tgrelid = table_class.oid AND tgisconstraint = FALSE) AS triggercount,
|
||||
(SELECT count(*)
|
||||
FROM pg_trigger
|
||||
WHERE tgrelid = table_class.oid AND tgisconstraint = FALSE AND tgenabled = 'O') AS has_enable_triggers,
|
||||
partitions.partitionboundary AS partition_value,
|
||||
partitions.partitionschemaname AS schema_id,
|
||||
schema_name,
|
||||
CASE WHEN sub_partitions.n > 0
|
||||
THEN TRUE
|
||||
ELSE FALSE END is_partitioned,
|
||||
'' AS partition_scheme
|
||||
FROM
|
||||
(SELECT
|
||||
table_class.relnamespace,
|
||||
nsp.nspname AS schema_name,
|
||||
partitions.partitiontablename,
|
||||
partitions.partitionboundary,
|
||||
partitions.partitionschemaname
|
||||
FROM pg_class table_class
|
||||
INNER JOIN pg_partitions partitions
|
||||
ON (relname = tablename AND parentpartitiontablename IS NULL) OR relname = parentpartitiontablename
|
||||
LEFT JOIN pg_namespace nsp ON table_class.relnamespace = nsp.oid
|
||||
WHERE
|
||||
{% if ptid %} table_class.oid = {{ ptid }}::OID {% endif %}
|
||||
{% if not ptid %} table_class.oid = {{ tid }}::OID {% endif %}
|
||||
) AS partitions
|
||||
LEFT JOIN (SELECT
|
||||
parentpartitiontablename,
|
||||
count(*) AS n
|
||||
FROM pg_partitions
|
||||
GROUP BY parentpartitiontablename) sub_partitions
|
||||
ON partitions.partitiontablename = sub_partitions.parentpartitiontablename
|
||||
LEFT JOIN pg_class table_class ON partitions.relnamespace = table_class.relnamespace AND partitions.partitiontablename = table_class.relname
|
||||
ORDER BY partitions.partitiontablename;
|
@ -0,0 +1,85 @@
|
||||
SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
|
||||
(CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE
|
||||
(SELECT sp.spcname FROM pg_database dtb
|
||||
JOIN pg_tablespace sp ON dtb.dattablespace=sp.oid
|
||||
WHERE dtb.oid = {{ did }}::oid)
|
||||
END) as spcname,
|
||||
(select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as parent_schema,
|
||||
nsp.nspname as schema,
|
||||
pg_get_userbyid(rel.relowner) AS relowner, rel.relhasoids,
|
||||
(CASE WHEN partitions.number_of_partitions > 0 THEN true ELSE false END) AS relispartition,
|
||||
rel.relhassubclass, rel.reltuples::bigint, des.description, con.conname, con.conkey,
|
||||
EXISTS(select 1 FROM pg_trigger
|
||||
JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
|
||||
JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
|
||||
WHERE tgrelid=rel.oid) AS isrepl,
|
||||
(SELECT count(*)
|
||||
FROM pg_trigger
|
||||
WHERE tgrelid = rel.oid AND tgisconstraint = FALSE) AS triggercount,
|
||||
(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE 'pg\_%') THEN
|
||||
quote_ident(nspname)||'.'||quote_ident(c.relname)
|
||||
ELSE quote_ident(c.relname) END AS inherited_tables
|
||||
FROM pg_inherits i
|
||||
JOIN pg_class c ON c.oid = i.inhparent
|
||||
JOIN pg_namespace n ON n.oid=c.relnamespace
|
||||
WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
|
||||
(SELECT count(*)
|
||||
FROM pg_inherits i
|
||||
JOIN pg_class c ON c.oid = i.inhparent
|
||||
JOIN pg_namespace n ON n.oid=c.relnamespace
|
||||
WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
|
||||
false AS relpersistence,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
|
||||
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
|
||||
THEN true ELSE false END) AS autovacuum_enabled,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
|
||||
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
|
||||
THEN true ELSE false END) AS toast_autovacuum_enabled,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||
array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
|
||||
array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
|
||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reltype, typ.typname,
|
||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||
-- Added for pgAdmin4
|
||||
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean THEN true ELSE false END) AS autovacuum_custom,
|
||||
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
|
||||
NULL AS seclabels,
|
||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table,
|
||||
-- Added for partition table
|
||||
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
|
||||
'' AS partition_scheme,
|
||||
{% if ptid %}
|
||||
(CASE WHEN partitions.number_of_partitions > 0 THEN partitions.expression ELSE '' END) AS partition_value,
|
||||
(SELECT relname FROM pg_class WHERE oid = {{ tid }}::oid) AS partitioned_table_name
|
||||
{% else %}
|
||||
partitions.expression AS partition_value
|
||||
{% endif %}
|
||||
|
||||
FROM pg_class rel
|
||||
LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
|
||||
LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
|
||||
LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
|
||||
LEFT JOIN pg_type typ ON rel.reltype=typ.oid
|
||||
LEFT JOIN pg_inherits inh ON inh.inhrelid = rel.oid
|
||||
LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
|
||||
LEFT JOIN (SELECT tablename, partitionboundary as expression, count(*) number_of_partitions FROM pg_partitions GROUP BY tablename, expression) partitions ON rel.relname = tablename
|
||||
WHERE inh.inhparent = {{ tid }}::oid
|
||||
{% if ptid %} AND rel.oid = {{ ptid }}::oid {% endif %}
|
||||
ORDER BY rel.relname;
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}} ATTACH PARTITION {{conn|qtIdent(data.schema, data.name)}}
|
||||
{{ data.partition_value }};
|
@ -0,0 +1,36 @@
|
||||
{% import 'table/sql/macros/constraints.macro' as CONSTRAINTS %}
|
||||
{#===========================================#}
|
||||
{#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
|
||||
{#===========================================#}
|
||||
{### CREATE TABLE STATEMENT FOR partitions ###}
|
||||
CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{% if data.relispartition is defined and data.relispartition %} PARTITION OF {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}}{% endif %}
|
||||
|
||||
{# Macro to render for constraints #}
|
||||
{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
|
||||
( {% endif %}
|
||||
{% if data.primary_key|length > 0 %}{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.primary_key|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.FOREIGN_KEY(conn, data.foreign_key)}}{% endif %}{% if data.check_constraint|length > 0 %}{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.CHECK(conn, data.check_constraint)}}{% endif %}{% if data.exclude_constraint|length > 0 %}{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.EXCLUDE(conn, data.exclude_constraint)}}{% endif %}
|
||||
{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
|
||||
|
||||
)
|
||||
{% endif %}
|
||||
{{ data.partition_value }}{% if data.is_partitioned is defined and data.is_partitioned %}
|
||||
|
||||
PARTITION BY {{ data.partition_scheme }}{% endif %}
|
||||
{### SQL for Tablespace ###}
|
||||
{% if data.spcname %}
|
||||
|
||||
TABLESPACE {{ conn|qtIdent(data.spcname) }};
|
||||
{% else %}
|
||||
;
|
||||
|
||||
{% endif %}
|
||||
{### Alter SQL for Owner ###}
|
||||
{% if data.relowner %}
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
OWNER to {{conn|qtIdent(data.relowner)}};
|
||||
{% endif %}
|
@ -0,0 +1 @@
|
||||
ALTER TABLE {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}} DETACH PARTITION {{conn|qtIdent(data.schema, data.name)}};
|
@ -0,0 +1,23 @@
|
||||
SELECT oid, quote_ident(nspname)||'.'||quote_ident(relname) AS table_name FROM
|
||||
(SELECT
|
||||
r.oid, r.relname, n.nspname, array_agg(a.attname) attnames, array_agg(a.atttypid) atttypes
|
||||
FROM
|
||||
(SELECT oid, relname, relnamespace FROM pg_catalog.pg_class
|
||||
WHERE relkind in ('r', 'p') AND NOT relispartition) r
|
||||
JOIN (SELECT oid AS nspoid, nspname FROM
|
||||
pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%') n
|
||||
ON (r.relnamespace = n.nspoid)
|
||||
JOIN (SELECT attrelid, attname, atttypid FROM
|
||||
pg_catalog.pg_attribute WHERE attnum > 0 ORDER BY attrelid, attnum) a
|
||||
ON (r.oid = a.attrelid)
|
||||
GROUP BY r.oid, r.relname, r.relnamespace, n.nspname) all_tables
|
||||
JOIN
|
||||
(SELECT
|
||||
attrelid, array_agg(attname) attnames, array_agg(atttypid) atttypes
|
||||
FROM
|
||||
(SELECT * FROM pg_catalog.pg_attribute
|
||||
WHERE attrelid = {{ tid }} AND attnum > 0
|
||||
ORDER BY attrelid, attnum) attributes
|
||||
GROUP BY attrelid) current_table ON current_table.attrelid != all_tables.oid
|
||||
AND current_table.attnames = all_tables.attnames
|
||||
AND current_table.atttypes = all_tables.atttypes
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}} ATTACH PARTITION {{conn|qtIdent(data.schema, data.name)}}
|
||||
{{ data.partition_value }};
|
@ -0,0 +1,9 @@
|
||||
{#=============Checks if it is partitioned table========#}
|
||||
{% if tid %}
|
||||
SELECT
|
||||
CASE WHEN c.relkind = 'p' THEN True ELSE False END As ptable
|
||||
FROM
|
||||
pg_class c
|
||||
WHERE
|
||||
c.oid = {{ tid }}::oid
|
||||
{% endif %}
|
@ -0,0 +1,36 @@
|
||||
{% import 'table/sql/macros/constraints.macro' as CONSTRAINTS %}
|
||||
{#===========================================#}
|
||||
{#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
|
||||
{#===========================================#}
|
||||
{### CREATE TABLE STATEMENT FOR partitions ###}
|
||||
CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{% if data.relispartition is defined and data.relispartition %} PARTITION OF {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}}{% endif %}
|
||||
|
||||
{# Macro to render for constraints #}
|
||||
{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
|
||||
( {% endif %}
|
||||
{% if data.primary_key|length > 0 %}{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.primary_key|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.FOREIGN_KEY(conn, data.foreign_key)}}{% endif %}{% if data.check_constraint|length > 0 %}{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.CHECK(conn, data.check_constraint)}}{% endif %}{% if data.exclude_constraint|length > 0 %}{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 %},{% endif %}
|
||||
{{CONSTRAINTS.EXCLUDE(conn, data.exclude_constraint)}}{% endif %}
|
||||
{% if data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
|
||||
|
||||
)
|
||||
{% endif %}
|
||||
{{ data.partition_value }}{% if data.is_partitioned is defined and data.is_partitioned %}
|
||||
|
||||
PARTITION BY {{ data.partition_scheme }}{% endif %}
|
||||
{### SQL for Tablespace ###}
|
||||
{% if data.spcname %}
|
||||
|
||||
TABLESPACE {{ conn|qtIdent(data.spcname) }};
|
||||
{% else %}
|
||||
;
|
||||
|
||||
{% endif %}
|
||||
{### Alter SQL for Owner ###}
|
||||
{% if data.relowner %}
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
OWNER to {{conn|qtIdent(data.relowner)}};
|
||||
{% endif %}
|
@ -0,0 +1 @@
|
||||
ALTER TABLE {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}} DETACH PARTITION {{conn|qtIdent(data.schema, data.name)}};
|
@ -0,0 +1,23 @@
|
||||
SELECT oid, quote_ident(nspname)||'.'||quote_ident(relname) AS table_name FROM
|
||||
(SELECT
|
||||
r.oid, r.relname, n.nspname, array_agg(a.attname) attnames, array_agg(a.atttypid) atttypes
|
||||
FROM
|
||||
(SELECT oid, relname, relnamespace FROM pg_catalog.pg_class
|
||||
WHERE relkind in ('r', 'p') AND NOT relispartition) r
|
||||
JOIN (SELECT oid AS nspoid, nspname FROM
|
||||
pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%') n
|
||||
ON (r.relnamespace = n.nspoid)
|
||||
JOIN (SELECT attrelid, attname, atttypid FROM
|
||||
pg_catalog.pg_attribute WHERE attnum > 0 ORDER BY attrelid, attnum) a
|
||||
ON (r.oid = a.attrelid)
|
||||
GROUP BY r.oid, r.relname, r.relnamespace, n.nspname) all_tables
|
||||
JOIN
|
||||
(SELECT
|
||||
attrelid, array_agg(attname) attnames, array_agg(atttypid) atttypes
|
||||
FROM
|
||||
(SELECT * FROM pg_catalog.pg_attribute
|
||||
WHERE attrelid = {{ tid }} AND attnum > 0
|
||||
ORDER BY attrelid, attnum) attributes
|
||||
GROUP BY attrelid) current_table ON current_table.attrelid != all_tables.oid
|
||||
AND current_table.attnames = all_tables.attnames
|
||||
AND current_table.atttypes = all_tables.atttypes
|
@ -0,0 +1,15 @@
|
||||
SELECT rel.oid, rel.relname AS name,
|
||||
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
|
||||
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers,
|
||||
pg_get_expr(rel.relpartbound, rel.oid) AS partition_value,
|
||||
rel.relnamespace AS schema_id,
|
||||
nsp.nspname AS schema_name,
|
||||
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
|
||||
(CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme
|
||||
FROM
|
||||
(SELECT * FROM pg_inherits WHERE inhparent = {{ tid }}::oid) inh
|
||||
LEFT JOIN pg_class rel ON inh.inhrelid = rel.oid
|
||||
LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
|
||||
WHERE rel.relispartition
|
||||
{% if ptid %} AND rel.oid = {{ ptid }}::OID {% endif %}
|
||||
ORDER BY rel.relname;
|
@ -0,0 +1,82 @@
|
||||
SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
|
||||
(CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE
|
||||
(SELECT sp.spcname FROM pg_database dtb
|
||||
JOIN pg_tablespace sp ON dtb.dattablespace=sp.oid
|
||||
WHERE dtb.oid = {{ did }}::oid)
|
||||
END) as spcname,
|
||||
(select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as parent_schema,
|
||||
nsp.nspname as schema,
|
||||
pg_get_userbyid(rel.relowner) AS relowner, rel.relhasoids, rel.relispartition,
|
||||
rel.relhassubclass, rel.reltuples::bigint, des.description, con.conname, con.conkey,
|
||||
EXISTS(select 1 FROM pg_trigger
|
||||
JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
|
||||
JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
|
||||
WHERE tgrelid=rel.oid) AS isrepl,
|
||||
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
|
||||
(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE 'pg\_%') THEN
|
||||
quote_ident(nspname)||'.'||quote_ident(c.relname)
|
||||
ELSE quote_ident(c.relname) END AS inherited_tables
|
||||
FROM pg_inherits i
|
||||
JOIN pg_class c ON c.oid = i.inhparent
|
||||
JOIN pg_namespace n ON n.oid=c.relnamespace
|
||||
WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
|
||||
(SELECT count(*)
|
||||
FROM pg_inherits i
|
||||
JOIN pg_class c ON c.oid = i.inhparent
|
||||
JOIN pg_namespace n ON n.oid=c.relnamespace
|
||||
WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
|
||||
(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
|
||||
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
|
||||
THEN true ELSE false END) AS autovacuum_enabled,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
|
||||
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
|
||||
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
|
||||
THEN true ELSE false END) AS toast_autovacuum_enabled,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
|
||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||
array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
|
||||
array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
|
||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname,
|
||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||
-- Added for pgAdmin4
|
||||
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean THEN true ELSE false END) AS autovacuum_custom,
|
||||
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
|
||||
|
||||
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table,
|
||||
-- Added for partition table
|
||||
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
|
||||
(CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme,
|
||||
{% if ptid %}
|
||||
(CASE WHEN rel.relispartition THEN pg_get_expr(rel.relpartbound, {{ ptid }}::oid) ELSE '' END) AS partition_value,
|
||||
(SELECT relname FROM pg_class WHERE oid = {{ tid }}::oid) AS partitioned_table_name
|
||||
{% else %}
|
||||
pg_get_expr(rel.relpartbound, rel.oid) AS partition_value
|
||||
{% endif %}
|
||||
|
||||
FROM pg_class rel
|
||||
LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
|
||||
LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
|
||||
LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
|
||||
LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
|
||||
LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
|
||||
LEFT JOIN pg_inherits inh ON inh.inhrelid = rel.oid
|
||||
LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
|
||||
WHERE rel.relispartition AND inh.inhparent = {{ tid }}::oid
|
||||
{% if ptid %} AND rel.oid = {{ ptid }}::oid {% endif %}
|
||||
ORDER BY rel.relname;
|
@ -0,0 +1,17 @@
|
||||
{% import 'table/sql/macros/db_catalogs.macro' as CATALOG %}
|
||||
SELECT c.oid, c.relname , nspname,
|
||||
CASE WHEN nspname NOT LIKE 'pg\_%' THEN
|
||||
quote_ident(nspname)||'.'||quote_ident(c.relname)
|
||||
ELSE quote_ident(c.relname)
|
||||
END AS inherits
|
||||
FROM pg_class c
|
||||
JOIN pg_namespace n
|
||||
ON n.oid=c.relnamespace
|
||||
WHERE relkind='r'
|
||||
{% if not show_system_objects %}
|
||||
{{ CATALOG.VALID_CATALOGS(server_type) }}
|
||||
{% endif %}
|
||||
{% if tid %}
|
||||
AND c.oid != tid
|
||||
{% endif %}
|
||||
ORDER BY relnamespace, c.relname
|
@ -14,4 +14,5 @@ WHERE relkind='r'
|
||||
{% if tid %}
|
||||
AND c.oid != tid
|
||||
{% endif %}
|
||||
AND c.relnamespace = {{ scid }}
|
||||
ORDER BY relnamespace, c.relname
|
||||
|
@ -0,0 +1,10 @@
|
||||
SELECT rel.oid, rel.relname AS name,
|
||||
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid) AS triggercount,
|
||||
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgenabled = 'O') AS has_enable_triggers
|
||||
FROM pg_class rel
|
||||
WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
|
||||
AND rel.relname NOT IN (SELECT partitiontablename FROM pg_partitions)
|
||||
{% if tid %}
|
||||
AND rel.oid = {{tid}}::OID
|
||||
{% endif %}
|
||||
ORDER BY rel.relname;
|
@ -116,7 +116,7 @@ class BaseTableView(PGChildNodeView):
|
||||
if server_type == 'gpdb' else
|
||||
'#{0}#'.format(ver)
|
||||
)
|
||||
self.partition_template_path = 'partition/sql/#{0}#'.format(ver)
|
||||
self.partition_template_path = 'partition/sql/{0}/#{0}#{1}#'.format(server_type, ver)
|
||||
|
||||
# Template for Column ,check constraint and exclusion
|
||||
# constraint node
|
||||
@ -600,7 +600,8 @@ class BaseTableView(PGChildNodeView):
|
||||
# system columns
|
||||
SQL = render_template("/".join([self.table_template_path,
|
||||
'get_inherits.sql']),
|
||||
show_system_objects=False
|
||||
show_system_objects=False,
|
||||
scid=scid
|
||||
)
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
|
@ -29,6 +29,7 @@ class VersionedTemplateLoader(DispatchingJinjaLoader):
|
||||
|
||||
gpdb_versions = (
|
||||
{'name': "gpdb_5.0_plus", 'number': 80323},
|
||||
{'name': "5_plus", 'number': 80323},
|
||||
{'name': "default", 'number': 0}
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user