mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-04 12:40:56 -06:00
Support for the 'Refresh CONCURRENTLY' is applicable only on the
database server >= 9.4.
This commit is contained in:
parent
70cca42d61
commit
4aaa58352c
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 %}
|
@ -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 %}
|
@ -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 %}
|
@ -0,0 +1,7 @@
|
||||
{# ===== fetch schema name =====#}
|
||||
SELECT
|
||||
nspname
|
||||
FROM
|
||||
pg_namespace
|
||||
WHERE
|
||||
oid = {{ scid }}::oid;
|
@ -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 %}
|
@ -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 %}
|
@ -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 %}
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
Loading…
Reference in New Issue
Block a user