Support for the 'Refresh CONCURRENTLY' is applicable only on the

database server >= 9.4.
This commit is contained in:
Surinder Kumar 2016-05-30 17:01:02 +05:30 committed by Ashesh Vashi
parent 70cca42d61
commit 4aaa58352c
13 changed files with 563 additions and 68 deletions

View File

@ -36,7 +36,7 @@ from functools import wraps
This modules uses separate template paths for each respective node
- templates/view for View node
- templates/materialized_view for MaterializedView node
- templates/materialized_view for the materialized view node
[Each path contains node specific js files as well as sql template files.]
"""
@ -122,11 +122,10 @@ class ViewModule(SchemaChildModule):
return snippets
class MaterializedViewModule(ViewModule):
class MViewModule(ViewModule):
"""
class MaterializedViewModule(ViewModule)
A module class for the materialized view and view node derived
from ViewModule.
class MViewModule(ViewModule)
A module class for the materialized view node derived from ViewModule.
"""
NODE_TYPE = 'mview'
@ -134,20 +133,20 @@ class MaterializedViewModule(ViewModule):
def __init__(self, *args, **kwargs):
"""
Method is used to initialize the MaterializedViewModule and
Method is used to initialize the MViewModule and
it's base module.
Args:
*args:
**kwargs:
"""
super(MaterializedViewModule, self).__init__(*args, **kwargs)
super(MViewModule, self).__init__(*args, **kwargs)
self.min_ver = 90300
self.max_ver = None
view_blueprint = ViewModule(__name__)
mview_blueprint = MaterializedViewModule(
__name__)
mview_blueprint = MViewModule(__name__)
def check_precondition(f):
@ -240,9 +239,6 @@ class ViewNode(PGChildNodeView, VacuumSettings):
- This function will generate sql to show it in sql pane for the view
node.
* refresh_data(gid, sid, did, scid, vid):
- This function will refresh view object
* select_sql(gid, sid, did, scid, vid):
- Returns select sql for Object
@ -278,7 +274,6 @@ class ViewNode(PGChildNodeView, VacuumSettings):
'get': 'children'
}],
'delete': [{'delete': 'delete'}],
'refresh_data': [{'put': 'refresh_data'}, {'put': 'refresh_data'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -315,22 +310,24 @@ class ViewNode(PGChildNodeView, VacuumSettings):
"""
Returns the template path for PPAS servers.
"""
return 'ppas/9.3_plus'
return 'ppas/{0}'.format(
'9.4_plus' if ver >= 90400 else
'9.3_plus' if ver >= 90300 else
'9.2_plus' if ver >= 90200 else
'9.1_plus'
)
@staticmethod
def pg_template_path(ver):
"""
Returns the template path for PostgreSQL servers.
"""
if ver >= 90400:
return 'pg/9.4_plus'
elif ver >= 90300:
return 'pg/9.3_plus'
elif ver >= 90200:
return 'pg/9.2_plus'
elif ver >= 90100:
return 'pg/9.1_plus'
return 'pg/9.1_plus'
return 'pg/{0}'.format(
'9.4_plus' if ver >= 90400 else
'9.3_plus' if ver >= 90300 else
'9.2_plus' if ver >= 90200 else
'9.1_plus'
)
@check_precondition
def list(self, gid, sid, did, scid):
@ -1193,7 +1190,14 @@ class ViewNode(PGChildNodeView, VacuumSettings):
return ajax_response(response=sql)
class MaterializedViewNode(ViewNode, VacuumSettings):
# Override the operations for materialized view
mview_operations = {
'refresh_data': [{'put': 'refresh_data'}, {}]
}
mview_operations.update(ViewNode.operations)
class MViewNode(ViewNode, VacuumSettings):
"""
This class is responsible for generating routes for
materialized view node.
@ -1201,8 +1205,7 @@ class MaterializedViewNode(ViewNode, VacuumSettings):
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the MaterializedView
and it's base view.
- Method is used to initialize the MView and it's base view.
* module_js()
- This property defines (if javascript) exists for this node.
@ -1220,27 +1223,40 @@ class MaterializedViewNode(ViewNode, VacuumSettings):
* get_sql(data, scid)
- This function will generate sql from model data
* refresh_data(gid, sid, did, scid, vid):
- This function will refresh view object
"""
node_type = mview_blueprint.node_type
operations = mview_operations
def __init__(self, *args, **kwargs):
"""
Initialize the variables used by methods of ViewNode.
"""
super(MaterializedViewNode, self).__init__(*args, **kwargs)
super(MViewNode, self).__init__(*args, **kwargs)
self.template_initial = 'mview'
@staticmethod
def ppas_template_path(ver):
"""
Returns the template path for PostgreSQL servers.
"""
return 'ppas/{0}'.format(
'9.4_plus' if ver >= 90400 else
'9.3_plus'
)
@staticmethod
def pg_template_path(ver):
"""
Returns the template path for PostgreSQL servers.
"""
if ver >= 90300:
return 'pg/9.3_plus'
return 'pg/9.3_plus'
return 'pg/{0}'.format(
'9.4_plus' if ver >= 90400 else
'9.3_plus'
)
def get_sql(self, gid, sid, data, scid, vid=None):
"""
@ -1249,8 +1265,7 @@ class MaterializedViewNode(ViewNode, VacuumSettings):
if scid is None:
return bad_request('Cannot create a View!')
return super(MaterializedViewNode, self).get_sql(
gid, sid, data, scid, vid)
return super(MViewNode, self).get_sql(gid, sid, data, scid, vid)
def getSQL(self, gid, sid, data, vid=None):
"""
@ -1577,8 +1592,11 @@ class MaterializedViewNode(ViewNode, VacuumSettings):
"""
# Below will decide if it's refresh data or refresh concurrently
data = request.form if request.form else json.loads(request.data.decode())
data = request.form if request.form else \
json.loads(request.data.decode())
is_concurrent = json.loads(data['concurrent'])
with_data = json.loads(data['with_data'])
try:
@ -1590,10 +1608,13 @@ class MaterializedViewNode(ViewNode, VacuumSettings):
return internal_server_error(errormsg=res)
# Refresh view
SQL = render_template("/".join(
[self.template_path, 'sql/refresh.sql']),
SQL = render_template(
"/".join([self.template_path, 'sql/refresh.sql']),
name=res['rows'][0]['name'],
nspname=res['rows'][0]['schema'], is_concurrent=is_concurrent)
nspname=res['rows'][0]['schema'],
is_concurrent=is_concurrent,
with_data=with_data
)
status, res_data = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res_data)
@ -1613,4 +1634,4 @@ class MaterializedViewNode(ViewNode, VacuumSettings):
return internal_server_error(errormsg=str(e))
ViewNode.register_node_view(view_blueprint)
MaterializedViewNode.register_node_view(mview_blueprint)
MViewNode.register_node_view(mview_blueprint)

