Fix exclusion constraint support on 9.6. Fixes #1875

This commit is contained in:
Harshal Dhumal 2016-10-21 16:14:19 +01:00 committed by Dave Page
parent 23a0fc2f22
commit 2952faab5e
21 changed files with 212 additions and 6 deletions

View File

@ -290,7 +290,11 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
self.template_path = 'table/sql/9.1_plus'
# Template for Column ,check constraint and exclusion constraint node
if ver >= 90200:
if ver >= 90600:
self.column_template_path = 'column/sql/9.2_plus'
self.check_constraint_template_path = 'check_constraint/sql/9.2_plus'
self.exclusion_constraint_template_path = 'exclusion_constraint/sql/9.6_plus'
elif ver >= 90200:
self.column_template_path = 'column/sql/9.2_plus'
self.check_constraint_template_path = 'check_constraint/sql/9.2_plus'
self.exclusion_constraint_template_path = 'exclusion_constraint/sql/9.2_plus'

View File

@ -217,7 +217,9 @@ class ExclusionConstraintView(PGChildNodeView):
self.conn = self.manager.connection(did=kwargs['did'])
ver = self.manager.version
if ver >= 90200:
if ver >= 90600:
self.template_path = 'exclusion_constraint/sql/9.6_plus'
elif ver >= 90200:
self.template_path = 'exclusion_constraint/sql/9.2_plus'
elif ver >= 90100:
self.template_path = 'exclusion_constraint/sql/9.1_plus'

View File

