diff --git a/docs/en_US/images/materialized_view_code.png b/docs/en_US/images/materialized_view_code.png new file mode 100644 index 000000000..61ded3ccb Binary files /dev/null and b/docs/en_US/images/materialized_view_code.png differ diff --git a/docs/en_US/images/materialized_view_definition.png b/docs/en_US/images/materialized_view_definition.png index a324e2537..ec6999f79 100644 Binary files a/docs/en_US/images/materialized_view_definition.png and b/docs/en_US/images/materialized_view_definition.png differ diff --git a/docs/en_US/images/materialized_view_parameter.png b/docs/en_US/images/materialized_view_parameter.png index affc81f13..c97025ba7 100644 Binary files a/docs/en_US/images/materialized_view_parameter.png and b/docs/en_US/images/materialized_view_parameter.png differ diff --git a/docs/en_US/images/materialized_view_security.png b/docs/en_US/images/materialized_view_security.png index b389804c3..5bdf98af2 100644 Binary files a/docs/en_US/images/materialized_view_security.png and b/docs/en_US/images/materialized_view_security.png differ diff --git a/docs/en_US/images/materialized_view_sql.png b/docs/en_US/images/materialized_view_sql.png index 2806fb2fa..74f3062ab 100644 Binary files a/docs/en_US/images/materialized_view_sql.png and b/docs/en_US/images/materialized_view_sql.png differ diff --git a/docs/en_US/images/materialized_view_storage.png b/docs/en_US/images/materialized_view_storage.png deleted file mode 100644 index 6960bfed8..000000000 Binary files a/docs/en_US/images/materialized_view_storage.png and /dev/null differ diff --git a/docs/en_US/images/table_advanced.png b/docs/en_US/images/table_advanced.png index 49aac77c4..d12f88162 100644 Binary files a/docs/en_US/images/table_advanced.png and b/docs/en_US/images/table_advanced.png differ diff --git a/docs/en_US/materialized_view_dialog.rst b/docs/en_US/materialized_view_dialog.rst index 65b360827..bdd344e5f 100644 --- a/docs/en_US/materialized_view_dialog.rst +++ b/docs/en_US/materialized_view_dialog.rst @@ -31,17 +31,6 @@ Use the fields in the *General* tab to identify the materialized view: Click the *Definition* tab to continue. .. image:: images/materialized_view_definition.png - :alt: Materialized view dialog definition tab - :align: center - -Use the text editor field in the *Definition* tab to provide the query that will -populate the materialized view. Please note that updating the definition of existing -materialized view would result in loss of Parameter(Table, Toast), Security(Privileges & Security labels), -Indexes and other dependent objects. - -Click the *Storage* tab to continue. - -.. image:: images/materialized_view_storage.png :alt: Materialized view dialog storage tab :align: center @@ -52,10 +41,24 @@ Use the fields in the *Storage* tab to maintain the materialized view: cannot be queried until you invoke REFRESH MATERIALIZED VIEW. * Use the drop-down listbox next to *Tablespace* to select a location for the materialized view. +* Use the drop-down list box next to Access Method to specify the table access method to use to store the contents + for the new materialized view; the method needs to be an access method of type TABLE. This field is optional. + This option is available from v12 and above. * Use the *Fill Factor* field to specify a fill factor for the materialized view. The fill factor for a table is a percentage between 10 and 100. 100 (complete packing) is the default. +Click the *Code* tab to continue. + +.. image:: images/materialized_view_code.png + :alt: Materialized view dialog definition tab + :align: center + +Use the text editor field in the *Code* tab to provide the query that will +populate the materialized view. Please note that updating the definition of existing +materialized view would result in loss of Parameter(Table, Toast), Security(Privileges & Security labels), +Indexes and other dependent objects. + Click the *Parameter* tab to continue. .. image:: images/materialized_view_parameter.png diff --git a/docs/en_US/table_dialog.rst b/docs/en_US/table_dialog.rst index 9ebcbfc72..e20ac3253 100644 --- a/docs/en_US/table_dialog.rst +++ b/docs/en_US/table_dialog.rst @@ -394,6 +394,9 @@ Use the fields in the *Advanced* tab to define advanced features for the table: * Use the drop-down listbox next to *Of type* to copy the table structure from the specified composite type. Please note that a typed table will be dropped if the type is dropped (with DROP TYPE ... CASCADE). +* Use the drop-down list box next to Access Method to specify the table access method to use to store + the contents for the new table; the method needs to be an access method of type TABLE. This field is optional. + This option is available from v12 and above. * Use the *Fill Factor* field to specify a fill factor for the table. The fill factor for a table is a percentage between 10 and 100. 100 (complete packing) is the default. diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py index bec311e5d..829ab084f 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py @@ -295,6 +295,7 @@ class TableView(BaseTableView, DataTypeReader, SchemaDiffTableCompare): 'get_toast_table_vacuum': [{}, {'get': 'get_toast_table_vacuum'}], 'all_tables': [{}, {'get': 'get_all_tables'}], 'get_access_methods': [{}, {'get': 'get_access_methods'}], + 'get_table_access_methods': [{}, {'get': 'get_table_access_methods'}], 'get_oper_class': [{}, {'get': 'get_oper_class'}], 'get_operator': [{}, {'get': 'get_operator'}], 'get_attach_tables': [ @@ -538,6 +539,28 @@ class TableView(BaseTableView, DataTypeReader, SchemaDiffTableCompare): status=200 ) + @BaseTableView.check_precondition + def get_table_access_methods(self, gid, sid, did, scid, tid=None): + """ + This function returns access methods for table. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + + Returns: + Returns list of access methods for table + """ + res = BaseTableView.get_access_methods(self) + + return make_json_response( + data=res, + status=200 + ) + @BaseTableView.check_precondition def get_oper_class(self, gid, sid, did, scid, tid=None): """ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/default/alter_expr_statistics_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/11_plus/alter_expr_statistics_msql.sql similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/default/alter_expr_statistics_msql.sql rename to web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/11_plus/alter_expr_statistics_msql.sql diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/default/test_indexes.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/default/test_indexes.json index f8279fbf2..e1b81690d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/default/test_indexes.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/default/test_indexes.json @@ -186,31 +186,6 @@ "expected_sql_file": "create_btree_expr_asc_null_last.sql", "expected_msql_file": "create_btree_expr_asc_null_last_msql.sql" }, - { - "type": "alter", - "name": "Alter index statistics of expression", - "endpoint": "NODE-index.obj_id", - "sql_endpoint": "NODE-index.sql_id", - "msql_endpoint": "NODE-index.msql_id", - "data": { - "name": "Idx3_$%{}[]()&*^!@\"'`\\/#", - "columns":{ - "changed": [{ - "is_exp": true, - "col_num": 2, - "colname":"lower(name)", - "collspcname":"pg_catalog.\"POSIX\"", - "op_class":"text_pattern_ops", - "sort_order":false, - "nulls":false, - "is_sort_nulls_applicable":true, - "statistics": 1000 - }] - } - }, - "expected_sql_file": "alter_expr_statistics.sql", - "expected_msql_file": "alter_expr_statistics_msql.sql" - }, { "type": "delete", "name": "Drop index", diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/index_test_data.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/index_test_data.json index 58ec65e32..619ad0473 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/index_test_data.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/index_test_data.json @@ -545,6 +545,8 @@ "is_positive_test": true, "update_statistics": true, "inventory_data": { + "server_min_version": 110000, + "skip_msg": "Update statistics is not supported below PPAS/PG 11.0" }, "test_data": { "columns": "PLACE_HOLDER" diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/test_indexes_put.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/test_indexes_put.py index 56e4018d5..d28297654 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/test_indexes_put.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/test_indexes_put.py @@ -23,6 +23,7 @@ from pgadmin.utils.route import BaseTestGenerator from regression import parent_node_dict from regression.python_test_utils import test_utils as utils from . import utils as indexes_utils +from pgadmin.utils import server_utils class IndexesUpdateTestCase(BaseTestGenerator): @@ -36,6 +37,16 @@ class IndexesUpdateTestCase(BaseTestGenerator): schema_info = parent_node_dict["schema"][-1] self.server_id = schema_info["server_id"] self.db_id = schema_info["db_id"] + + if "server_min_version" in self.inventory_data: + server_con = server_utils.connect_server(self, self.server_id) + if not server_con["info"] == "Server connected.": + raise Exception("Could not connect to server to add " + "partitioned table.") + if server_con["data"]["version"] < \ + self.inventory_data["server_min_version"]: + self.skipTest(self.inventory_data["skip_msg"]) + db_con = database_utils.connect_database(self, utils.SERVER_GROUP, self.server_id, self.db_id) if not db_con['data']["connected"]: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py index 5ac0b9e59..558846cc2 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py @@ -211,7 +211,8 @@ class PartitionsView(BaseTableView, DataTypeReader, SchemaDiffObjectCompare): 'msql': [{'get': 'msql'}, {}], 'detach': [{'put': 'detach'}], 'truncate': [{'put': 'truncate'}], - 'set_trigger': [{'put': 'enable_disable_triggers'}] + 'set_trigger': [{'put': 'enable_disable_triggers'}], + 'get_table_access_methods': [{}, {'get': 'get_table_access_methods'}], }) # Schema Diff: Keys to ignore while comparing @@ -865,6 +866,29 @@ class PartitionsView(BaseTableView, DataTypeReader, SchemaDiffObjectCompare): return diff + '\n' + @BaseTableView.check_precondition + def get_table_access_methods(self, gid, sid, did, scid, tid, ptid=None): + """ + This function returns access methods for table. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + ptid: Partition Table ID + + Returns: + Returns list of access methods for partition table + """ + res = BaseTableView.get_access_methods(self) + + return make_json_response( + data=res, + status=200 + ) + SchemaDiffRegistry(blueprint.node_type, PartitionsView, 'table') PartitionsView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.ui.js index 26acf6514..66f37c7c8 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.ui.js @@ -40,6 +40,7 @@ export function getNodePartitionTableSchema(treeNodeInfo, itemNodeData, pgBrowse coll_inherits: ()=>getNodeAjaxOptions('get_inherits', partNode, treeNodeInfo, itemNodeData), typname: ()=>getNodeAjaxOptions('get_oftype', partNode, treeNodeInfo, itemNodeData), like_relation: ()=>getNodeAjaxOptions('get_relations', partNode, treeNodeInfo, itemNodeData), + table_amname_list: ()=>getNodeAjaxOptions('get_table_access_methods', partNode, treeNodeInfo, itemNodeData), }, treeNodeInfo, { @@ -110,6 +111,7 @@ export default class PartitionTableSchema extends BaseUISchema { partition_type: 'range', is_partitioned: false, partition_value: undefined, + amname: undefined, ...initValues, }); @@ -121,7 +123,7 @@ export default class PartitionTableSchema extends BaseUISchema { this.getAttachTables = getAttachTables; this.partitionKeysObj = new PartitionKeysSchema([], getCollations, getOperatorClass); - this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass, getAttachTables); + this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass, getAttachTables, fieldOptions.table_amname_list); this.constraintsObj = this.schemas.constraints(); } @@ -229,6 +231,23 @@ export default class PartitionTableSchema extends BaseUISchema { mode: ['create', 'edit'], group: 'advanced', min_version: 90600, disabled: obj.isPartitioned, }, + { + id: 'amname', label: gettext('Access Method'), group: 'advanced', + type: (state)=>{ + return { + type: 'select', options: this.fieldOptions.table_amname_list, + controlProps: { + allowClear: obj.isNew(state) ? true : false, + } + }; + }, mode: ['create', 'properties', 'edit'], min_version: 120000, + disabled: (state) => { + if (obj.getServerVersion() < 150000 && !obj.isNew(state)) { + return true; + } + return obj.isPartitioned(state); + }, + }, { id: 'relhasoids', label: gettext('Has OIDs?'), cell: 'switch', type: 'switch', mode: ['properties', 'create', 'edit'], diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.ui.js index 97c40385d..bfadceb58 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.ui.js @@ -113,7 +113,7 @@ export class PartitionKeysSchema extends BaseUISchema { } } export class PartitionsSchema extends BaseUISchema { - constructor(nodeInfo, getCollations, getOperatorClass, getAttachTables=()=>[]) { + constructor(nodeInfo, getCollations, getOperatorClass, getAttachTables=()=>[], table_amname_list) { super({ oid: undefined, is_attach: false, @@ -126,11 +126,13 @@ export class PartitionsSchema extends BaseUISchema { values_remainder: undefined, is_sub_partitioned: false, sub_partition_type: 'range', + amname: undefined, }); this.subPartitionsObj = new PartitionKeysSchema([], getCollations, getOperatorClass); this.getAttachTables = getAttachTables; this.nodeInfo = nodeInfo; + this.table_amname_list = table_amname_list; } changeColumnOptions(columns) { @@ -198,6 +200,27 @@ export class PartitionsSchema extends BaseUISchema { readonly: function(state) { return !obj.isNew(state); }, noEmpty: true, + },{ + id: 'amname', label: gettext('Access Method'), deps: ['is_sub_partitioned'], cell: 'select', + type: (state)=>{ + return { + type: 'select', options: this.table_amname_list, + controlProps: { + allowClear: obj.isNew(state) ? true : false, + } + }; + }, min_version: 120000, disabled: state => { + if (obj.getServerVersion() < 150000 && !obj.isNew(state)) { + return true; + } + return state.is_sub_partitioned; + }, depChange: state => { + if (state.is_sub_partitioned) { + return { + amname: undefined + }; + } + }, },{ id: 'is_default', label: gettext('Default'), type: 'switch', cell:'switch', width: 55, disableResizing: true, min_version: 110000, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js index 2495842d3..5b9171d85 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.ui.js @@ -45,6 +45,7 @@ export function getNodeTableSchema(treeNodeInfo, itemNodeData, pgBrowser) { coll_inherits: ()=>getNodeAjaxOptions('get_inherits', tableNode, treeNodeInfo, itemNodeData), typname: ()=>getNodeAjaxOptions('get_oftype', tableNode, treeNodeInfo, itemNodeData), like_relation: ()=>getNodeAjaxOptions('get_relations', tableNode, treeNodeInfo, itemNodeData), + table_amname_list: ()=>getNodeAjaxOptions('get_table_access_methods', tableNode, treeNodeInfo, itemNodeData), }, treeNodeInfo, { @@ -343,6 +344,7 @@ export default class TableSchema extends BaseUISchema { partition_type: 'range', is_partitioned: false, columns: [], + amname: undefined, ...initValues, }); @@ -352,7 +354,7 @@ export default class TableSchema extends BaseUISchema { this.nodeInfo = nodeInfo; this.getColumns = getColumns; - this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass, getAttachTables); + this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass, getAttachTables, fieldOptions.table_amname_list); this.constraintsObj = this.schemas.constraints && this.schemas.constraints() || {}; this.columnsSchema = this.schemas.columns && this.schemas.columns() || {}; this.vacuumSettingsSchema = this.schemas.vacuum_settings && this.schemas.vacuum_settings() || {}; @@ -760,6 +762,29 @@ export default class TableSchema extends BaseUISchema { } }, }, + { + id: 'amname', label: gettext('Access Method'), group: 'advanced', + deps:['is_partitioned'], type: (state)=>{ + return { + type: 'select', options: this.fieldOptions.table_amname_list, + controlProps: { + allowClear: obj.isNew(state) ? true : false, + } + }; + }, mode: ['create', 'properties', 'edit'], min_version: 120000, + disabled: (state) => { + if (obj.getServerVersion() < 150000 && !obj.isNew(state)) { + return true; + } + return obj.isPartitioned(state); + }, depChange: state => { + if (state.is_partitioned) { + return { + amname: undefined + }; + } + }, + }, { id: 'fillfactor', label: gettext('Fill factor'), type: 'int', mode: ['create', 'edit'], min: 10, max: 100, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/indexes/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/indexes/sql/default/create.sql index ea3ce45f8..38f5b9d28 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/indexes/sql/default/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/indexes/sql/default/create.sql @@ -13,7 +13,7 @@ FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %}) FIRST{% else %}LAST{% endif %}{% endif %}{% endfor %}) {% endif %} {% if data.fillfactor %} - WITH (FILLFACTOR={{data.fillfactor}}) + WITH (fillfactor={{data.fillfactor}}) {% endif %}{% if data.spcname %} TABLESPACE {{conn|qtIdent(data.spcname)}}{% endif %}{% if data.indconstraint %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/create.sql new file mode 100644 index 000000000..77f5064c4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/create.sql @@ -0,0 +1,74 @@ +{% import 'tables/sql/macros/constraints.macro' as CONSTRAINTS %} +{#===========================================#} +{#====== MAIN TABLE TEMPLATE STARTS HERE ======#} +{#===========================================#} +{### CREATE TABLE STATEMENT FOR partitions ###} + +CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{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 %} +{% if data.default_amname and data.default_amname != data.amname and data.amname is not none %} + +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} + +USING {{data.amname}} +{% endif %} +{% if data.fillfactor or data.autovacuum_custom or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum or data.toast_autovacuum_enabled in ('t', 'f') or (data.autovacuum_enabled in ('t', 'f') and data.vacuum_table|length > 0) or (data.toast_autovacuum_enabled in ('t', 'f') and data.vacuum_toast|length > 0) %} +{% set ns = namespace(add_comma=false) %} + +WITH ( +{% if data.fillfactor %}{% set ns.add_comma = true%} + FILLFACTOR = {{ data.fillfactor }}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% if data.autovacuum_custom and data.vacuum_table|length > 0 %} +{% for opt in data.vacuum_table %}{% if opt.name and opt.value is defined %} +{% if ns.add_comma %}, +{% endif %} + {{opt.name}} = {{opt.value}}{% endif %}{% if opt.name and opt.value is defined %}{% set ns.add_comma = true%}{% endif %} +{% endfor %}{% endif %} +{% if data.toast_autovacuum and data.vacuum_toast|length > 0 %} +{% for opt in data.vacuum_toast %}{% if opt.name and opt.value is defined %} +, + toast.{{opt.name}} = {{opt.value}}{% endif %}{% if opt.name and opt.value is defined %}{% set ns.add_comma = true%}{% endif %} +{% endfor %}{% endif %} + +){% endif %} +{### SQL for Tablespace ###} +{% if data.spcname %} + +TABLESPACE {{ conn|qtIdent(data.spcname) }}; +{% else %} +; + +{% endif %} +{### Alter SQL for Owner ###} +{% if data.relowner %} + +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + OWNER to {{conn|qtIdent(data.relowner)}}; +{% endif %} +{### SQL for COMMENT ###} +{% if data.description %} +COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}} + IS {{data.description|qtLiteral(conn)}}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/nodes.sql new file mode 100644 index 000000000..ec1d4ff02 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/nodes.sql @@ -0,0 +1,55 @@ +SELECT rel.oid, rel.relname AS name, + (SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount, + (SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers, + pg_catalog.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 true ELSE false END) AS is_sub_partitioned, + (CASE WHEN rel.relkind = 'p' THEN pg_catalog.pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme, + (CASE WHEN rel.relkind = 'p' THEN pg_catalog.pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS sub_partition_scheme, + (CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence, + (CASE WHEN length(spc.spcname::text) > 0 THEN spc.spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END) as spcname, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname, + typ.typrelid AS typoid, des.description, pg_catalog.pg_get_userbyid(rel.relowner) AS relowner, am.amname +FROM + (SELECT * FROM pg_catalog.pg_inherits WHERE inhparent = {{ tid }}::oid) inh + LEFT JOIN pg_catalog.pg_class rel ON inh.inhrelid = rel.oid + LEFT JOIN pg_catalog.pg_namespace nsp ON rel.relnamespace = nsp.oid + LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid + LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) + LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=rel.reltablespace + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam + LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid + WHERE rel.relispartition + {% if ptid %} AND rel.oid = {{ ptid }}::OID {% endif %} +{% if schema_diff %} + AND CASE WHEN (SELECT COUNT(*) FROM pg_catalog.pg_depend + WHERE objid = rel.oid AND deptype = 'e') > 0 THEN FALSE ELSE TRUE END +{% endif %} + ORDER BY rel.relname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/properties.sql index 817534100..b4c1b907d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/12_plus/properties.sql @@ -48,7 +48,8 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname, - typ.typrelid AS typoid, + typ.typrelid AS typoid, am.amname, + (SELECT st.setting from pg_catalog.pg_settings st WHERE st.name = 'default_table_access_method') as default_amname, (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.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, @@ -67,6 +68,7 @@ FROM pg_catalog.pg_class rel LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) LEFT OUTER JOIN pg_catalog.pg_constraint con ON con.conrelid=rel.oid AND con.contype='p' LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid LEFT JOIN pg_catalog.pg_inherits inh ON inh.inhrelid = rel.oid LEFT JOIN pg_catalog.pg_namespace nsp ON rel.relnamespace = nsp.oid diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/14_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/14_plus/nodes.sql index 2c2159738..01f90b66a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/14_plus/nodes.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/14_plus/nodes.sql @@ -36,7 +36,7 @@ SELECT rel.oid, rel.relname AS name, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname, - typ.typrelid AS typoid, des.description, pg_catalog.pg_get_userbyid(rel.relowner) AS relowner, inh.inhdetachpending + typ.typrelid AS typoid, des.description, pg_catalog.pg_get_userbyid(rel.relowner) AS relowner, inh.inhdetachpending, am.amname FROM (SELECT * FROM pg_catalog.pg_inherits WHERE inhparent = {{ tid }}::oid) inh LEFT JOIN pg_catalog.pg_class rel ON inh.inhrelid = rel.oid @@ -44,6 +44,7 @@ FROM LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=rel.reltablespace + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid WHERE rel.relispartition {% if ptid %} AND rel.oid = {{ ptid }}::OID {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/create.sql new file mode 100644 index 000000000..d837366f0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/create.sql @@ -0,0 +1,72 @@ +{% import 'tables/sql/macros/constraints.macro' as CONSTRAINTS %} +{#===========================================#} +{#====== MAIN TABLE TEMPLATE STARTS HERE ======#} +{#===========================================#} +{### CREATE TABLE STATEMENT FOR partitions ###} +CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE IF NOT EXISTS {{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 %} +{% if data.default_amname and data.default_amname != data.amname and data.amname is not none %} + +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} + +USING {{data.amname}} +{% endif %} +{% if data.fillfactor or data.autovacuum_custom or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum or data.toast_autovacuum_enabled in ('t', 'f') or (data.autovacuum_enabled in ('t', 'f') and data.vacuum_table|length > 0) or (data.toast_autovacuum_enabled in ('t', 'f') and data.vacuum_toast|length > 0) %} +{% set ns = namespace(add_comma=false) %} + +WITH ( +{% if data.fillfactor %}{% set ns.add_comma = true%} + FILLFACTOR = {{ data.fillfactor }}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% if data.autovacuum_custom and data.vacuum_table|length > 0 %} +{% for opt in data.vacuum_table %}{% if opt.name and opt.value is defined %} +{% if ns.add_comma %}, +{% endif %} + {{opt.name}} = {{opt.value}}{% endif %}{% if opt.name and opt.value is defined %}{% set ns.add_comma = true%}{% endif %} +{% endfor %}{% endif %}{% if data.toast_autovacuum and data.vacuum_toast|length > 0 %} +{% for opt in data.vacuum_toast %}{% if opt.name and opt.value is defined %} +, + toast.{{opt.name}} = {{opt.value}}{% endif %} +{% endfor %}{% endif %} + +){% endif %} +{### SQL for Tablespace ###} +{% if data.spcname %} + +TABLESPACE {{ conn|qtIdent(data.spcname) }}; +{% else %} +; + +{% endif %} +{### Alter SQL for Owner ###} +{% if data.relowner %} + +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + OWNER to {{conn|qtIdent(data.relowner)}}; +{% endif %} +{### SQL for COMMENT ###} +{% if data.description %} +COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}} + IS {{data.description|qtLiteral(conn)}}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/nodes.sql new file mode 100644 index 000000000..ec1d4ff02 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/nodes.sql @@ -0,0 +1,55 @@ +SELECT rel.oid, rel.relname AS name, + (SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount, + (SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers, + pg_catalog.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 true ELSE false END) AS is_sub_partitioned, + (CASE WHEN rel.relkind = 'p' THEN pg_catalog.pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme, + (CASE WHEN rel.relkind = 'p' THEN pg_catalog.pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS sub_partition_scheme, + (CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence, + (CASE WHEN length(spc.spcname::text) > 0 THEN spc.spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END) as spcname, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname, + typ.typrelid AS typoid, des.description, pg_catalog.pg_get_userbyid(rel.relowner) AS relowner, am.amname +FROM + (SELECT * FROM pg_catalog.pg_inherits WHERE inhparent = {{ tid }}::oid) inh + LEFT JOIN pg_catalog.pg_class rel ON inh.inhrelid = rel.oid + LEFT JOIN pg_catalog.pg_namespace nsp ON rel.relnamespace = nsp.oid + LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid + LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) + LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=rel.reltablespace + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam + LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid + WHERE rel.relispartition + {% if ptid %} AND rel.oid = {{ ptid }}::OID {% endif %} +{% if schema_diff %} + AND CASE WHEN (SELECT COUNT(*) FROM pg_catalog.pg_depend + WHERE objid = rel.oid AND deptype = 'e') > 0 THEN FALSE ELSE TRUE END +{% endif %} + ORDER BY rel.relname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/properties.sql index 641564a91..db03b0310 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/12_plus/properties.sql @@ -48,7 +48,8 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname, - typ.typrelid AS typoid, + typ.typrelid AS typoid, am.amname, + (SELECT st.setting from pg_catalog.pg_settings st WHERE st.name = 'default_table_access_method') as default_amname, (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.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, @@ -67,6 +68,7 @@ FROM pg_catalog.pg_class rel LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) LEFT OUTER JOIN pg_catalog.pg_constraint con ON con.conrelid=rel.oid AND con.contype='p' LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid LEFT JOIN pg_catalog.pg_inherits inh ON inh.inhrelid = rel.oid LEFT JOIN pg_catalog.pg_namespace nsp ON rel.relnamespace = nsp.oid diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/14_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/14_plus/nodes.sql index 2c2159738..01f90b66a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/14_plus/nodes.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/ppas/14_plus/nodes.sql @@ -36,7 +36,7 @@ SELECT rel.oid, rel.relname AS name, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname, - typ.typrelid AS typoid, des.description, pg_catalog.pg_get_userbyid(rel.relowner) AS relowner, inh.inhdetachpending + typ.typrelid AS typoid, des.description, pg_catalog.pg_get_userbyid(rel.relowner) AS relowner, inh.inhdetachpending, am.amname FROM (SELECT * FROM pg_catalog.pg_inherits WHERE inhparent = {{ tid }}::oid) inh LEFT JOIN pg_catalog.pg_class rel ON inh.inhrelid = rel.oid @@ -44,6 +44,7 @@ FROM LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=rel.reltablespace + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid WHERE rel.relispartition {% if ptid %} AND rel.oid = {{ ptid }}::OID {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/create.sql index 6879ee3c0..d6d258b73 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/create.sql @@ -87,6 +87,11 @@ CACHE {{c.seqcache|int}} {% endif %} {% if data.coll_inherits %} INHERITS ({% for val in data.coll_inherits %}{% if loop.index != 1 %}, {% endif %}{{val}}{% endfor %}){% if not data.spcname and not with_clause %};{% endif %} {% endif %} +{% if data.default_amname and data.default_amname != data.amname and data.amname is not none %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} {% if with_clause %} {% set ns = namespace(add_comma=false) %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/get_access_methods.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/get_access_methods.sql new file mode 100644 index 000000000..2a93232bf --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/get_access_methods.sql @@ -0,0 +1,3 @@ +-- Fetches access methods +SELECT oid, amname +FROM pg_catalog.pg_am WHERE amtype = 't'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/properties.sql index a98d5b69b..ea420a44f 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/12_plus/properties.sql @@ -32,6 +32,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r JOIN pg_catalog.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, + (SELECT st.setting from pg_catalog.pg_settings st WHERE st.name = 'default_table_access_method') as default_amname, substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor, substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'parallel_workers=([0-9]*)') AS parallel_workers, substring(pg_catalog.array_to_string(rel.reloptions, ',') FROM 'toast_tuple_target=([0-9]*)') AS toast_tuple_target, @@ -55,7 +56,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, - rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, + rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, am.amname, CASE WHEN typ.typname IS NOT NULL THEN (select pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace WHERE oid = {{scid}}::oid )||'.'||pg_catalog.quote_ident(typ.typname) ELSE typ.typname END AS typname, typ.typrelid AS typoid, rel.relrowsecurity as rlspolicy, rel.relforcerowsecurity as forcerlspolicy, (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, @@ -69,6 +70,7 @@ FROM pg_catalog.pg_class rel LEFT OUTER JOIN pg_catalog.pg_constraint con ON con.conrelid=rel.oid AND con.contype='p' LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = rel.reltoastrelid LEFT JOIN pg_catalog.pg_type typ ON rel.reloftype=typ.oid + LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = rel.relam WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid AND NOT rel.relispartition {% if tid %} AND rel.oid = {{ tid }}::oid {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/14_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/14_plus/create.sql index 1924ccb95..578ae5afd 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/14_plus/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/14_plus/create.sql @@ -89,6 +89,11 @@ CACHE {{c.seqcache|int}} {% endif %} {% if data.coll_inherits %} INHERITS ({% for val in data.coll_inherits %}{% if loop.index != 1 %}, {% endif %}{{val}}{% endfor %}){% if not data.spcname and not with_clause %};{% endif %} {% endif %} +{% if data.default_amname and data.default_amname != data.amname and data.amname is not none %} +USING {{data.amname}} +{% elif data.amname and not data.default_amname %} +USING {{data.amname}} +{% endif %} {% if with_clause %} {% set ns = namespace(add_comma=false) %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/15_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/15_plus/update.sql new file mode 100644 index 000000000..4483a08a3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/15_plus/update.sql @@ -0,0 +1,292 @@ +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% import 'macros/variable.macros' as VARIABLE %} +{#####################################################} +{## Rename table ##} +{#####################################################} +{% if data.name and data.name != o_data.name %} +ALTER TABLE IF EXISTS {{conn|qtIdent(o_data.schema, o_data.name)}} + RENAME TO {{conn|qtIdent(data.name)}}; + +{% endif %} +{#####################################################} +{## change table access method ##} +{#####################################################} +{% if data.amname and data.amname != o_data.amname %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + SET ACCESS METHOD {{conn|qtIdent(data.amname)}}; + +{% endif %} +{#####################################################} +{## Change table schema ##} +{#####################################################} +{% if data.schema and data.schema != o_data.schema %} +ALTER TABLE IF EXISTS {{conn|qtIdent(o_data.schema, data.name)}} + SET SCHEMA {{conn|qtIdent(data.schema)}}; + +{% endif %} +{#####################################################} +{## Change table owner ##} +{#####################################################} +{% if data.relowner and data.relowner != o_data.relowner %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + OWNER TO {{conn|qtIdent(data.relowner)}}; + +{% endif %} +{#####################################################} +{## Update Inherits table definition ##} +{#####################################################} +{% if data.coll_inherits_added|length > 0 %} +{% for val in data.coll_inherits_added %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + INHERIT {{val}}; + +{% endfor %} +{% endif %} +{% if data.coll_inherits_removed|length > 0 %} +{% for val in data.coll_inherits_removed %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + NO INHERIT {{val}}; + +{% endfor %} +{% endif %} +{#####################################################} +{## Change tablespace ##} +{#####################################################} +{% if data.spcname and data.spcname != o_data.spcname %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + SET TABLESPACE {{conn|qtIdent(data.spcname)}}; + +{% endif %} + + +{#####################################################} +{## Enable Row Level Security Policy on table ##} +{#####################################################} +{% if data.rlspolicy %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + ENABLE ROW LEVEL SECURITY; +{% elif data.rlspolicy is defined and data.rlspolicy != o_data.rlspolicy%} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + DISABLE ROW LEVEL SECURITY; + +{% endif %} + +{#####################################################} +{## Force Enable Row Level Security Policy on table ##} +{#####################################################} +{% if data.forcerlspolicy %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + FORCE ROW LEVEL SECURITY; +{% elif data.forcerlspolicy is defined and data.forcerlspolicy != o_data.forcerlspolicy%} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + NO FORCE ROW LEVEL SECURITY; +{% endif %} + +{#####################################################} +{## change fillfactor settings ##} +{#####################################################} +{% if data.fillfactor and data.fillfactor != o_data.fillfactor %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + SET (FILLFACTOR={{data.fillfactor}}); +{% elif (data.fillfactor == '' or data.fillfactor == None) and data.fillfactor != o_data.fillfactor %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + RESET (FILLFACTOR); + +{% endif %} + +{## change parallel_workers settings ##} +{#####################################################} +{% if (data.parallel_workers == '' or data.parallel_workers == None) and data.parallel_workers != o_data.parallel_workers %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + RESET (parallel_workers); +{% elif data.parallel_workers is defined and data.parallel_workers != o_data.parallel_workers %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + SET (parallel_workers={{data.parallel_workers}}); + +{% endif %} + +{## change toast_tuple_target settings ##} +{#####################################################} +{% if (data.toast_tuple_target == '' or data.toast_tuple_target == None) and data.toast_tuple_target != o_data.toast_tuple_target %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + RESET (toast_tuple_target); +{% elif data.toast_tuple_target is defined and data.toast_tuple_target != o_data.toast_tuple_target %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} + SET (toast_tuple_target={{data.toast_tuple_target}}); + +{% endif %} + +{###############################} +{## Table AutoVacuum settings ##} +{###############################} +{% if data.vacuum_table is defined and data.vacuum_table.set_values|length > 0 %} +{% set has_vacuum_set = true %} +{% endif %} +{% if data.vacuum_table is defined and data.vacuum_table.reset_values|length > 0 %} +{% set has_vacuum_reset = true %} +{% endif %} +{% if o_data.autovacuum_custom and data.autovacuum_custom == false %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} RESET ( + autovacuum_enabled, + autovacuum_analyze_scale_factor, + autovacuum_analyze_threshold, + autovacuum_freeze_max_age, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_cost_limit, + autovacuum_vacuum_scale_factor, + autovacuum_vacuum_threshold, + autovacuum_freeze_min_age, + autovacuum_freeze_table_age +); +{% else %} +{% if (data.autovacuum_enabled in ('t', 'f') and data.autovacuum_enabled != o_data.autovacuum_enabled) or has_vacuum_set %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} SET ( +{% if data.autovacuum_enabled in ('t', 'f') and data.autovacuum_enabled != o_data.autovacuum_enabled %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if has_vacuum_set %}, +{% endif %} +{% endif %} +{% if has_vacuum_set %} +{% for opt in data.vacuum_table.set_values %}{% if opt.name and opt.value is defined %} + {{opt.name}} = {{opt.value}}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} +{% endif %} + +); +{% endif %} +{% if (data.autovacuum_enabled == 'x' and data.autovacuum_enabled != o_data.autovacuum_enabled) or has_vacuum_reset %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} RESET ( +{% if data.autovacuum_enabled =='x' and data.autovacuum_enabled != o_data.autovacuum_enabled %} + autovacuum_enabled{% if has_vacuum_reset %}, +{% endif %} +{% endif %} +{% if has_vacuum_reset %} +{% for opt in data.vacuum_table.reset_values %}{% if opt.name %} + {{opt.name}}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} +{% endif %} + +); +{% endif %} +{% endif %} +{#####################################} +{## Toast table AutoVacuum settings ##} +{#####################################} +{% if data.vacuum_toast is defined and data.vacuum_toast.set_values|length > 0 %} +{% set has_vacuum_toast_set = true %} +{% endif %} +{% if data.vacuum_toast is defined and data.vacuum_toast.reset_values|length > 0 %} +{% set has_vacuum_toast_reset = true %} +{% endif %} +{% if o_data.toast_autovacuum and data.toast_autovacuum == false %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} RESET ( + toast.autovacuum_enabled, + toast.autovacuum_freeze_max_age, + toast.autovacuum_vacuum_cost_delay, + toast.autovacuum_vacuum_cost_limit, + toast.autovacuum_vacuum_scale_factor, + toast.autovacuum_vacuum_threshold, + toast.autovacuum_freeze_min_age, + toast.autovacuum_freeze_table_age, + toast.autovacuum_analyze_threshold, + toast.autovacuum_analyze_scale_factor +); +{% else %} +{% if (data.toast_autovacuum_enabled in ('t', 'f') and data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled) or has_vacuum_toast_set %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} SET ( +{% if data.toast_autovacuum_enabled in ('t', 'f') and data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if has_vacuum_toast_set %}, +{% endif %} +{% endif %} +{% if has_vacuum_toast_set %} +{% for opt in data.vacuum_toast.set_values %}{% if opt.name and opt.value is defined %} + toast.{{opt.name}} = {{opt.value}}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} +{% endif %} + +); +{% endif %} +{% if (data.toast_autovacuum_enabled == 'x' and data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled) or has_vacuum_toast_reset %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} RESET ( +{% if data.toast_autovacuum_enabled == 'x' and data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled %} + toast.autovacuum_enabled{% if has_vacuum_toast_reset %}, +{% endif %} +{% endif %} +{% if has_vacuum_toast_reset %} +{% for opt in data.vacuum_toast.reset_values %}{% if opt.name %} + toast.{{opt.name}}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} +{% endif %} + +); +{% endif %} +{% endif %} +{#####################################################} +{## Change table comments ##} +{#####################################################} +{% if data.description is defined and data.description != o_data.description %} +COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}} + IS {{data.description|qtLiteral(conn)}}; + +{% endif %} +{#####################################################} +{## Update table Privileges ##} +{#####################################################} +{% if data.relacl %} +{% if 'deleted' in data.relacl %} +{% for priv in data.relacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.relacl %} +{% for priv in data.relacl.changed %} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in data.relacl %} +{% for priv in data.relacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{#####################################################} +{## Update table SecurityLabel ##} +{#####################################################} +{% if data.seclabels and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'TABLE', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} + +{% endif %} +{#####################################################} +{## Change replica identity ##} +{#####################################################} +{% if data.replica_identity and data.replica_identity != o_data.replica_identity %} +ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.name)}} REPLICA IDENTITY {{data.replica_identity }}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py index aa16ecabc..d66ab36e7 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py @@ -926,6 +926,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings): part_data['partition_scheme'] = row['partition_scheme'] part_data['description'] = row['description'] part_data['relowner'] = row['relowner'] + part_data['default_amname'] = data.get('default_amname') + part_data['amname'] = row.get('amname') self.update_autovacuum_properties(row) @@ -1872,6 +1874,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings): part_data = dict() part_data['partitioned_table_name'] = partitions['name'] part_data['parent_schema'] = partitions['schema'] + part_data['amname'] = row.get('amname') if 'is_attach' in row and row['is_attach']: schema_name, table_name = \ @@ -2199,3 +2202,23 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings): res['toast_autovacuum_freeze_max_age'], res['toast_autovacuum_freeze_table_age']]) or \ res['toast_autovacuum_enabled'] in ('t', 'f') + + def get_access_methods(self): + """ + This function returns the access methods for table + """ + + res = [] + sql = render_template("/".join([self.table_template_path, + 'get_access_methods.sql'])) + + status, rest = self.conn.execute_2darray(sql) + if not status: + return internal_server_error(errormsg=rest) + + for row in rest['rows']: + res.append( + {'label': row['amname'], 'value': row['amname']} + ) + + return res diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py index 41a1addd3..2b950f3db 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py @@ -1759,7 +1759,8 @@ class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare): # Override the operations for materialized view mview_operations = { 'refresh_data': [{'put': 'refresh_data'}, {}], - 'check_utility_exists': [{'get': 'check_utility_exists'}, {}] + 'check_utility_exists': [{'get': 'check_utility_exists'}, {}], + 'get_access_methods': [{}, {'get': 'get_access_methods'}], } mview_operations.update(ViewNode.operations) @@ -2415,6 +2416,35 @@ class MViewNode(ViewNode, VacuumSettings): status=200 ) + @check_precondition + def get_access_methods(self, gid, sid, did, scid, vid=None): + """ + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + vid: View ID + + Returns the access method to be used by mview + """ + res = [] + sql = render_template("/".join([self.template_path, + 'sql/get_access_methods.sql'])) + status, rest = self.conn.execute_2darray(sql) + if not status: + return internal_server_error(errormsg=rest) + + for row in rest['rows']: + res.append( + {'label': row['amname'], 'value': row['amname']} + ) + + return make_json_response( + data=res, + status=200 + ) + SchemaDiffRegistry(view_blueprint.node_type, ViewNode) ViewNode.register_node_view(view_blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js index 75b1e0054..ea8dd8371 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////// import MViewSchema from './mview.ui'; -import { getNodeListByName } from '../../../../../../../static/js/node_ajax'; +import { getNodeListByName, getNodeAjaxOptions } from '../../../../../../../static/js/node_ajax'; import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui'; import { getNodeVacuumSettingsSchema } from '../../../../../static/js/vacuum.ui'; import Notify from '../../../../../../../../static/js/helpers/Notifier'; @@ -140,6 +140,7 @@ define('pgadmin.node.mview', [ spcname: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=> { return (m.label != 'pg_global'); }), + table_amname_list: ()=>getNodeAjaxOptions('get_access_methods', this, treeNodeInfo, itemNodeData), nodeInfo: treeNodeInfo, }, { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js index 2d14967e7..f6f36aa21 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js @@ -20,6 +20,7 @@ export default class MViewSchema extends BaseUISchema { toast_autovacuum_enabled: 'x', autovacuum_enabled: 'x', warn_text: undefined, + amname: undefined, ...initValues }); this.getPrivilegeRoleSchema = getPrivilegeRoleSchema; @@ -29,6 +30,7 @@ export default class MViewSchema extends BaseUISchema { schema: [], spcname: [], nodeInfo: null, + amname: [], ...fieldOptions, }; @@ -71,29 +73,38 @@ export default class MViewSchema extends BaseUISchema { },{ id: 'comment', label: gettext('Comment'), cell: 'text', type: 'multiline', - },{ - id: 'definition', label: gettext('Definition'), cell: 'text', - type: 'sql', mode: ['create', 'edit'], group: gettext('Definition'), - isFullTab: true, controlProps: { readOnly: this.nodeInfo && 'catalog' in this.nodeInfo ? true: false }, },{ id: 'with_data', label: gettext('With data?'), - group: gettext('Storage'), mode: ['edit', 'create'], + group: gettext('Definition'), mode: ['edit', 'create'], type: 'switch', },{ id: 'spcname', label: gettext('Tablespace'), cell: 'text', - type: 'select', group: gettext('Storage'), + type: 'select', group: gettext('Definition'), options: obj.fieldOptions.spcname, controlProps: { allowClear: false, first_empty: false, }, + }, { + id: 'amname', label: gettext('Access Method'), group: gettext('Definition'), + type: 'select', mode: ['create', 'properties', 'edit'], min_version: 120000, + options: obj.fieldOptions.table_amname_list, + disabled: (state) => { + if (obj.getServerVersion() < 150000 && !obj.isNew(state)) { + return true; + } + }, },{ id: 'fillfactor', label: gettext('Fill factor'), - group: gettext('Storage'), mode: ['edit', 'create'], + group: gettext('Definition'), mode: ['edit', 'create'], noEmpty: false, type: 'int', controlProps: {min: 10, max: 100} },{ id: 'vacuum_settings_str', label: gettext('Storage settings'), - type: 'multiline', group: gettext('Storage'), mode: ['properties'], + type: 'multiline', group: gettext('Definition'), mode: ['properties'], + },{ + id: 'definition', label: gettext('Definition'), cell: 'text', + type: 'sql', mode: ['create', 'edit'], group: gettext('Code'), + isFullTab: true, controlProps: { readOnly: this.nodeInfo && 'catalog' in this.nodeInfo ? true: false }, }, { type: 'nested-tab', group: gettext('Parameter'), mode: ['create', 'edit'], @@ -128,7 +139,7 @@ export default class MViewSchema extends BaseUISchema { /* mview definition validation*/ if (isEmptyString(state.definition)) { - errmsg = gettext('Please enter view definition.'); + errmsg = gettext('Please enter view code.'); setError('definition', errmsg); return true; } else { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/create.sql new file mode 100644 index 000000000..f05f828ce --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/create.sql @@ -0,0 +1,50 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ data.schema }}.{{ data.name }} + +-- DROP MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} +{% if data.default_amname and data.default_amname != data.amname %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} +{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% set ns = namespace(add_comma=false) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if ns.add_comma %}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% set ns.add_comma = true%}{% endif %}{% endfor %} +{{ '\n' }}) +{% 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 IF EXISTS {{ 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(conn) }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/create_access_method.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/create_access_method.sql new file mode 100644 index 000000000..e5505b2e0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/create_access_method.sql @@ -0,0 +1,3 @@ +CREATE ACCESS METHOD {{ data.name }} + TYPE {{ data.type }} + HANDLER {{ data.handler }} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/get_access_methods.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/get_access_methods.sql new file mode 100644 index 000000000..2a93232bf --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/get_access_methods.sql @@ -0,0 +1,3 @@ +-- Fetches access methods +SELECT oid, amname +FROM pg_catalog.pg_am WHERE amtype = 't'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/properties.sql new file mode 100644 index 000000000..96f4fda4a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/properties.sql @@ -0,0 +1,112 @@ +{# ========================== 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(spcname::text) > 0 THEN spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END as spcname, + (SELECT st.setting from pg_catalog.pg_settings st + WHERE st.name = 'default_table_access_method') as default_amname, + c.relacl, + nsp.nspname as schema, + pg_catalog.pg_get_userbyid(c.relowner) AS owner, + description AS comment, + pg_catalog.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 %} + pg_catalog.array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.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, am.amname, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable +FROM + pg_catalog.pg_class c +LEFT OUTER JOIN pg_catalog.pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = c.reltoastrelid +LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = c.relam + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_catalog.pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (pg_catalog.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_catalog.pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_catalog.pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/update.sql new file mode 100644 index 000000000..4ce4a7f9b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/12_plus/sql/update.sql @@ -0,0 +1,207 @@ +{# ===================== Update View ===================#} +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} +{% if data.amname and data.amname != o_data.amname %} +USING {{ data.amname }} +{% endif %} +{% if data.fillfactor or o_data.fillfactor %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% elif o_data.fillfactor %} + FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% 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 %} +{% 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 is defined %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% if o_data.owner and not data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(o_data.owner) }}; + +{% endif %} +{% if o_data.comment and not data.comment %} +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ o_data.comment|qtLiteral(conn) }}; +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcname and o_data.spcname != data.spcname -%} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + SET TABLESPACE {{ data.spcname }}; + +{% endif %} +{# ======= SET/RESET Fillfactor ========= #} +{% if data.fillfactor and o_data.fillfactor != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 Autovacuum options ===== #} +{% if data.autovacuum_custom is defined and data.autovacuum_custom == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %} + +{% if data.toast_autovacuum is defined and data.toast_autovacuum == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %}{#-- toast_endif ends --#} +{% if data['vacuum_data']['changed']|length > 0 or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} SET( +{% if data.autovacuum_enabled in ('t', 'f') %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 or data.toast_autovacuum_enabled in ('t', 'f') %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled in ('t', 'f') %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} + +); +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 or data.autovacuum_enabled == 'x' or data.toast_autovacuum_enabled == 'x' %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( +{% if data.autovacuum_enabled == 'x' %} + autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 or data.toast_autovacuum_enabled == 'x' %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled == 'x' %} + toast.autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['reset'] %} {{ field.name }}{% if not loop.last %}, +{% endif %} +{% endfor %} + +); +{% endif %} +{# ===== End check for custom autovacuum ===== #} +{% 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(conn) }}; +{% 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 -%} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ 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 %} +{{ SECLABEL.UNSET(conn, 'MATERIALIZED VIEW', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql new file mode 100644 index 000000000..ca6ba22b2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql @@ -0,0 +1,214 @@ +{# ===================== Update View ===================#} +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} +{% if data.amname and data.amname != o_data.amname%} +USING {{ data.amname }} +{% endif %} +{% if data.fillfactor or o_data.fillfactor %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% elif o_data.fillfactor %} + FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% 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 %} +{% 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 is defined %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% if o_data.owner and not data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(o_data.owner) }}; + +{% endif %} +{% if o_data.comment and not data.comment %} +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ o_data.comment|qtLiteral(conn) }}; +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcname and o_data.spcname != data.spcname -%} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + SET TABLESPACE {{ data.spcname }}; + +{% endif %} +{# ======= SET/RESET Fillfactor ========= #} +{% if data.fillfactor and o_data.fillfactor != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +RESET( + FILLFACTOR +); + +{% endif %} +{# ======= Change Access Method ========= #} +{% if data.amname and o_data.amname != data.amname %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + SET ACCESS METHOD {{ data.amname }}; + +{% endif %} +{# ======= Change Access Method end ========= #} +{# ===== 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 Autovacuum options ===== #} +{% if data.autovacuum_custom is defined and data.autovacuum_custom == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %} + +{% if data.toast_autovacuum is defined and data.toast_autovacuum == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %}{#-- toast_endif ends --#} +{% if data['vacuum_data']['changed']|length > 0 or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} SET( +{% if data.autovacuum_enabled in ('t', 'f') %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 or data.toast_autovacuum_enabled in ('t', 'f') %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled in ('t', 'f') %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} + +); +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 or data.autovacuum_enabled == 'x' or data.toast_autovacuum_enabled == 'x' %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( +{% if data.autovacuum_enabled == 'x' %} + autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 or data.toast_autovacuum_enabled == 'x' %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled == 'x' %} + toast.autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['reset'] %} {{ field.name }}{% if not loop.last %}, +{% endif %} +{% endfor %} + +); +{% endif %} +{# ===== End check for custom autovacuum ===== #} +{% 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(conn) }}; +{% 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 -%} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ 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 %} +{{ SECLABEL.UNSET(conn, 'MATERIALIZED VIEW', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/create.sql new file mode 100644 index 000000000..64b859776 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/create.sql @@ -0,0 +1,50 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ 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{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} +{% if data.default_amname and data.default_amname != data.amname %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} +{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% set ns = namespace(add_comma=false) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if ns.add_comma %}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% set ns.add_comma = true%}{% endif %}{% endfor %} +{{ '\n' }}) +{% 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 IF EXISTS {{ 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(conn) }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/get_access_methods.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/get_access_methods.sql new file mode 100644 index 000000000..2a93232bf --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/get_access_methods.sql @@ -0,0 +1,3 @@ +-- Fetches access methods +SELECT oid, amname +FROM pg_catalog.pg_am WHERE amtype = 't'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/properties.sql new file mode 100644 index 000000000..c69930da1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/properties.sql @@ -0,0 +1,112 @@ +{# ========================== 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(spcname::text) > 0 THEN spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END as spcname, + (SELECT st.setting from pg_catalog.pg_settings st + WHERE st.name = 'default_table_access_method') as default_amname, + c.relacl, + nsp.nspname as schema, + pg_catalog.pg_get_userbyid(c.relowner) AS owner, + description AS comment, + pg_catalog.pg_get_viewdef(c.oid) 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 %} + pg_catalog.array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.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, am.amname, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable +FROM + pg_catalog.pg_class c +LEFT OUTER JOIN pg_catalog.pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = c.reltoastrelid +LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = c.relam + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_catalog.pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (pg_catalog.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_catalog.pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_catalog.pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/update.sql new file mode 100644 index 000000000..997f27528 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/12_plus/sql/update.sql @@ -0,0 +1,207 @@ +{# ===================== Update View ===================#} +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} +{% if data.amname and data.amname != o_data.amname %} +USING {{ data.amname }} +{% endif %} +{% if data.fillfactor or o_data.fillfactor %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% elif o_data.fillfactor %} + FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% 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 %} +{% 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 is defined %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% if o_data.owner and not data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(o_data.owner) }}; + +{% endif %} +{% if o_data.comment and not data.comment %} +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ o_data.comment|qtLiteral(conn) }}; +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcoid and o_data.spcoid != data.spcoid -%} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 Autovacuum options ===== #} +{% if data.autovacuum_custom is defined and data.autovacuum_custom == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %} + +{% if data.toast_autovacuum is defined and data.toast_autovacuum == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %}{#-- toast_endif ends --#} +{% if data['vacuum_data']['changed']|length > 0 or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} SET( +{% if data.autovacuum_enabled in ('t', 'f') %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 or data.toast_autovacuum_enabled in ('t', 'f') %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled in ('t', 'f') %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} + +); +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 or data.autovacuum_enabled == 'x' or data.toast_autovacuum_enabled == 'x' %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( +{% if data.autovacuum_enabled == 'x' %} + autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 or data.toast_autovacuum_enabled == 'x' %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled == 'x' %} + toast.autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['reset'] %} {{ field.name }}{% if not loop.last %}, +{% endif %} +{% endfor %} + +); +{% endif %} +{# ===== End check for custom autovacuum ===== #} +{% 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(conn) }}; +{% 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 -%} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ 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 %} +{{ SECLABEL.UNSET(conn, 'MATERIALIZED VIEW', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql new file mode 100644 index 000000000..6661e1054 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql @@ -0,0 +1,214 @@ +{# ===================== Update View ===================#} +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ 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 IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} +{% if data.amname and data.amname != o_data.amname%} +USING {{ data.amname }} +{% endif %} +{% if data.fillfactor or o_data.fillfactor %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% elif o_data.fillfactor %} + FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% 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 %} +{% 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 is defined %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% if o_data.owner and not data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(o_data.owner) }}; + +{% endif %} +{% if o_data.comment and not data.comment %} +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ o_data.comment|qtLiteral(conn) }}; +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcoid and o_data.spcoid != data.spcoid -%} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +RESET( + FILLFACTOR +); + +{% endif %} +{# ======= Change Access Method ========= #} +{% if data.amname and o_data.amname != data.amname %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + SET ACCESS Method {{ data.amname }}; + +{% endif %} +{# ======= Change Access Method end ========= #} +{# ===== 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 Autovacuum options ===== #} +{% if data.autovacuum_custom is defined and data.autovacuum_custom == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %} + +{% if data.toast_autovacuum is defined and data.toast_autovacuum == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ 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 +); + +{% endif %}{#-- toast_endif ends --#} +{% if data['vacuum_data']['changed']|length > 0 or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} SET( +{% if data.autovacuum_enabled in ('t', 'f') %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 or data.toast_autovacuum_enabled in ('t', 'f') %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled in ('t', 'f') %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} + +); +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 or data.autovacuum_enabled == 'x' or data.toast_autovacuum_enabled == 'x' %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( +{% if data.autovacuum_enabled == 'x' %} + autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 or data.toast_autovacuum_enabled == 'x' %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled == 'x' %} + toast.autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['reset'] %} {{ field.name }}{% if not loop.last %}, +{% endif %} +{% endfor %} + +); +{% endif %} +{# ===== End check for custom autovacuum ===== #} +{% 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(conn) }}; +{% 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 -%} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ 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 %} +{{ SECLABEL.UNSET(conn, 'MATERIALIZED VIEW', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am_msql.sql new file mode 100644 index 000000000..d43f961e4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am_msql.sql @@ -0,0 +1,12 @@ +CREATE MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#" +USING heap +TABLESPACE pg_default +AS +SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_am_$%{}[]()&*^!/@`#" + OWNER TO postgres; + +COMMENT ON MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#" + IS 'comment1'; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json new file mode 100644 index 000000000..146fb1241 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json @@ -0,0 +1,279 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Materialised Views", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1" + }, + "expected_sql_file": "create_mview.sql", + "expected_msql_file": "create_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Adding privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "postgres", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview.sql", + "expected_msql_file": "alter_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Remove all privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "postgres", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_drop_all_priv.sql", + "expected_msql_file": "alter_mview_drop_all_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change grantee in privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "postgres", + "old_grantee": "postgres", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_change_grantee_priv.sql", + "expected_msql_file": "alter_mview_change_grantee_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change definition)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "definition": "SELECT 12 AS col1;" + }, + "expected_sql_file": "alter_mview_definition.sql", + "expected_msql_file": "alter_mview_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Fillfactor)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "fillfactor": "18", + "with_data": true + }, + "expected_sql_file": "alter_mview_add_fillfactor.sql", + "expected_msql_file": "alter_mview_add_fillfactor_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (add table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "t", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": 0.2 + } + ] + } + }, + "expected_sql_file": "alter_mview_add_table_parameter.sql", + "expected_msql_file": "alter_mview_add_table_parameter_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (remove table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "x", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": null + } + ] + } + }, + "expected_sql_file": "alter_mview_remove_table_parameter.sql", + "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql" + } + ] + } + \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/tests.json new file mode 100644 index 000000000..4180ec310 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/tests.json @@ -0,0 +1,224 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Table for Views", + "endpoint": "NODE-table.obj", + "sql_endpoint": "NODE-table.sql_id", + "data": { + "name": "test_view_table", + "check_constraint": [], + "coll_inherits": "[]", + "columns": [ + { + "name": "col1", + "cltype": "integer" + } + ], + "schema": "public" + } + }, + { + "type": "create", + "name": "Create View", + "endpoint": "NODE-view.obj", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql", + "data": { + "definition": "select col1 from test_view_table;", + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "local", + "security_barrier": false, + "comment":"Testcomment", + "datacl":[{"grantee":"postgres", "old_grantee": "postgres", "grantor":"postgres", "privileges":[{"privilege_type": "a", "privilege": true, + "with_grant":false}]}] + }, + "expected_sql_file": "create_view.sql", + "expected_msql_file": "create_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl":[{"grantee":"postgres", "grantor":"postgres", "old_grantee": "postgres", "privileges":[{"privilege_type": "a", "privilege": true, + "with_grant":false}]}] + }, + "expected_sql_file": "alter_view.sql", + "expected_msql_file": "alter_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (changing code)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "definition": "SELECT * FROM test_view_table;" + }, + "expected_sql_file": "alter_view_definition.sql", + "expected_msql_file": "alter_view_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (adding privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl":{ + "added":[ + { + "grantee":"PUBLIC", + "grantor":"postgres", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_add_some_priv.sql", + "expected_msql_file": "alter_view_add_some_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges (PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "deleted":[ + { + "grantee":"PUBLIC", + "grantor":"postgres", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + } + }, + { + "type": "alter", + "name": "Alter View (changing privileges (postgres to PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "changed":[ + { + "grantee":"PUBLIC", + "grantor":"postgres", + "old_grantee": "postgres", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_update_priv.sql", + "expected_msql_file": "alter_view_update_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "deleted":[ + { + "grantee":"PUBLIC", + "grantor":"postgres", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_delete_priv.sql", + "expected_msql_file": "alter_view_delete_priv_msql.sql" + }, + { + "type": "delete", + "name": "Drop View", + "endpoint": "NODE-view.obj_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "postgres", + "schema": "public" + } + }, + { + "type": "delete", + "name": "Drop Table for view", + "endpoint": "NODE-table.obj_id", + "data": { + "name": "test_view_table", + "owner": "postgres", + "schema": "public" + } + } + ] + } + \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json index 1feb2d1a5..0141eec0e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json @@ -254,6 +254,25 @@ }, "expected_sql_file": "alter_mview_remove_table_parameter.sql", "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json index 1feb2d1a5..0141eec0e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json @@ -254,6 +254,25 @@ }, "expected_sql_file": "alter_mview_remove_table_parameter.sql", "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am_msql.sql new file mode 100644 index 000000000..361c79eb7 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am_msql.sql @@ -0,0 +1,12 @@ +CREATE MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#" +USING heap +TABLESPACE pg_default +AS +SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_am_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +COMMENT ON MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#" + IS 'comment1'; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json new file mode 100644 index 000000000..ed01fea19 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json @@ -0,0 +1,279 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Materialised Views", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1" + }, + "expected_sql_file": "create_mview.sql", + "expected_msql_file": "create_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Adding privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview.sql", + "expected_msql_file": "alter_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Remove all privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_drop_all_priv.sql", + "expected_msql_file": "alter_mview_drop_all_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change grantee in privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "old_grantee": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_change_grantee_priv.sql", + "expected_msql_file": "alter_mview_change_grantee_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change definition)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "definition": "SELECT 12 AS col1;" + }, + "expected_sql_file": "alter_mview_definition.sql", + "expected_msql_file": "alter_mview_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Fillfactor)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "fillfactor": "18", + "with_data": true + }, + "expected_sql_file": "alter_mview_add_fillfactor.sql", + "expected_msql_file": "alter_mview_add_fillfactor_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (add table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "t", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": 0.2 + } + ] + } + }, + "expected_sql_file": "alter_mview_add_table_parameter.sql", + "expected_msql_file": "alter_mview_add_table_parameter_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (remove table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "x", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": null + } + ] + } + }, + "expected_sql_file": "alter_mview_remove_table_parameter.sql", + "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql" + } + ] + } + \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/tests.json new file mode 100644 index 000000000..312b25ab3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/tests.json @@ -0,0 +1,206 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Table for Views", + "endpoint": "NODE-table.obj", + "sql_endpoint": "NODE-table.sql_id", + "data": { + "name": "test_view_table", + "check_constraint": [], + "coll_inherits": "[]", + "columns": [ + { + "name": "col1", + "cltype": "integer" + } + ], + "schema": "public" + } + }, + { + "type": "create", + "name": "Create View", + "endpoint": "NODE-view.obj", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql", + "data": { + "definition": "select col1 from test_view_table;", + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "local", + "security_barrier": false, + "comment":"Testcomment", + "datacl":[{"grantee":"enterprisedb", "grantor":"enterprisedb", "privileges":[{"privilege_type": "a", "privilege": true, + "with_grant":false}]}] + }, + "expected_sql_file": "create_view.sql", + "expected_msql_file": "create_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl":[{"grantee":"enterprisedb", "grantor":"enterprisedb", "privileges":[{"privilege_type": "a", "privilege": true, + "with_grant":false}]}] + }, + "expected_sql_file": "alter_view.sql", + "expected_msql_file": "alter_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (adding privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "datacl":{ + "added":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_add_some_priv.sql", + "expected_msql_file": "alter_view_add_some_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges (PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "deleted":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + } + }, + { + "type": "alter", + "name": "Alter View (changing privileges (enterprisedb to PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "changed":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "old_grantee": "enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_update_priv.sql", + "expected_msql_file": "alter_view_update_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "deleted":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_delete_priv.sql", + "expected_msql_file": "alter_view_delete_priv_msql.sql" + }, + { + "type": "delete", + "name": "Drop View", + "endpoint": "NODE-view.obj_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public" + } + }, + { + "type": "delete", + "name": "Drop Table for view", + "endpoint": "NODE-table.obj_id", + "data": { + "name": "test_view_table", + "owner": "enterprisedb", + "schema": "public" + } + } + ] + } + \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json index aacf62106..44a9d5cb5 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json @@ -254,6 +254,25 @@ }, "expected_sql_file": "alter_mview_remove_table_parameter.sql", "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json index aacf62106..44a9d5cb5 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json @@ -254,6 +254,25 @@ }, "expected_sql_file": "alter_mview_remove_table_parameter.sql", "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql" } ] } diff --git a/web/regression/javascript/schema_ui_files/mview.ui.spec.js b/web/regression/javascript/schema_ui_files/mview.ui.spec.js index de9c6915e..2902e0d64 100644 --- a/web/regression/javascript/schema_ui_files/mview.ui.spec.js +++ b/web/regression/javascript/schema_ui_files/mview.ui.spec.js @@ -40,6 +40,7 @@ describe('MaterializedViewSchema', ()=>{ /* https://material-ui.com/guides/testing/#api */ beforeAll(()=>{ mount = createMount(); + spyOn(schemaObj, 'getServerVersion').and.returnValue(100000); }); afterAll(() => { @@ -68,7 +69,7 @@ describe('MaterializedViewSchema', ()=>{ state.definition = null; schemaObj.validate(state, setError); - expect(setError).toHaveBeenCalledWith('definition', 'Please enter view definition.'); + expect(setError).toHaveBeenCalledWith('definition', 'Please enter view code.'); state.definition = 'SELECT 1;'; schemaObj.validate(state, setError);