Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/en_US/images/index_definition.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/en_US/index_dialog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
factor specifies how full the selected method will try to fill each index
page.
Expand Down
8 changes: 4 additions & 4 deletions docs/en_US/materialized_view_dialog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ the REFRESH MATERIALIZED VIEW command to update the content 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
dialog selections.

Expand All @@ -31,10 +31,10 @@ 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 storage tab
:alt: Materialized view dialog definition tab
: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
view should be populated at creation time. If not, the materialized view
Expand All @@ -54,7 +54,7 @@ Use the fields in the *Storage* tab to maintain the materialized view:
Click the *Code* tab to continue.

.. image:: images/materialized_view_code.png
:alt: Materialized view dialog definition tab
:alt: Materialized view dialog code tab
:align: center

Use the text editor field in the *Code* tab to provide the query that will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ define('pgadmin.node.index', [
},
getSchema: (treeNodeInfo, itemNodeData) => {
let nodeObj = pgAdmin.Browser.Nodes['index'];
let nodeExtObj = pgBrowser.Nodes['extension'];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Verify that the extension node is always registered.

The code assumes pgBrowser.Nodes['extension'] exists. If the extension node hasn't been registered, nodeExtObj will be undefined, potentially causing issues in getNodeAjaxOptions at line 138.

Run the following script to verify that the extension node is properly registered before this code executes:


🏁 Script executed:

#!/bin/bash
# Search for extension node registration to confirm it's loaded before index.js
rg -nP --type=js -C3 "Nodes\['extension'\]\s*=" 

Length of output: 828


🏁 Script executed:

#!/bin/bash
# Check for imports/requires of extension.js in index.js
rg -nP --type=js "extension" web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.js

# Search for how these modules are registered/loaded
fd --type f -name "*.py" | xargs grep -l "extension.js\|index.js" | head -10

Length of output: 417


🏁 Script executed:

#!/bin/bash
# Check for plugin registration or module loading configuration
find web/pgadmin/browser/server_groups/servers/databases -name "*.py" -type f -exec grep -l "extensionsList\|extension.*index" {} \; | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any blueprint or module registration in the tables and extensions directories
rg -nP "Blueprint\|register" web/pgadmin/browser/server_groups/servers/databases/extensions/ -g "*.py" | head -10

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for __init__.py files that might control script loading order
cat web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py

Length of output: 39587


🏁 Script executed:

#!/bin/bash
# Find and examine the extensions module __init__.py to check script_load order
cat web/pgadmin/browser/server_groups/servers/databases/extensions/__init__.py

Length of output: 19448


🏁 Script executed:

#!/bin/bash
# Search for any module initialization order or registry configuration
find web/pgadmin/browser/server_groups/servers/databases -name "__init__.py" -type f -exec grep -l "script_load\|register" {} \; | head -5

Length of output: 2034


🏁 Script executed:

#!/bin/bash
# Check if there are any import dependencies between index.js and extension.js
rg -nP --type=js "import|require|getNodeAjaxOptions" web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.js | head -20

Length of output: 684


🏁 Script executed:

#!/bin/bash
# Check if index.js includes any initialization that waits for extension node
rg -nP --type=js -A5 "nodeExtObj\|extension" web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.js

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any module loading/initialization logic in the framework
find web/pgadmin/browser -name "*.py" -type f -exec grep -l "CollectionNodeModule\|script_load" {} \; | xargs grep -l "sort\|order" | head -3

Length of output: 111


🏁 Script executed:

#!/bin/bash
# Get full context around nodeExtObj definition and usage in index.js
rg -nP --type=js -B10 -A10 "let nodeExtObj" web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.js

Length of output: 1308


🏁 Script executed:

#!/bin/bash
# Check the collection.py for module loading/ordering logic
cat web/pgadmin/browser/collection.py | head -100

Length of output: 3116


🏁 Script executed:

#!/bin/bash
# Check browser __init__.py for script loading order
rg -nP "script_load|sort|order" web/pgadmin/browser/__init__.py -A3 -B3 | head -60

Length of output: 445


Add defensive null check for extension node before using it.

The code assumes pgBrowser.Nodes['extension'] is always defined, but both the extension and index modules are triggered on the same event with no documented ordering guarantee. While alphabetical directory structure may provide implicit safety, this lacks defensive programming.

Add a null/undefined check at line 128 before passing nodeExtObj to getNodeAjaxOptions, or verify and document that the framework guarantees extension.js loads first.

🤖 Prompt for AI Agents
In
web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.js
around line 128, the code assumes pgBrowser.Nodes['extension'] exists before
passing it into getNodeAjaxOptions; add a defensive null/undefined check and
handle the missing node: if nodeExtObj is undefined/null, either skip calling
getNodeAjaxOptions (return or no-op), or pass a safe default object (e.g., {})
and/or log a warning—ensure no property access occurs on nodeExtObj when it may
be absent.


return new IndexSchema(
{
tablespaceList: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{
Expand All @@ -133,7 +135,17 @@ define('pgadmin.node.index', [
amnameList : ()=>getNodeAjaxOptions('get_access_methods', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
columnList: ()=>getNodeListByName('column', treeNodeInfo, itemNodeData, {}),
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,23 @@ export default class IndexSchema extends BaseUISchema {
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'),
schema: this.withSchema,
},{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
NO DEPENDS ON EXTENSION postgres_fdw;
Original file line number Diff line number Diff line change
@@ -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 lines +13 to +14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Filename/content mismatch: file adds dependency instead of removing it.

Similar to the 15_plus version, this filename suggests NO DEPENDS ON EXTENSION (removing dependencies), but the content uses DEPENDS ON EXTENSION plpgsql (adding a dependency).

Either:

  • Update the SQL to use ALTER INDEX ... NO DEPENDS ON EXTENSION postgres_fdw; to match the filename, or
  • Rename the file to reflect that it adds a dependency
🤖 Prompt for AI Agents
web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/13_plus/alter_index_no_depends.sql
lines 13-14: the SQL currently adds a dependency (DEPENDS ON EXTENSION plpgsql)
but the filename indicates it should remove one; change the statement to use NO
DEPENDS ON EXTENSION postgres_fdw to match the file name (i.e., ALTER INDEX ...
NO DEPENDS ON EXTENSION postgres_fdw), keeping the same index identifier/quoting
and escaping as-is.


COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"

ALTER TABLE IF EXISTS public.test_table_for_indexes
CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#";

COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
{
"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",
"name": "Create Table for indexes",
Expand All @@ -21,6 +33,75 @@
},
"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",
"name": "Create btree index with ASC and NULLS LAST -- 13 Plus",
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Comment on lines +1 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify filename mismatch with test content.

The filename suggests "no_depends" but the test actually includes an ALTER INDEX ... DEPENDS ON EXTENSION plpgsql statement on Lines 14-15. This appears to be a mismatch between the filename and the test content.

Please verify:

  • Is this test intended to verify removing dependencies (NO DEPENDS)?
  • Should this file be renamed to reflect that it adds a dependency?
  • Or should the test content be updated to match the "no_depends" scenario?

Run the following script to check if there are other test files that might clarify the intended test scenarios:


🏁 Script executed:

#!/bin/bash
# Search for test files related to extension dependencies
fd -e sql -e msql . web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/ | rg -i "depend|ext"

Length of output: 810


Verify filename mismatch with test content.

NO DEPENDS ON EXTENSION syntax was added in PostgreSQL 13, and it marks the index as no longer dependent on that extension if NO is specified. The filename alter_index_no_depends.sql indicates the test should remove extension dependency, but the file actually contains ALTER INDEX ... DEPENDS ON EXTENSION (lines 14-15), which adds a dependency instead.

This represents a mismatch. Either:

  • The filename should change to reflect that it adds a dependency (e.g., alter_index_with_depends.sql or alter_index_add_depends.sql)
  • Or the test content should be updated to use NO DEPENDS ON EXTENSION to match the "no_depends" intent
🤖 Prompt for AI Agents
In
web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/tests/15_plus/alter_index_no_depends.sql
around lines 1-18, the test filename implies removing an extension dependency
("no_depends") but the SQL uses "ALTER INDEX ... DEPENDS ON EXTENSION" which
adds a dependency; fix by making content and filename consistent: either change
the ALTER statement to "ALTER INDEX ... NO DEPENDS ON EXTENSION plpgsql" to
match the current filename, or rename the file to something like
alter_index_with_depends.sql (or alter_index_add_depends.sql) if you intend to
test adding a dependency; update any test metadata or references accordingly.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@ CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"

ALTER TABLE IF EXISTS public.test_table_for_indexes
CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#";

COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
@@ -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';
Loading
Loading