@ -700,8 +700,14 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
if (column_collection.length > 0 && current_am != previous_am) {
var msg = '{{ _('Changing access method will clear columns collection') }}';
Alertify.confirm(msg, function (e) {
// User clicks Ok, lets clear collection
column_collection.reset();
// User clicks Ok, lets clear collection.
column_collection.each(function(m) {
/*
* Our datamodel do not support collection reset method.
* So remove model one by one.
*/
column_collection.remove(m);
});
setTimeout(function() {
column_collection.trigger('pgadmin:columns:updated', column_collection);
}, 10);

View File

@ -2,5 +2,5 @@ SELECT ct.oid,
ct.conname as name,
NOT convalidated as convalidated
FROM pg_constraint ct
WHERE contype='f' AND
WHERE contype='x' AND
conrelid = {{tid}}::oid LIMIT 1;

View File

@ -2,5 +2,5 @@ SELECT ct.oid,
ct.conname as name,
NOT convalidated as convalidated
FROM pg_constraint ct
WHERE contype='f' AND
WHERE contype='x' AND
conrelid = {{tid}}::oid LIMIT 1;

View File

@ -0,0 +1,17 @@
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} (
{% for col in data.columns %}{% if loop.index != 1 %},
{% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %}
WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %}
USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}
{% if data.condeferrable %}
DEFERRABLE{% if data.condeferred %}
INITIALLY DEFERRED{% endif%}
{% endif%}{% if data.constraint %} WHERE ({{data.constraint}}){% endif%};
{% if data.comment and data.name %}
COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
IS {{ data.comment|qtLiteral }};
{% endif %}

View File

@ -0,0 +1,3 @@
{% if data %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
{% endif %}

View File

@ -0,0 +1,6 @@
SELECT amname
FROM pg_am
WHERE EXISTS (SELECT 1
FROM pg_proc
WHERE oid=amhandler)
ORDER BY amname;

View File

@ -0,0 +1,22 @@
{% for n in range(colcnt|int) %}
{% if loop.index != 1 %}
UNION
{% endif %}
SELECT
i.indoption[{{loop.index -1}}] AS options,
pg_get_indexdef(i.indexrelid, {{loop.index}}, true) AS coldef,
op.oprname,
CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname
,
coll.collname,
nspc.nspname as collnspname,
format_type(ty.oid,NULL) AS datatype
FROM pg_index i
JOIN pg_attribute a ON (a.attrelid = i.indexrelid AND attnum = {{loop.index}})
JOIN pg_type ty ON ty.oid=a.atttypid
LEFT OUTER JOIN pg_opclass o ON (o.oid = i.indclass[{{loop.index -1}}])
LEFT OUTER JOIN pg_constraint c ON (c.conindid = i.indexrelid) LEFT OUTER JOIN pg_operator op ON (op.oid = c.conexclop[{{loop.index}}])
LEFT OUTER JOIN pg_collation coll ON a.attcollation=coll.oid
LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
WHERE i.indexrelid = {{cid}}::oid
{% endfor %}

View File

@ -0,0 +1,3 @@
SELECT conname as name
FROM pg_constraint ct
WHERE ct.conindid = {{cid}}::oid

View File

@ -0,0 +1,4 @@
SELECT ct.oid
FROM pg_constraint ct
WHERE contype='x' AND
ct.conname = {{ name|qtLiteral }};

View File

@ -0,0 +1,6 @@
SELECT ct.oid,
ct.conname as name,
NOT convalidated as convalidated
FROM pg_constraint ct
WHERE contype='x' AND
conrelid = {{tid}}::oid LIMIT 1;

View File

@ -0,0 +1,7 @@
SELECT opcname
FROM pg_opclass opc,
pg_am am
WHERE opcmethod=am.oid AND
am.amname ={{indextype|qtLiteral}} AND
NOT opcdefault
ORDER BY 1

View File

@ -0,0 +1,30 @@
SELECT DISTINCT op.oprname as oprname
FROM pg_operator op,
( SELECT oid
FROM (SELECT format_type(t.oid,NULL) AS typname,
t.oid as oid
FROM pg_type t
JOIN pg_namespace nsp ON typnamespace=nsp.oid
WHERE (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) AND
typisdefined AND
typtype IN ('b', 'c', 'd', 'e', 'r') AND
NOT EXISTS (SELECT 1
FROM pg_class
WHERE relnamespace=typnamespace AND
relname = typname AND
relkind != 'c') AND
(typname NOT LIKE '_%' OR
NOT EXISTS (SELECT 1
FROM pg_class
WHERE relnamespace=typnamespace AND
relname = SUBSTRING(typname FROM 2)::name AND
relkind != 'c'))
{% if not show_sysobj %}
AND nsp.nspname != 'information_schema'
{% endif %}
UNION SELECT 'smallserial', 0
UNION SELECT 'bigserial', 0
UNION SELECT 'serial', 0) t1
WHERE typname = {{type|qtLiteral}}) AS types
WHERE oprcom > 0 AND
(op.oprleft=types.oid OR op.oprright=types.oid)

View File

@ -0,0 +1,7 @@
SELECT nsp.nspname AS schema,
rel.relname AS table
FROM
pg_class rel
JOIN pg_namespace nsp
ON rel.relnamespace = nsp.oid::int
WHERE rel.oid = {{tid}}::int

View File

@ -0,0 +1,7 @@
SELECT conindid as oid,
conname as name,
NOT convalidated as convalidated
FROM pg_constraint ct
WHERE contype='x' AND
conrelid = {{tid}}::oid
ORDER BY conname

View File

@ -0,0 +1,30 @@
SELECT cls.oid,
cls.relname as name,
indnatts,
amname,
COALESCE(spcname, 'pg_default') as spcname,
CASE contype
WHEN 'p' THEN desp.description
WHEN 'u' THEN desp.description
WHEN 'x' THEN desp.description
ELSE des.description
END AS comment,
condeferrable,
condeferred,
substring(array_to_string(cls.reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
JOIN pg_namespace n ON n.oid=tab.relnamespace
JOIN pg_am am ON am.oid=cls.relam
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
WHERE indrelid = {{tid}}::oid
{% if cid %}
AND cls.oid = {{cid}}::oid
{% endif %}
AND contype='x'
ORDER BY cls.relname

View File

@ -0,0 +1,28 @@
SELECT
idx_scan AS {{ conn|qtIdent(_('Index scans')) }},
idx_tup_read AS {{ conn|qtIdent(_('Index tuples read')) }},
idx_tup_fetch AS {{ conn|qtIdent(_('Index tuples fetched')) }},
idx_blks_read AS {{ conn|qtIdent(_('Index blocks read')) }},
idx_blks_hit AS {{ conn|qtIdent(_('Index blocks hit')) }},
pg_size_pretty(pg_relation_size({{ exid }}::OID)) AS {{ conn|qtIdent(_('Index size')) }}
{#=== Extended stats ===#}
{% if is_pgstattuple %}
,version AS {{ conn|qtIdent(_('Version')) }},
tree_level AS {{ conn|qtIdent(_('Tree level')) }},
pg_size_pretty(index_size) AS {{ conn|qtIdent(_('Index size')) }},
root_block_no AS {{ conn|qtIdent(_('Root block no')) }},
internal_pages AS {{ conn|qtIdent(_('Internal pages')) }},
leaf_pages AS {{ conn|qtIdent(_('Leaf pages')) }},
empty_pages AS {{ conn|qtIdent(_('Empty pages')) }},
deleted_pages AS {{ conn|qtIdent(_('Deleted pages')) }},
avg_leaf_density AS {{ conn|qtIdent(_('Average leaf density')) }},
leaf_fragmentation AS {{ conn|qtIdent(_('Leaf fragmentation')) }}
FROM
pgstatindex('{{conn|qtIdent(schema)}}.{{conn|qtIdent(name)}}'), pg_stat_all_indexes stat
{% else %}
FROM
pg_stat_all_indexes stat
{% endif %}
JOIN pg_statio_all_indexes statio ON stat.indexrelid = statio.indexrelid
JOIN pg_class cl ON cl.oid=stat.indexrelid
WHERE stat.indexrelid = {{ exid }}::OID

View File

@ -0,0 +1,22 @@
{### SQL to update exclusion constraint object ###}
{% if data %}
{# ==== To update exclusion constraint name ==== #}
{% if data.name != o_data.name %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};
{% endif %}
{# ==== To update exclusion constraint tablespace ==== #}
{% if data.spcname and data.spcname != o_data.spcname %}
ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
SET TABLESPACE {{ conn|qtIdent(data.spcname) }};
{% endif %}
{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
SET (FILLFACTOR={{ data.fillfactor }});
{% endif %}
{# ==== To update exclusion constraint comments ==== #}
{% if data.comment is defined and data.comment != o_data.comment %}
COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
IS {{ data.comment|qtLiteral }};
{% endif %}
{% endif %}