Add support of DEPENDS/NO DEPENDS ON EXTENSION for INDEX. #6388

pull/9347/head^2
Rohit Bhati 2025-11-19 12:32:35 +05:30 committed by GitHub
parent 4129d38410
commit f06668aed9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 508 additions and 32 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -48,6 +48,9 @@ Use the fields in the *Definition* tab to define the index:
* Select *brin* to create a BRIN index. A BRIN index may improve * Select *brin* to create a BRIN index. A BRIN index may improve
performance when managing minimum and maximum values and ranges. performance when managing minimum and maximum values and ranges.
* Use the drop-down listbox next to *Depends on extensions* to select the extension
that this index depends on (for example, edbspl). If set, dropping the extension
will automatically drop the index as well.
* Use the *Fill Factor* field to specify a fill factor for the index. The fill * Use the *Fill Factor* field to specify a fill factor for the index. The fill
factor specifies how full the selected method will try to fill each index factor specifies how full the selected method will try to fill each index
page. page.

View File

@ -10,7 +10,7 @@ the REFRESH MATERIALIZED VIEW command to update the content of a materialized
view. view.
The *Materialized View* dialog organizes the development of a materialized_view The *Materialized View* dialog organizes the development of a materialized_view
through the following dialog tabs: *General*, *Definition*, *Storage*, through the following dialog tabs: *General*, *Definition*, *Code*,
*Parameter*, and *Security*. The *SQL* tab displays the SQL code generated by *Parameter*, and *Security*. The *SQL* tab displays the SQL code generated by
dialog selections. dialog selections.
@ -31,10 +31,10 @@ Use the fields in the *General* tab to identify the materialized view:
Click the *Definition* tab to continue. Click the *Definition* tab to continue.
.. image:: images/materialized_view_definition.png .. image:: images/materialized_view_definition.png
:alt: Materialized view dialog storage tab :alt: Materialized view dialog definition tab
:align: center :align: center
Use the fields in the *Storage* tab to maintain the materialized view: Use the fields in the *Definition* tab to maintain the materialized view:
* Move the *With Data* switch to the *Yes* position to specify the materialized * Move the *With Data* switch to the *Yes* position to specify the materialized
view should be populated at creation time. If not, the materialized view view should be populated at creation time. If not, the materialized view
@ -54,7 +54,7 @@ Use the fields in the *Storage* tab to maintain the materialized view:
Click the *Code* tab to continue. Click the *Code* tab to continue.
.. image:: images/materialized_view_code.png .. image:: images/materialized_view_code.png
:alt: Materialized view dialog definition tab :alt: Materialized view dialog code tab
:align: center :align: center
Use the text editor field in the *Code* tab to provide the query that will Use the text editor field in the *Code* tab to provide the query that will

View File