View File

@ -61,35 +61,52 @@ function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) {
@property {data} - Allow create view option on schema node or
system view nodes.
*/
pgAdmin.Browser.add_menu_category(
'refresh_mview', '{{ _('Refresh View') }}', 18, 'fa fa-recycle');
pgBrowser.add_menus([{
name: 'create_mview_on_coll', node: 'coll-mview',
module: this, applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 1, label: '{{ _("Materialized View...") }}',
icon: 'wcTabIcon icon-mview', data: {action: 'create', check: true},
enable: 'canCreate'
name: 'create_mview_on_coll', node: 'coll-mview', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 1, icon: 'wcTabIcon icon-mview',
data: {action: 'create', check: true}, enable: 'canCreate',
label: '{{ _("Materialized View...") }}'
},{
name: 'create_mview', node: 'mview', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 1, label: '{{ _("Materialized View...") }}',
icon: 'wcTabIcon icon-mview', data: {action: 'create', check: true},
enable: 'canCreate'
category: 'create', priority: 1, icon: 'wcTabIcon icon-mview',
data: {action: 'create', check: true}, enable: 'canCreate',
label: '{{ _("Materialized View...") }}',
},{
name: 'create_mview', node: 'schema', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 18, label: '{{ _("Materialized View...") }}',
icon: 'wcTabIcon icon-mview', data: {action: 'create', check: false},
enable: 'canCreate'
category: 'create', priority: 18, icon: 'wcTabIcon icon-mview',
data: {action: 'create', check: false}, enable: 'canCreate',
label: '{{ _("Materialized View...") }}'
},{
name: 'refresh_mview', node: 'mview', module: this, category: 'Refresh view',
applies: ['object', 'context'], callback: 'refresh_mview', icon: 'fa fa-refresh',
priority: 1, label: '{{ _("Refresh data") }}', data: {concurrent: false}
name: 'refresh_mview_data', node: 'mview', module: this,
priority: 1, callback: 'refresh_mview', category: 'refresh_mview',
applies: ['object', 'context'], label: '{{ _("With data") }}',
data: {concurrent: false, with_data: true}, icon: 'fa fa-recycle'
},{
name: 'refresh_mview_nodata', node: 'mview',
callback: 'refresh_mview', priority: 2, module: this,
category: 'refresh_mview', applies: ['object', 'context'],
label: '{{ _("With no data") }}', data: {
concurrent: false, with_data: false
}, icon: 'fa fa-refresh'
},{
name: 'refresh_mview_concurrent', node: 'mview', module: this,
category: 'Refresh view',
applies: ['object', 'context'], callback: 'refresh_mview', icon: 'fa fa-refresh',
priority: 2, label: '{{ _("Refresh concurrently") }}', data: {concurrent: true}
}
]);
category: 'refresh_mview', enable: 'is_version_supported',
data: {concurrent: true, with_data: true}, priority: 3,
applies: ['object', 'context'], callback: 'refresh_mview',
label: '{{ _("With data (concurrently)") }}', icon: 'fa fa-recycle'
},{
name: 'refresh_mview_concurrent_nodata', node: 'mview', module: this,
category: 'refresh_mview', enable: 'is_version_supported',
data: {concurrent: true, with_data: false}, priority: 4,
applies: ['object', 'context'], callback: 'refresh_mview',
label: '{{ _("With no data (concurrently)") }}',
icon: 'fa fa-refresh'
}]);
},
/**
@ -257,14 +274,13 @@ function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) {
// by default we do not want to allow create menu
return true;
},
refresh_mview: function(args) {
var input = args || {};
obj = this,
t = pgBrowser.tree,
i = input.item || t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined;
var input = args || {},
obj = this,
t = pgBrowser.tree,
i = input.item || t.selected(),
d = i && i.length == 1 ? t.itemData(i) : undefined;
if (!d)
return false;
@ -273,7 +289,7 @@ function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) {
$.ajax({
url: obj.generate_url(i, 'refresh_data' , d, true),
type: 'PUT',
data: {'concurrent': args.concurrent},
data: {'concurrent': args.concurrent, 'with_data': args.with_data},
dataType: "json",
success: function(res) {
if (res.success == 1) {
@ -292,6 +308,17 @@ function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) {
}
});
},
is_version_supported: function(data, item, args) {
var t = pgAdmin.Browser.tree,
i = item || t.selected(),
d = data || (i && i.length == 1 ? t.itemData(i): undefined),
node = this || (d && pgAdmin.Browser.Nodes[d._type]),
info = node.getTreeNodeHierarchy.apply(node, [i]),
version = info.server.version;
// disable refresh concurrently if server version is 9.3
return (version >= 90400);
}
});
}

View File

@ -1,4 +1,2 @@
{#=== refresh mat view [concurrenlty] ===#}
{% if name and nspname %}
REFRESH MATERIALIZED VIEW {% if is_concurrent %}CONCURRENTLY{% endif %} {{ conn|qtIdent(nspname, name) }};
{% endif %}
{#= Refresh materialized view ===#}
REFRESH MATERIALIZED VIEW {{ conn|qtIdent(nspname, name) }} WITH {% if not with_data %} NO {% endif %}DATA;

View File

@ -0,0 +1,41 @@
{#============================Get ACLs=========================#}
{% if vid %}
SELECT
'datacl' as deftype,
COALESCE(gt.rolname, 'public') grantee,
g.rolname grantor,
array_agg(privilege_type) as privileges,
array_agg(is_grantable) as grantable
FROM
(SELECT
d.grantee,
d.grantor,
d.is_grantable,
CASE d.privilege_type
WHEN 'DELETE' THEN 'd'
WHEN 'INSERT' THEN 'a'
WHEN 'REFERENCES' THEN 'x'
WHEN 'SELECT' THEN 'r'
WHEN 'TRIGGER' THEN 't'
WHEN 'UPDATE' THEN 'w'
WHEN 'TRUNCATE' THEN 'D'
ELSE 'UNKNOWN'
END AS privilege_type
FROM
(SELECT
relacl
FROM
pg_class cl
LEFT OUTER JOIN pg_shdescription descr ON
(cl.oid=descr.objoid AND descr.classoid='pg_class'::regclass)
WHERE
cl.oid = {{ vid }}::OID AND relkind = 'm'
) acl,
aclexplode(relacl) d
) d
LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
GROUP BY
g.rolname,
gt.rolname
{% endif %}

View File

@ -0,0 +1,40 @@
{# ===================== Create new view ===================== #}
{% if display_comments %}
-- View: {{ conn|qtIdent(data.schema, data.name) }}
-- DROP MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }};
{% endif %}
{% if data.name and data.schema and data.definition %}
CREATE MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}
{% if(data.fillfactor or data['vacuum_data']|length > 0) %}
WITH (
{% if data.fillfactor %}
FILLFACTOR = {{ data.fillfactor }}{% if data['autovacuum_enabled'] or data['toast_autovacuum_enabled'] or data['vacuum_data']|length > 0 %},{{ '\r' }}{% endif %}
{% endif %}
{% for field in data['vacuum_data'] %}
{% if field.value is defined and field.value != '' and field.value != none %}
{% if loop.index > 1 %},
{% endif %} {{ field.name }} = {{ field.value|lower }}{% endif %}
{% endfor %}{{ '\r' }}
)
{% endif %}
{% if data.spcname %}TABLESPACE {{ data.spcname }}
{% endif %}AS
{{ data.definition.rstrip(';') }}
{% if data.with_data %}
WITH DATA;
{% else %}
WITH NO DATA;
{% endif %}
{% if data.owner %}
ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }}
OWNER TO {{ conn|qtIdent(data.owner) }};
{% endif %}
{% if data.comment %}
COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}
IS {{ data.comment|qtLiteral }};
{% endif %}
{% endif %}

View File

@ -0,0 +1,13 @@
{# =================== Drop/Cascade materialized view by name ====================#}
{% if vid %}
SELECT
c.relname As name,
nsp.nspname
FROM
pg_class c
LEFT JOIN pg_namespace nsp ON c.relnamespace = nsp.oid
WHERE
c.relfilenode = {{ vid }};
{% elif (name and nspname) %}
DROP MATERIALIZED VIEW {{ conn|qtIdent(nspname, name) }} {% if cascade %} CASCADE {% endif %}
{% endif %}

View File

@ -0,0 +1,7 @@
{# ===== fetch schema name =====#}
SELECT
nspname
FROM
pg_namespace
WHERE
oid = {{ scid }}::oid;

View File

@ -0,0 +1,11 @@
{# ===== get view name against view id ==== #}
{% if vid %}
SELECT
c.relname AS name,
nsp.nspname AS schema
FROM
pg_class c
LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace
WHERE
c.oid = {{vid}}
{% endif %}

View File

@ -0,0 +1,6 @@
{# ===== Grant Permissions to User Role on Views/Tables ==== #}
{% import 'macros/security.macros' as SECLABLE %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{# We will generate Security Label SQL using macro #}
{% if data.seclabels %}{% for r in data.seclabels %}{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.label) }}{% endfor %}{% endif %}
{% if data.datacl %}{% for priv in data.datacl %}{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}{% endfor %}{% endif %}

View File

@ -0,0 +1,111 @@
{# ========================== Fetch Materialized View Properties ========================= #}
{% if (vid and datlastsysoid) or scid %}
SELECT
c.oid,
c.xmin,
c.relname AS name,
c.reltablespace AS spcoid,
c.relispopulated AS with_data,
(CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname,
c.relacl,
nsp.nspname as schema,
pg_get_userbyid(c.relowner) AS owner,
description AS comment,
pg_get_viewdef(c.oid, true) AS definition,
{# ============= Checks if it is system view ================ #}
{% if vid and datlastsysoid %}
CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view,
{% endif %}
array_to_string(c.relacl::text[], ', ') AS acl,
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels,
substring(array_to_string(c.reloptions, ',')
FROM 'fillfactor=([0-9]*)') AS fillfactor,
(CASE WHEN (substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') THEN true ELSE false END) AS autovacuum_enabled,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
substring(array_to_string(c.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,
c.reloptions AS reloptions, tst.reloptions AS toast_reloptions,
(CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
(CASE WHEN (substring(array_to_string(c.reloptions, ',')
FROM 'autovacuum_enabled=([a-z|0-9]*)')) = 'true' THEN true ELSE false END) AS autovacuum_custom,
(CASE WHEN (substring(array_to_string(tst.reloptions, ',')
FROM 'autovacuum_enabled=([a-z|0-9]*)')) = 'true' THEN true ELSE false END) AS toast_autovacuum
FROM
pg_class c
LEFT OUTER JOIN pg_namespace nsp on nsp.oid = c.relnamespace
LEFT OUTER JOIN pg_tablespace spc on spc.oid=c.reltablespace
LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass)
LEFT OUTER JOIN pg_class tst ON tst.oid = c.reltoastrelid
WHERE ((c.relhasrules AND (EXISTS (
SELECT
r.rulename
FROM
pg_rewrite r
WHERE
((r.ev_class = c.oid)
AND (bpchar(r.ev_type) = '1'::bpchar)) )))
AND (c.relkind = 'm'::char)
)
{% if (vid and datlastsysoid) %}
AND c.oid = {{vid}}::oid
{% elif scid %}
AND c.relnamespace = {{scid}}::oid
ORDER BY
c.relname
{% endif %}
{% elif type == 'roles' %}
SELECT
pr.rolname
FROM
pg_roles pr
WHERE
pr.rolcanlogin
ORDER BY
pr.rolname
{% elif type == 'schemas' %}
SELECT
nsp.nspname
FROM
pg_namespace nsp
WHERE
(nsp.nspname NOT LIKE E'pg\\_%'
AND nsp.nspname != 'information_schema')
{% endif %}

View File

@ -0,0 +1,2 @@
{#= Refresh materialized view =#}
REFRESH MATERIALIZED VIEW{% if is_concurrent %} CONCURRENTLY{% endif %} {{ conn|qtIdent(nspname, name) }} WITH {% if not with_data %}NO {% endif %}DATA;

View File

@ -0,0 +1,214 @@
{# ===================== Update View ===================#}
{% import 'macros/security.macros' as SECLABLE %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{%- if data -%}
{% set view_name = data.name if data.name else o_data.name %}
{% set view_schema = data.schema if data.schema else o_data.schema %}
{% set def = data.definition.rstrip(';') if data.definition %}
{# ===== Rename mat view ===== #}
{% if data.name and data.name != o_data.name %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{# ===== Alter schema view ===== #}
{% if data.schema and data.schema != o_data.schema %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(o_data.schema, view_name ) }}
SET SCHEMA {{ conn|qtIdent(data.schema) }};
{% endif %}
{# ===== Alter Table owner ===== #}
{% if data.owner and data.owner != o_data.owner %}
ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }}
OWNER TO {{ conn|qtIdent(data.owner) }};
{% endif %}
{# ===== First Drop and then create mat view ===== #}
{% if def and def != o_data.definition.rstrip(';') %}
DROP MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }};
CREATE MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
{% if data.fillfactor or (data['vacuum_data']['changed']|length > 0 ) %}
WITH(
{% if data.fillfactor %}
FILLFACTOR = {{ data.fillfactor }}{% if data['vacuum_data']['changed']|length > 0 %},{% endif %}{{ '\r' }}
{% endif %}
{% if data['vacuum_data']['changed']|length > 0 %}
{% for field in data['vacuum_data']['changed'] %}
{{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }}
{% endfor %}
{% endif %}
)
{% endif %}
AS
{{ def }}
{% if data.with_data is defined %}
WITH {{ 'DATA' if data.with_data else 'NO DATA' }};
{% elif o_data.with_data %}
WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }};
{% endif %}
{% else %}
{# ======= Alter Tablespace ========= #}
{%- if data.spcoid and o_data.spcoid != data.spcoid -%}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
SET TABLESPACE {{ data.spcoid }};
{% endif %}
{# ======= SET/RESET Fillfactor ========= #}
{% if data.fillfactor and o_data.fillfactor != data.fillfactor %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
SET(
FILLFACTOR = {{ data.fillfactor }}
);
{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
RESET(
FILLFACTOR
);
{% endif %}
{# ===== Check for with_data property ===== #}
{% if data.with_data is defined and o_data.with_data|lower != data.with_data|lower %}
REFRESH MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} WITH{{ ' NO' if data.with_data|lower == 'false' else '' }} DATA;
{% endif %}
{# ===== Check for Table tab properties ===== #}
{% if ((data.autovacuum_custom is defined and data.autovacuum_custom|lower == 'false') or
(data.toast_autovacuum is defined and data.toast_autovacuum|lower == 'false')
) %}
{% if data.autovacuum_custom|lower == 'false' %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
RESET(
autovacuum_enabled,
autovacuum_vacuum_threshold,
autovacuum_analyze_threshold,
autovacuum_vacuum_scale_factor,
autovacuum_analyze_scale_factor,
autovacuum_vacuum_cost_delay,
autovacuum_vacuum_cost_limit,
autovacuum_freeze_min_age,
autovacuum_freeze_max_age,
autovacuum_freeze_table_age
);
{% if data.toast_autovacuum is defined and data.toast_autovacuum|lower != 'false' %}
{% if('vacuum_toast' in data and data['vacuum_toast']['changed']|length > 0) %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} SET(
{% for field in data['vacuum_toast']['changed'] %}
{% if field.value != None %}
{{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }}
{% endif %}
{% endfor %}
);
{% endif %}
{% endif %}
{% endif %}
{% if data.toast_autovacuum|lower == 'false' %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
RESET(
toast.autovacuum_enabled,
toast.autovacuum_vacuum_threshold,
toast.autovacuum_analyze_threshold,
toast.autovacuum_vacuum_scale_factor,
toast.autovacuum_analyze_scale_factor,
toast.autovacuum_vacuum_cost_delay,
toast.autovacuum_vacuum_cost_limit,
toast.autovacuum_freeze_min_age,
toast.autovacuum_freeze_max_age,
toast.autovacuum_freeze_table_age
);
{% if data.autovacuum_custom is defined and data.autovacuum_custom|lower != 'false' %}
{% if('vacuum_table' in data and data['vacuum_table']['changed']|length > 0) %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} SET(
{% for field in data['vacuum_table']['changed'] %}
{% if field.value != None %}
{{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }}
{% endif %}
{% endfor %}
);
{% endif %}
{% endif %}
{% endif %}{#-- toast_endif ends --#}
{% else %}
{% if data['vacuum_data']['reset']|length == 0 and
data['vacuum_data']['changed']|length == 0 and data['settings']|length > 0 %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
SET(
{% for field in data['settings'] %}
{{ field }} = {{ data['settings'][field]|lower }}{% if not loop.last %},{% endif %}{{ '\r' }}
{% endfor %}
);
{% endif %}
{% if(data['vacuum_data']['changed']|length > 0) %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}
SET(
{% for field in data['vacuum_data']['changed'] %}
{% if field.value != None %}
{{ field.name }} = {{ field.value|lower }}{% if not loop.last %},{% endif %}{{ '\r' }}
{% endif %}
{% endfor %}
);
{% endif %}
{% if data['vacuum_data']['reset']|length > 0 %}
ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
RESET(
{% for field in data['vacuum_data']['reset'] %}
{{ field.name }}{% if not loop.last %},{% endif %}{{ '\r' }}
{% endfor %}
);
{% endif %}
{% endif %}{# ===== End check for custom autovaccum ===== #}
{% endif %}{# ===== End block for check data definition ===== #}
{% set old_comment = o_data.comment|default('', true) %}
{% if (data.comment is defined and (data.comment != old_comment)) %}
COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }}
IS {{ data.comment|qtLiteral }};
{% endif %}
{# ============= The SQL generated below will change privileges ============= #}
{% if data.datacl %}
{% if 'deleted' in data.datacl %}
{% for priv in data.datacl.deleted %}
{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.datacl %}
{% for priv in data.datacl.changed -%}
{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{%- endfor %}
{% endif %}
{% if 'added' in data.datacl %}
{% for priv in data.datacl.added %}
{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
{# ============== The SQL generated below will change Security Label ========= #}
{% if data.seclabels is not none and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'VIEW', data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'VIEW', data.name, r.provider, r.label) }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,4 @@
{# ===== Below will provide view id for last created view ==== #}
{% if data %}
SELECT c.oid, c.relname FROM pg_class c WHERE c.relname = '{{ data.name }}';
{% endif %}