Added support to create an unnamed index. #3318

pull/6161/head
Akshay Joshi 2023-04-20 12:35:10 +05:30
parent ed941b5b95
commit d6ecc531e0
15 changed files with 137 additions and 67 deletions

View File

@ -2,7 +2,7 @@
Version 7.1
***********
Release date: 2023-05-01
Release date: 2023-05-04
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.0.
@ -22,6 +22,7 @@ New features
| `Issue #3275 <https://github.com/pgadmin-org/pgadmin4/issues/3275>`_ - Allow on demand record count setting to be changed per user using preferences.
| `Issue #3316 <https://github.com/pgadmin-org/pgadmin4/issues/3316>`_ - Added support to show statistics for materialized views.
| `Issue #3318 <https://github.com/pgadmin-org/pgadmin4/issues/3318>`_ - Added support to create an unnamed index.
Housekeeping
************
@ -33,5 +34,8 @@ Bug fixes
| `Issue #5777 <https://github.com/pgadmin-org/pgadmin4/issues/5777>`_ - Fixed an issue where the browser tree state is not remembered when reopening pgAdmin.
| `Issue #5820 <https://github.com/pgadmin-org/pgadmin4/issues/5820>`_ - Fixed an issue where collation was set to none if we remove it while creating partitioned table.
| `Issue #6075 <https://github.com/pgadmin-org/pgadmin4/issues/6075>`_ - Ensure that the save button is enabled when registering a new server fails due to an API error.
| `Issue #6120 <https://github.com/pgadmin-org/pgadmin4/issues/6120>`_ - Fixed error occurring while logging out from pgAdmin keeping a query tool opened.
| `Issue #6128 <https://github.com/pgadmin-org/pgadmin4/issues/6128>`_ - Fix a SQL error occurring on roles dependents SQL.
| `Issue #6130 <https://github.com/pgadmin-org/pgadmin4/issues/6130>`_ - Ensure to quote the primary key value if needed while deleting rows from the table.
| `Issue #6137 <https://github.com/pgadmin-org/pgadmin4/issues/6137>`_ - Fixed error occurring while dumping the servers from CLI.
| `Issue #6138 <https://github.com/pgadmin-org/pgadmin4/issues/6138>`_ - Throw an appropriate error when a table for which View/Edit data is open, is deleted, and query is executed.

View File