@ -125,6 +125,8 @@ define('pgadmin.node.index', [
}, },
getSchema: (treeNodeInfo, itemNodeData) => { getSchema: (treeNodeInfo, itemNodeData) => {
let nodeObj = pgAdmin.Browser.Nodes['index']; let nodeObj = pgAdmin.Browser.Nodes['index'];
let nodeExtObj = pgBrowser.Nodes['extension'];
return new IndexSchema( return new IndexSchema(
{ {
tablespaceList: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{ tablespaceList: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{
@ -133,7 +135,17 @@ define('pgadmin.node.index', [
amnameList : ()=>getNodeAjaxOptions('get_access_methods', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}), amnameList : ()=>getNodeAjaxOptions('get_access_methods', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
columnList: ()=>getNodeListByName('column', treeNodeInfo, itemNodeData, {}), columnList: ()=>getNodeListByName('column', treeNodeInfo, itemNodeData, {}),
collationList: ()=>getNodeAjaxOptions('get_collations', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}), collationList: ()=>getNodeAjaxOptions('get_collations', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
opClassList: ()=>getNodeAjaxOptions('get_op_class', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}) opClassList: ()=>getNodeAjaxOptions('get_op_class', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
extensionsList:()=>getNodeAjaxOptions('nodes', nodeExtObj, treeNodeInfo, itemNodeData, { cacheLevel: 'server'},
(data)=>{
let res = [];
if (data && _.isArray(data)) {
_.each(data, function(d) {
res.push({label: d.label, value: d.label, data: d});
});
}
return res;
}),
}, },
{ {
node_info: treeNodeInfo node_info: treeNodeInfo

View File

@ -505,7 +505,23 @@ export default class IndexSchema extends BaseUISchema {
return Promise.resolve(()=>{/*This is intentional (SonarQube)*/}); return Promise.resolve(()=>{/*This is intentional (SonarQube)*/});
} }
}, },
},{ },
{
id: 'dependsonextensions',
label: gettext('Depends on extensions'),
group: gettext('Definition'),
type: 'select',
options: this.fieldOptions.extensionsList,
controlProps: {
multiple: true,
allowClear: true,
allowSelectAll: true,
placeholder: gettext('Select the Depends on extensions...'),
},
min_version: 130000,
mode: ['create', 'edit', 'properties']
},
{
type: 'nested-fieldset', label: gettext('With'), group: gettext('Definition'), type: 'nested-fieldset', label: gettext('With'), group: gettext('Definition'),
schema: this.withSchema, schema: this.withSchema,
},{ },{

View File

@ -0,0 +1,2 @@
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
NO DEPENDS ON EXTENSION postgres_fdw;

View File

@ -0,0 +1,17 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default
WHERE id < 100;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION plpgsql;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -11,6 +11,5 @@ CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"
ALTER TABLE IF EXISTS public.test_table_for_indexes ALTER TABLE IF EXISTS public.test_table_for_indexes
CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#"; CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#";
COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#" COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment'; IS 'Test Comment';

View File

@ -0,0 +1,16 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default
WHERE id < 100;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION plpgsql;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION postgres_fdw;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,20 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default
WHERE id < 100;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION plpgsql;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION postgres_fdw;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -1,5 +1,17 @@
{ {
"scenarios": [ "scenarios": [
{
"type": "create",
"name": "Create Extension",
"endpoint": "NODE-extension.obj",
"sql_endpoint": "NODE-extension.sql_id",
"data": {
"name": "postgres_fdw",
"version": "",
"relocatable": true
},
"store_object_id": true
},
{ {
"type": "create", "type": "create",
"name": "Create Table for indexes", "name": "Create Table for indexes",
@ -21,6 +33,75 @@
}, },
"store_object_id": true "store_object_id": true
}, },
{
"type": "create",
"name": "Create btree index with extensions.",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"colname":"name",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"deduplicate_items": false,
"indisunique":true,
"indnullsnotdistinct":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100",
"dependsonextensions": ["plpgsql", "postgres_fdw"]
},
"expected_sql_file": "create_index_with_ext.sql",
"expected_msql_file": "create_index_with_ext.msql"
},
{
"type": "alter",
"name": "Alter index with NO DEPENDS ON",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#",
"dependsonextensions": ["plpgsql"]
},
"expected_sql_file": "alter_index_no_depends.sql",
"expected_msql_file": "alter_index_no_depends.msql"
},
{
"type": "delete",
"name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "delete",
"name": "Drop Extension",
"endpoint": "NODE-extension.delete",
"data": {
"ids": ["<postgres_fdw>"]
},
"preprocess_data": true
},
{ {
"type": "create", "type": "create",
"name": "Create btree index with ASC and NULLS LAST -- 13 Plus", "name": "Create btree index with ASC and NULLS LAST -- 13 Plus",

View File

@ -0,0 +1,18 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT
WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default
WHERE id < 100;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION plpgsql;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -12,6 +12,5 @@ CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"
ALTER TABLE IF EXISTS public.test_table_for_indexes ALTER TABLE IF EXISTS public.test_table_for_indexes
CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#"; CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#";
COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#" COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment'; IS 'Test Comment';

View File

@ -0,0 +1,17 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT
WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default
WHERE id < 100;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION plpgsql;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION postgres_fdw;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,21 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT
WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default
WHERE id < 100;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION plpgsql;
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
DEPENDS ON EXTENSION postgres_fdw;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -1,5 +1,17 @@
{ {
"scenarios": [ "scenarios": [
{
"type": "create",
"name": "Create Extension",
"endpoint": "NODE-extension.obj",
"sql_endpoint": "NODE-extension.sql_id",
"data": {
"name": "postgres_fdw",
"version": "",
"relocatable": true
},
"store_object_id": true
},
{ {
"type": "create", "type": "create",
"name": "Create Table for indexes", "name": "Create Table for indexes",
@ -21,6 +33,75 @@
}, },
"store_object_id": true "store_object_id": true
}, },
{
"type": "create",
"name": "Create btree index with extensions.",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"colname":"name",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"deduplicate_items": false,
"indisunique":true,
"indnullsnotdistinct":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100",
"dependsonextensions": ["plpgsql", "postgres_fdw"]
},
"expected_sql_file": "create_index_with_ext.sql",
"expected_msql_file": "create_index_with_ext.msql"
},
{
"type": "alter",
"name": "Alter index with NO DEPENDS ON",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#",
"dependsonextensions": ["plpgsql"]
},
"expected_sql_file": "alter_index_no_depends.sql",
"expected_msql_file": "alter_index_no_depends.msql"
},
{
"type": "delete",
"name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "delete",
"name": "Drop Extension",
"endpoint": "NODE-extension.delete",
"data": {
"ids": ["<postgres_fdw>"]
},
"preprocess_data": true
},
{ {
"type": "create", "type": "create",
"name": "Create btree index with ASC and NULLS LAST -- 15 Plus", "name": "Create btree index with ASC and NULLS LAST -- 15 Plus",

View File

@ -31,6 +31,7 @@
"name": "test_index_add", "name": "test_index_add",
"spcname": "pg_default", "spcname": "pg_default",
"amname": "btree", "amname": "btree",
"dependsonextensions": ["plpgsql"],
"columns": [ "columns": [
{ {
"colname": "id", "colname": "id",
@ -529,7 +530,8 @@
}, },
"test_data": { "test_data": {
"description": "This is test comment for index", "description": "This is test comment for index",
"name": "updating name for index using api tests" "name": "updating name for index using api tests",
"dependsonextensions": ["plpgsql"]
}, },
"mocking_required": false, "mocking_required": false,
"mock_data": {}, "mock_data": {},

View File

@ -242,6 +242,9 @@ def get_sql(conn, **kwargs):
show_sys_obj = kwargs.get('show_sys_objects', False) show_sys_obj = kwargs.get('show_sys_objects', False)
name = data['name'] if 'name' in data else None name = data['name'] if 'name' in data else None
if data.get('dependsonextensions') is None:
data['dependsonextensions'] = \
data.get('dependsonextensions') or []
if idx is not None: if idx is not None:
sql = render_template("/".join([template_path, 'properties.sql']), sql = render_template("/".join([template_path, 'properties.sql']),
did=did, tid=tid, idx=idx, did=did, tid=tid, idx=idx,
@ -272,7 +275,9 @@ def get_sql(conn, **kwargs):
old_data['withcheck'].startswith('(') and \ old_data['withcheck'].startswith('(') and \
old_data['withcheck'].endswith(')'): old_data['withcheck'].endswith(')'):
old_data['withcheck'] = old_data['withcheck'][1:-1] old_data['withcheck'] = old_data['withcheck'][1:-1]
if old_data.get('dependsonextensions') is None:
old_data['dependsonextensions'] = \
old_data.get('dependsonextensions') or []
# If name is not present in data then # If name is not present in data then
# we will fetch it from old data, we also need schema & table name # we will fetch it from old data, we also need schema & table name
if 'name' not in data: if 'name' not in data:

View File

@ -0,0 +1,33 @@
CREATE{% if data.indisunique %} UNIQUE{% endif %} INDEX{% if add_not_exists_clause %} IF NOT EXISTS{% endif %}{% if data.isconcurrent %} CONCURRENTLY{% endif %}{% if data.name %} {{conn|qtIdent(data.name)}}{% endif %}
ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %}
{% if mode == 'create' %}
({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{% if c.is_exp %}({{c.colname}}){% else %}{{conn|qtIdent(c.colname)}}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %}
{{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %}
FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %})
{% if data.include|length > 0 %}
INCLUDE({% for col in data.include %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(col)}}{% endfor %})
{% endif %}
{% else %}
{## We will get indented data from postgres for column ##}
({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{c.colname}}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %}
{{c.op_class}}{% endif %}{% if c.sort_order is defined %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined %} NULLS {% if c.nulls %}
FIRST{% else %}LAST{% endif %}{% endif %}{% endfor %})
{% if data.include|length > 0 %}
INCLUDE({% for col in data.include %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(col)}}{% endfor %})
{% endif %}
{% endif %}
{% if data.storage_parameters %}
WITH ({% for key, value in data.storage_parameters.items() %}{% if loop.index != 1 %}, {% endif %}{{key}}={{value}}{% endfor %})
{% endif %}{% if data.spcname %}
TABLESPACE {{conn|qtIdent(data.spcname)}}{% endif %}{% if data.indconstraint %}
WHERE {{data.indconstraint}}{% endif %};
{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}
ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}

View File

@ -30,6 +30,12 @@ SELECT DISTINCT ON (cls.relname)
WHEN con.contype IN ('p', 'u', 'x') THEN desp.description WHEN con.contype IN ('p', 'u', 'x') THEN desp.description
ELSE des.description ELSE des.description
END AS description, END AS description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = cls.oid
) AS dependsonextensions,
pg_catalog.pg_get_expr(idx.indpred, idx.indrelid, true) AS indconstraint, pg_catalog.pg_get_expr(idx.indpred, idx.indrelid, true) AS indconstraint,
con.contype, con.contype,
con.condeferrable, con.condeferrable,

View File

@ -0,0 +1,110 @@
{## Changes name ##}
{% if data.name and o_data.name != data.name %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, o_data.name)}}
RENAME TO {{conn|qtIdent(data.name)}};
{% endif %}
{## Changes fillfactor ##}
{% if data.fillfactor and o_data.fillfactor != data.fillfactor %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (fillfactor={{data.fillfactor}});
{% elif (data.fillfactor == '' or data.fillfactor == None) and o_data.fillfactor|default('', 'true') != data.fillfactor %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
RESET (fillfactor);
{% endif %}
{## Changes gin_pending_list_limit ##}
{% if data.gin_pending_list_limit and o_data.gin_pending_list_limit != data.gin_pending_list_limit %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (gin_pending_list_limit={{data.gin_pending_list_limit}});
{% elif (data.gin_pending_list_limit == '' or data.gin_pending_list_limit == None) and o_data.gin_pending_list_limit|default('', 'true') != data.gin_pending_list_limit %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
RESET (gin_pending_list_limit);
{% endif %}
{## Changes deduplicate_items ##}
{% if data.deduplicate_items in [True, False] and o_data.deduplicate_items != data.deduplicate_items %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (deduplicate_items={{data.deduplicate_items}});
{% endif %}
{## Changes pages_per_range ##}
{% if data.pages_per_range and o_data.pages_per_range != data.pages_per_range %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (pages_per_range={{data.pages_per_range}});
{% elif (data.pages_per_range == '' or data.pages_per_range == None) and o_data.pages_per_range|default('', 'true') != data.pages_per_range %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
RESET (pages_per_range);
{% endif %}
{## Changes buffering ##}
{% if data.buffering and o_data.buffering != data.buffering %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (buffering={{data.buffering}});
{% elif (data.buffering == '' or data.buffering == None) and o_data.buffering|default('', 'true') != data.buffering %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
RESET (buffering);
{% endif %}
{## Changes fastupdate ##}
{% if data.fastupdate in [True, False] and o_data.fastupdate != data.fastupdate %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (fastupdate={{data.fastupdate}});
{% endif %}
{## Changes autosummarize ##}
{% if data.autosummarize in [True, False] and o_data.autosummarize != data.autosummarize %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET (autosummarize={{data.autosummarize}});
{% endif %}
{## Changes tablespace ##}
{% if data.spcname and o_data.spcname != data.spcname %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
SET TABLESPACE {{conn|qtIdent(data.spcname)}};
{% endif %}
{## Alter index to use cluster type ##}
{% if data.indisclustered is defined and o_data.indisclustered != data.indisclustered %}
{% if data.indisclustered %}
ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
CLUSTER ON {{conn|qtIdent(data.name)}};
{% else %}
ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
SET WITHOUT CLUSTER;
{% endif %}
{% endif %}
{## Changes description ##}
{% if data.description is defined and o_data.description != data.description %}
COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral(conn)}};{% endif %}
{## Alter column statistics##}
{% if update_column %}
{% for col in update_column_data %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
ALTER COLUMN {{col.col_num}} SET STATISTICS {{col.statistics}};
{% endfor %}
{% endif %}
{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}
{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}
{% if ext in new_exts and ext not in old_exts %}
ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}

View File

@ -30,3 +30,10 @@ FIRST{% else %}LAST{% endif %}{% endif %}{% endfor %})
TABLESPACE {{conn|qtIdent(data.spcname)}}{% endif %}{% if data.indconstraint %} TABLESPACE {{conn|qtIdent(data.spcname)}}{% endif %}{% if data.indconstraint %}
WHERE {{data.indconstraint}}{% endif %}; WHERE {{data.indconstraint}}{% endif %};
{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}
ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}

View File

@ -31,6 +31,12 @@ SELECT DISTINCT ON (cls.relname)
WHEN con.contype IN ('p', 'u', 'x') THEN desp.description WHEN con.contype IN ('p', 'u', 'x') THEN desp.description
ELSE des.description ELSE des.description
END AS description, END AS description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = cls.oid
) AS dependsonextensions,
pg_catalog.pg_get_expr(idx.indpred, idx.indrelid, true) AS indconstraint, pg_catalog.pg_get_expr(idx.indpred, idx.indrelid, true) AS indconstraint,
con.contype, con.contype,
con.condeferrable, con.condeferrable,

View File

@ -1,11 +1,9 @@
{## Alter index to use cluster type ##} {## Alter index to use cluster type ##}
{% if data.indisclustered %} {% if data.indisclustered %}
ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}} ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
CLUSTER ON {{conn|qtIdent(data.name)}}; CLUSTER ON {{conn|qtIdent(data.name)}};
{% endif %} {% endif %}
{## Changes description ##} {## Changes description ##}
{% if data.description is defined and data.description %} {% if data.description is defined and data.description %}
COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}} COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral(conn)}};{% endif %} IS {{data.description|qtLiteral(conn)}};{% endif %}

View File

@ -202,6 +202,13 @@ describe('IndexSchema', () => {
}); });
}); });
it('dependsonextensions field exists', ()=>{
let field = _.find(indexSchemaObj.fields, (f)=>f.id=='dependsonextensions');
expect(field).toBeTruthy();
expect(field.type).toBe('select');
expect(field.controlProps.multiple).toBe(true);
});
it('columns formatter', () => { it('columns formatter', () => {
let formatter = _.find(indexSchemaObj.fields, (f) => f.id=='columns').cell().controlProps.formatter; let formatter = _.find(indexSchemaObj.fields, (f) => f.id=='columns').cell().controlProps.formatter;
expect(formatter.fromRaw([{ expect(formatter.fromRaw([{