@ -551,10 +551,17 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
return True, err_msg
return False, ''
def end_transaction(self, data):
"""
This function is used to end the transaction
"""
if hasattr(data, "isconcurrent") and not data['isconcurrent']:
self.conn.execute_scalar("END;")
@check_precondition
def create(self, gid, sid, did, scid, tid):
"""
This function will creates new the schema object
This function will create the new index object
Args:
gid: Server Group ID
@ -579,7 +586,6 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
data[k] = v
required_args = {
'name': 'Name',
'columns': 'Columns'
}
@ -611,8 +617,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
status, res = self.conn.execute_scalar(SQL)
if not status:
# End transaction.
if hasattr(data, "isconcurrent") and not data['isconcurrent']:
self.conn.execute_scalar("END;")
self.end_transaction(data)
return internal_server_error(errormsg=res)
# If user chooses concurrent index then we cannot run it along
@ -625,27 +630,35 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
if SQL != '':
status, res = self.conn.execute_scalar(SQL)
if not status:
if hasattr(data, "isconcurrent") and not data[
'isconcurrent']:
# End transaction.
self.conn.execute_scalar("END;")
self.end_transaction(data)
return internal_server_error(errormsg=res)
# we need oid to add object in tree at browser
SQL = render_template(
"/".join([self.template_path, self._OID_SQL]),
tid=tid, data=data, conn=self.conn
)
status, idx = self.conn.execute_scalar(SQL)
if not status:
if hasattr(data, "isconcurrent") and not data['isconcurrent']:
# End transaction.
self.conn.execute_scalar("END;")
return internal_server_error(errormsg=tid)
idx = 0
if data.get('name', '') == "":
SQL = render_template(
"/".join([self.template_path, 'get_oid_name.sql']),
tid=tid, conn=self.conn
)
status, res = self.conn.execute_dict(SQL)
if not status:
self.end_transaction(data)
return internal_server_error(errormsg=tid)
if hasattr(data, "isconcurrent") and not data['isconcurrent']:
# End transaction.
self.conn.execute_scalar("END;")
if 'rows' in res and len(res['rows']) > 0:
data['name'] = res['rows'][0]['relname']
idx = res['rows'][0]['oid']
else:
SQL = render_template(
"/".join([self.template_path, self._OID_SQL]),
tid=tid, data=data, conn=self.conn
)
status, idx = self.conn.execute_scalar(SQL)
if not status:
self.end_transaction(data)
return internal_server_error(errormsg=tid)
self.end_transaction(data)
return jsonify(
node=self.blueprint.generate_browser_node(
idx,
@ -655,9 +668,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
)
)
except Exception as e:
if hasattr(data, "isconcurrent") and not data['isconcurrent']:
# End transaction.
self.conn.execute_scalar("END;")
self.end_transaction(data)
return internal_server_error(errormsg=str(e))
@check_precondition

View File

@ -263,7 +263,7 @@ export default class IndexSchema extends BaseUISchema {
return [
{
id: 'name', label: gettext('Name'), cell: 'string',
type: 'text', noEmpty: true,
type: 'text',
disabled: () => inSchema(indexSchemaObj.node_info),
},{
id: 'oid', label: gettext('OID'), cell: 'string',
@ -366,8 +366,15 @@ export default class IndexSchema extends BaseUISchema {
group: gettext('Definition'),
},{
id: 'indisclustered', label: gettext('Clustered?'), cell: 'string',
type: 'switch', disabled: () => inSchema(indexSchemaObj.node_info),
group: gettext('Definition'),
type: 'switch', group: gettext('Definition'), deps: ['name'],
disabled: function (state) {
return isEmptyString(state.name) || inSchema(indexSchemaObj.node_info);
},
depChange: (state)=>{
if(isEmptyString(state.name)) {
return {indisclustered: false};
}
}
},{
id: 'indisvalid', label: gettext('Valid?'), cell: 'string',
type: 'switch', mode: ['properties'],
@ -429,7 +436,15 @@ export default class IndexSchema extends BaseUISchema {
},{
id: 'description', label: gettext('Comment'), cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
disabled: () => inSchema(indexSchemaObj.node_info),
deps: ['name'],
disabled: function (state) {
return isEmptyString(state.name) || inSchema(indexSchemaObj.node_info);
},
depChange: (state)=>{
if(isEmptyString(state.name)) {
return {comment: ''};
}
}
},
];
}

View File

@ -0,0 +1,4 @@
CREATE INDEX
ON public.test_table_for_indexes USING hash
(id)
TABLESPACE pg_default;

View File

@ -258,6 +258,33 @@
"data": {
"name": "test_table_for_indexes"
}
},
{
"type": "create",
"name": "Create unnamed hash index",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"spcname": "pg_default",
"amname": "hash",
"columns": [{
"colname": "id",
"collspcname": "",
"op_class": "",
"sort_order": false,
"nulls": false,
"is_sort_nulls_applicable": false
}],
"indisunique": false,
"isconcurrent": false
},
"expected_msql_file": "create_unnamed_hash_index_msql.sql"
},
{
"type": "delete",
"name": "Drop hash index",
"endpoint": "NODE-index.delete_id"
}
]
}

View File

@ -1,5 +1,28 @@
{
"index_create": [
{
"name": "Create unnamed index: With valid data.",
"is_positive_test": true,
"inventory_data": {},
"test_data": {
"spcname": "pg_default",
"amname": "btree",
"columns": [
{
"colname": "id",
"sort_order": false,
"nulls": false
}
]
},
"mocking_required": false,
"mock_data": {},
"expected_data": {
"status_code": 200,
"error_msg": null,
"test_result_data": {}
}
},
{
"name": "Create index: With valid data.",
"is_positive_test": true,
@ -108,32 +131,6 @@
"test_result_data": {}
}
},
{
"name": "Create index: With invalid data - Missing Parameter.",
"is_positive_test": false,
"inventory_data": {},
"test_data": {
"spcname": "pg_default",
"amname": "btree",
"columns": [
{
"colname": "id",
"sort_order": false,
"nulls": false
}
],
"include": [
"name"
]
},
"mocking_required": false,
"mock_data": {},
"expected_data": {
"status_code": 410,
"error_msg": "Could not find the required parameter (Name).",
"test_result_data": {}
}
},
{
"name": "Create index: With valid data while server is down.",
"is_positive_test": false,

View File

@ -61,11 +61,13 @@ class IndexesAddTestCase(BaseTestGenerator):
if self.is_positive_test:
response = indexes_utils.api_create_index(self)
indexes_utils.assert_status_code(self, response)
index_response = indexes_utils.verify_index(self.server,
self.db_name,
self.index_name)
self.assertIsNot(index_response, "Could not find the newly "
"created index.")
# In case of unnamed index the below logic is not required
if hasattr(self, 'index_name'):
index_response = indexes_utils.verify_index(self.server,
self.db_name,
self.index_name)
self.assertIsNot(index_response, "Could not find the newly "
"created index.")
else:
if self.mocking_required:

View File

@ -184,7 +184,6 @@ def _get_create_sql(data, template_path, conn, mode, name,
:return:
"""
required_args = {
'name': 'Name',
'columns': 'Columns'
}
for arg in required_args:

View File

@ -3,4 +3,5 @@ SELECT ct.oid,
NOT convalidated as convalidated
FROM pg_catalog.pg_constraint ct
WHERE contype='c' AND
conrelid = {{tid}}::oid LIMIT 1;
conrelid = {{tid}}::oid
ORDER BY ct.oid DESC LIMIT 1;

View File

@ -3,4 +3,5 @@ SELECT ct.conindid AS oid,
NOT convalidated AS convalidated
FROM pg_catalog.pg_constraint ct
WHERE contype='x' AND
conrelid = {{tid}}::oid LIMIT 1;
conrelid = {{tid}}::oid
ORDER BY oid DESC LIMIT 1;

View File

@ -3,4 +3,5 @@ SELECT ct.oid,
NOT convalidated as convalidated
FROM pg_catalog.pg_constraint ct
WHERE contype='f' AND
conrelid = {{tid}}::oid LIMIT 1;
conrelid = {{tid}}::oid
ORDER BY ct.oid DESC LIMIT 1;

View File

@ -2,4 +2,5 @@ SELECT ct.conindid as oid,
ct.conname as name
FROM pg_catalog.pg_constraint ct
WHERE contype='{{constraint_type}}' AND
conrelid = {{tid}}::oid LIMIT 1;
conrelid = {{tid}}::oid
ORDER BY oid DESC LIMIT 1;

View File

@ -1,4 +1,5 @@
CREATE {% if data.indisunique %}UNIQUE {% endif %}INDEX{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {% if data.isconcurrent %}CONCURRENTLY {% endif %}{{conn|qtIdent(data.name)}}
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' %}

View File

@ -1,4 +1,5 @@
CREATE {% if data.indisunique %}UNIQUE {% endif %}INDEX{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {% if data.isconcurrent %}CONCURRENTLY {% endif %}{{conn|qtIdent(data.name)}}
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' %}

View File

@ -0,0 +1,5 @@
SELECT cls.relname, cls.oid
FROM pg_catalog.pg_index idx
JOIN pg_catalog.pg_class cls ON cls.oid=indexrelid
WHERE indrelid = {{tid}}::OID
ORDER BY cls.oid DESC LIMIT 1;