1) Added support for SYSTEM, CONCURRENTLY and TABLESPACE options in REINDEX. #6381
2) Added new/missing options to the VACUUM command. #6397 3) Added SKIP_LOCKED and BUFFER_USAGE_LIMIT option to Analyze command. #6415pull/6596/head
parent
e177344ae1
commit
a460644ae8
Binary file not shown.
Before Width: | Height: | Size: 52 KiB |
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
Binary file not shown.
After Width: | Height: | Size: 178 KiB |
|
@ -7,36 +7,109 @@
|
|||
Use the *Maintenance* dialog to VACUUM, ANALYZE, REINDEX or CLUSTER a database
|
||||
or selected database objects.
|
||||
|
||||
.. image:: images/maintenance.png
|
||||
:alt: Maintenance dialog
|
||||
:align: center
|
||||
|
||||
While this utility is useful for ad-hoc maintenance purposes, you are encouraged
|
||||
to perform automatic VACUUM jobs on a regular schedule.
|
||||
|
||||
Select a button next to *Maintenance operation* to specify the type of
|
||||
maintenance:
|
||||
|
||||
.. image:: images/maintenance_vacuum.png
|
||||
:alt: Maintenance dialog
|
||||
:align: center
|
||||
|
||||
* Click *VACUUM* to scan the selected database or table to reclaim storage used
|
||||
by dead tuples.
|
||||
|
||||
* Move the *FULL* switch to the *Yes* position to compact tables by writing
|
||||
a completely new version of the table file without dead space. The default
|
||||
is *No*.
|
||||
a completely new version of the table file without dead space.
|
||||
|
||||
* Move the *FREEZE* switch to the *Yes* position to freeze data in a table
|
||||
when it will have no further updates. The default is *No*.
|
||||
when it will have no further updates.
|
||||
|
||||
* Move the *ANALYZE* switch to the *Yes* position to issue ANALYZE commands
|
||||
whenever the content of a table has changed sufficiently. The default is
|
||||
*No*.
|
||||
whenever the content of a table has changed sufficiently.
|
||||
|
||||
* Move the *DISABLE PAGE SKIPPING* switch to the *Yes* position to disables
|
||||
all page-skipping behavior.
|
||||
|
||||
* Move the *SKIP LOCKED* switch to the *Yes* position to specifies that
|
||||
VACUUM should not wait for any conflicting locks to be released when
|
||||
beginning work on a relation. This option is available from v12 onwards.
|
||||
|
||||
* Move the *TRUNCATE* switch to the *Yes* position to specifies that VACUUM
|
||||
should attempt to truncate off any empty pages at the end of the table and
|
||||
allow the disk space for the truncated pages to be returned to the operating
|
||||
system. This option is available from v12 onwards.
|
||||
|
||||
* Move the *PROCESS TOAST* switch to the *Yes* position to specifies that
|
||||
VACUUM should attempt to process the corresponding TOAST table for each
|
||||
relation, if one exists. This option is available from v14 onwards.
|
||||
|
||||
* Move the *PROCESS MAIN* switch to the *Yes* position to specifies that
|
||||
VACUUM should attempt to process the main relation. This option is available
|
||||
from v16 onwards.
|
||||
|
||||
* Move the *SKIP DATABASE STATS* switch to the *Yes* position to specifies
|
||||
that VACUUM should skip updating the database-wide statistics about oldest
|
||||
unfrozen XIDs. This option is available from v16 onwards.
|
||||
|
||||
* Move the *ONLY DATABASE STATS* switch to the *Yes* position to specifies
|
||||
that VACUUM should do nothing except update the database-wide statistics
|
||||
about oldest unfrozen XIDs . This option is available from v16 onwards.
|
||||
|
||||
* Use the *INDEX CLEANUP* field to force VACUUM to process indexes when there
|
||||
are more than zero dead tuples.
|
||||
|
||||
* Use the *PARALLEL* field to specify index vacuum and index cleanup phases
|
||||
of VACUUM in parallel using integer background workers. This option is
|
||||
available from v13 onwards.
|
||||
|
||||
* Use the *BUFFER USAGE LIMIT* field to specifies the Buffer Access Strategy
|
||||
ring buffer size for VACUUM. This size is used to calculate the number of
|
||||
shared buffers which will be reused as part of this strategy. This option
|
||||
is available from v16 onwards
|
||||
|
||||
|
||||
.. image:: images/maintenance_analyze.png
|
||||
:alt: Maintenance dialog
|
||||
:align: center
|
||||
|
||||
* Click *ANALYZE* to update the stored statistics used by the query planner.
|
||||
This enables the query optimizer to select the fastest query plan for optimal
|
||||
performance.
|
||||
|
||||
* Move the *SKIP LOCKED* switch to the *Yes* position to specifies that
|
||||
ANALYZE should not wait for any conflicting locks to be released when
|
||||
beginning work on a relation. This option is available from v12 onwards.
|
||||
|
||||
* Use the *BUFFER USAGE LIMIT* field to specifies the Buffer Access Strategy
|
||||
ring buffer size for ANALYZE. This size is used to calculate the number of
|
||||
shared buffers which will be reused as part of this strategy. This option
|
||||
is available from v16 onwards
|
||||
|
||||
.. image:: images/maintenance_reindex.png
|
||||
:alt: Maintenance dialog
|
||||
:align: center
|
||||
|
||||
* Click *REINDEX* to rebuild any index in case it has degenerated due to the
|
||||
insertion of unusual data patterns. This happens, for example, if you insert
|
||||
rows with increasing index values, and delete low index values.
|
||||
|
||||
* Move the *SYSTEM* switch to the *Yes* position to recreate all indexes
|
||||
on system catalogs within the current database. This option is enabled
|
||||
only when database object is selected.
|
||||
|
||||
* Move the *CONCURRENTLY* switch to the *Yes* position to rebuild the index
|
||||
without taking any locks that prevent concurrent inserts, updates, or
|
||||
deletes on the table. This option is available from v12 onwards.
|
||||
|
||||
* Use the *TABLESPACE* field to specifies that indexes will be rebuilt on
|
||||
a new tablespace. This option is available from v14 onwards.
|
||||
|
||||
.. image:: images/maintenance_cluster.png
|
||||
:alt: Maintenance dialog
|
||||
:align: center
|
||||
|
||||
* Click *CLUSTER* to instruct PostgreSQL to cluster the selected table.
|
||||
|
||||
To exclude status messages from the process output, move the *Verbose Messages*
|
||||
|
@ -47,4 +120,4 @@ to exit the dialog without performing maintenance operations, click *Cancel*.
|
|||
|
||||
pgAdmin will run the maintenance process in background. You can view all the background
|
||||
process with there running status and logs on the :ref:`Processes <processes>`
|
||||
tab
|
||||
tab.
|
||||
|
|
|
@ -11,6 +11,7 @@ notes for it.
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release_notes_7_6
|
||||
release_notes_7_5
|
||||
release_notes_7_4
|
||||
release_notes_7_3
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
***********
|
||||
Version 7.6
|
||||
***********
|
||||
|
||||
Release date: 2023-08-24
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.5.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 11, 12, 13, 14 and 15
|
||||
|
||||
**EDB Advanced Server**: 11, 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 15.3
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #6381 <https://github.com/pgadmin-org/pgadmin4/issues/6381>`_ - Added support for SYSTEM, CONCURRENTLY and TABLESPACE options in REINDEX.
|
||||
| `Issue #6397 <https://github.com/pgadmin-org/pgadmin4/issues/6397>`_ - Added new/missing options to the VACUUM command.
|
||||
| `Issue #6415 <https://github.com/pgadmin-org/pgadmin4/issues/6415>`_ - Added SKIP_LOCKED and BUFFER_USAGE_LIMIT option to Analyze command.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
|
||||
Bug fixes
|
||||
*********
|
|
@ -470,19 +470,19 @@ STORAGE_DIR = os.path.join(DATA_DIR, 'storage')
|
|||
##########################################################################
|
||||
DEFAULT_BINARY_PATHS = {
|
||||
"pg": "",
|
||||
"pg-10": "",
|
||||
"pg-11": "",
|
||||
"pg-12": "",
|
||||
"pg-13": "",
|
||||
"pg-14": "",
|
||||
"pg-15": "",
|
||||
"pg-16": "",
|
||||
"ppas": "",
|
||||
"ppas-10": "",
|
||||
"ppas-11": "",
|
||||
"ppas-12": "",
|
||||
"ppas-13": "",
|
||||
"ppas-14": "",
|
||||
"ppas-15": ""
|
||||
"ppas-15": "",
|
||||
"ppas-16": ""
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
|
|
|
@ -75,59 +75,50 @@ class Message(IProcessDesc):
|
|||
|
||||
return "{0} ({1}:{2})".format(s.name, host, port)
|
||||
|
||||
def get_op(self):
|
||||
op = self._check_for_vacuum()
|
||||
|
||||
if self.data['op'] == "ANALYZE":
|
||||
op = _('ANALYZE')
|
||||
if self.data['verbose']:
|
||||
op += '(' + _('VERBOSE') + ')'
|
||||
|
||||
if self.data['op'] == "REINDEX":
|
||||
if 'schema' in self.data and self.data['schema']:
|
||||
if 'primary_key' in self.data or \
|
||||
'unique_constraint' in self.data or \
|
||||
'index' in self.data:
|
||||
return _('REINDEX INDEX')
|
||||
else:
|
||||
return _('REINDEX TABLE')
|
||||
op = _('REINDEX')
|
||||
|
||||
if self.data['op'] == "CLUSTER":
|
||||
op = _('CLUSTER')
|
||||
|
||||
return op
|
||||
def get_object_msg(self):
|
||||
msg = _("on database '{0}'").format(self.data['database'])
|
||||
if 'primary_key' in self.data or 'unique_constraint' in self.data:
|
||||
msg = _("on constraint '{0}/{1}/{2}/{3}'").format(
|
||||
self.data['database'], self.data['schema'], self.data['table'],
|
||||
self.data['primary_key'] if 'primary_key' in self.data else
|
||||
self.data['unique_constraint'])
|
||||
elif 'index' in self.data:
|
||||
msg = _("on index '{0}/{1}/{2}/{3}'").format(
|
||||
self.data['database'], self.data['schema'],
|
||||
self.data['table'], self.data['index'])
|
||||
elif 'table' in self.data:
|
||||
msg = _("on table '{0}/{1}/{2}'").format(
|
||||
self.data['database'], self.data['schema'], self.data['table'])
|
||||
elif 'schema' in self.data:
|
||||
msg = _("on schema '{0}/{1}'").format(self.data['database'],
|
||||
self.data['schema'])
|
||||
return msg
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
res = _("{0} on database '{1}' of server {2}")
|
||||
return res.format(
|
||||
self.get_op(), self.data['database'], self.get_server_name())
|
||||
op = _('VACUUM')
|
||||
if self.data['op'] == "ANALYZE":
|
||||
op = _('ANALYZE')
|
||||
elif self.data['op'] == "REINDEX" and 'schema' not in self.data:
|
||||
op = _('REINDEX')
|
||||
elif self.data['op'] == "REINDEX" and 'schema' in self.data:
|
||||
if 'primary_key' in self.data or 'unique_constraint' in self.data\
|
||||
or 'index' in self.data:
|
||||
op = _('REINDEX INDEX')
|
||||
elif 'table' in self.data:
|
||||
op = _('REINDEX TABLE')
|
||||
else:
|
||||
op = _('REINDEX SCHEMA')
|
||||
elif self.data['op'] == "CLUSTER":
|
||||
op = _('CLUSTER')
|
||||
|
||||
res = _("{0} {1} of server {2}")
|
||||
return res.format(op, self.get_object_msg(), self.get_server_name())
|
||||
|
||||
@property
|
||||
def type_desc(self):
|
||||
return _("Maintenance")
|
||||
|
||||
def _check_for_vacuum(self):
|
||||
"""
|
||||
Check for VACUUM in data and return format response.
|
||||
:return: response.
|
||||
"""
|
||||
res = None
|
||||
if self.data['op'] == "VACUUM":
|
||||
res = _('VACUUM ({0})')
|
||||
|
||||
opts = []
|
||||
if 'vacuum_full' in self.data and self.data['vacuum_full']:
|
||||
opts.append(_('FULL'))
|
||||
if 'vacuum_freeze' in self.data and self.data['vacuum_freeze']:
|
||||
opts.append(_('FREEZE'))
|
||||
if self.data['verbose']:
|
||||
opts.append(_('VERBOSE'))
|
||||
|
||||
res = res.format(', '.join(str(x) for x in opts))
|
||||
return res
|
||||
|
||||
def details(self, cmd, args):
|
||||
return {
|
||||
"message": self.message,
|
||||
|
|
|
@ -11,6 +11,7 @@ import Notify from '../../../../static/js/helpers/Notifier';
|
|||
import {getUtilityView} from '../../../../browser/static/js/utility_view';
|
||||
import getApiInstance from 'sources/api_instance';
|
||||
import MaintenanceSchema, {getVacuumSchema} from './maintenance.ui';
|
||||
import { getNodeListByName } from '../../../../browser/static/js/node_ajax';
|
||||
|
||||
define([
|
||||
'sources/gettext', 'sources/url_for', 'sources/pgadmin', 'pgadmin.browser',
|
||||
|
@ -76,9 +77,15 @@ define([
|
|||
},
|
||||
getUISchema: function(treeItem) {
|
||||
let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(treeItem);
|
||||
const selectedNode = pgBrowser.tree.selected();
|
||||
let itemNodeData = pgBrowser.tree.findNodeByDomElement(selectedNode).getData();
|
||||
|
||||
return new MaintenanceSchema(
|
||||
()=>getVacuumSchema(),
|
||||
()=>getVacuumSchema({
|
||||
tablespace: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{
|
||||
return (m.label != 'pg_global');
|
||||
})
|
||||
}),
|
||||
{
|
||||
nodeInfo: treeNodeInfo
|
||||
}
|
||||
|
@ -106,6 +113,15 @@ define([
|
|||
if(treeInfo?.mview) {
|
||||
extraData['table'] = treeInfo?.mview._label;
|
||||
}
|
||||
if(treeInfo?.primary_key) {
|
||||
extraData['primary_key'] = treeInfo?.primary_key._label;
|
||||
}
|
||||
if(treeInfo?.unique_constraint) {
|
||||
extraData['unique_constraint'] = treeInfo?.unique_constraint._label;
|
||||
}
|
||||
if(treeInfo?.index) {
|
||||
extraData['index'] = treeInfo?.index._label;
|
||||
}
|
||||
extraData['save_btn_icon'] = 'done';
|
||||
return extraData;
|
||||
},
|
||||
|
@ -174,7 +190,7 @@ define([
|
|||
} else{
|
||||
|
||||
pgBrowser.Node.registerUtilityPanel();
|
||||
let panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md),
|
||||
let panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md, pgBrowser.stdH.lg),
|
||||
j = panel.$container.find('.obj_properties').first();
|
||||
|
||||
let schema = that.getUISchema(item);
|
||||
|
@ -194,7 +210,7 @@ define([
|
|||
});
|
||||
|
||||
getUtilityView(
|
||||
schema, treeInfo, 'select', 'dialog', j[0], panel, that.saveCallBack, extraData, 'OK', jobUrl, sqlHelpUrl, helpUrl);
|
||||
schema, treeInfo, 'create', 'dialog', j[0], panel, that.saveCallBack, extraData, 'OK', jobUrl, sqlHelpUrl, helpUrl);
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
|
|
|
@ -23,44 +23,296 @@ export class VacuumSchema extends BaseUISchema {
|
|||
return 'op';
|
||||
}
|
||||
|
||||
isDisabled(state) {
|
||||
if(state?.op) {
|
||||
return (state.op != 'VACUUM');
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
isApplicableForVacuum(state) {
|
||||
return state?.op ? state.op == 'VACUUM' : false;
|
||||
}
|
||||
isApplicableForReindex(state) {
|
||||
return state?.op ? state.op == 'REINDEX' : false;
|
||||
}
|
||||
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [{
|
||||
id: 'vacuum_full',
|
||||
group: gettext('Vacuum'),
|
||||
disabled: function(state) {
|
||||
return obj.isDisabled(state);
|
||||
},
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('FULL'),
|
||||
deps: ['op'],
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_full = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, {
|
||||
id: 'vacuum_freeze',
|
||||
deps: ['op'],
|
||||
disabled: function(state) {
|
||||
return obj.isDisabled(state);
|
||||
},
|
||||
type: 'switch',
|
||||
label: gettext('FREEZE'),
|
||||
group: gettext('Vacuum'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_freeze = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, {
|
||||
id: 'vacuum_analyze',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
disabled: function(state) {
|
||||
return obj.isDisabled(state);
|
||||
},
|
||||
label: gettext('ANALYZE'),
|
||||
group: gettext('Vacuum'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_analyze = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, {
|
||||
id: 'vacuum_disable_page_skipping',
|
||||
deps: ['op', 'vacuum_full'],
|
||||
type: 'switch',
|
||||
label: gettext('DISABLE PAGE SKIPPING'),
|
||||
inlineNext: true,
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state) || state.vacuum_full) {
|
||||
state.vacuum_disable_page_skipping = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
}
|
||||
}, {
|
||||
id: 'skip_locked',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('SKIP LOCKED'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return state?.op ? (state.op == 'VACUUM' || state.op == 'ANALYZE') : false;
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (state?.op && state.op != 'VACUUM' && state.op != 'ANALYZE') {
|
||||
state.skip_locked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 120000,
|
||||
}, {
|
||||
id: 'vacuum_truncate',
|
||||
deps: ['op', 'vacuum_full'],
|
||||
type: 'switch',
|
||||
label: gettext('TRUNCATE'),
|
||||
inlineNext: true,
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state) || state.vacuum_full) {
|
||||
state.vacuum_truncate = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
min_version: 120000,
|
||||
}, {
|
||||
id: 'vacuum_process_toast',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('PROCESS TOAST'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_process_toast = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 140000,
|
||||
}, {
|
||||
id: 'vacuum_process_main',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('PROCESS MAIN'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_process_main = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 160000,
|
||||
}, {
|
||||
id: 'vacuum_skip_database_stats',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('SKIP DATABASE STATS'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_skip_database_stats = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 160000,
|
||||
}, {
|
||||
id: 'vacuum_only_database_stats',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('ONLY DATABASE STATS'),
|
||||
inlineNext: true,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state)) {
|
||||
state.vacuum_only_database_stats = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 160000,
|
||||
}, {
|
||||
id: 'vacuum_index_cleanup',
|
||||
deps: ['op', 'vacuum_full'],
|
||||
type: 'select',
|
||||
label: gettext('INDEX CLEANUP'),
|
||||
controlProps: { allowClear: false, width: '100%' },
|
||||
options: [
|
||||
{
|
||||
label: gettext('AUTO'),
|
||||
value: 'AUTO',
|
||||
},
|
||||
{
|
||||
label: gettext('ON'),
|
||||
value: 'ON',
|
||||
},
|
||||
{
|
||||
label: gettext('OFF'),
|
||||
value: 'OFF',
|
||||
}
|
||||
],
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state) || state.vacuum_full) {
|
||||
state.vacuum_index_cleanup = undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
min_version: 120000,
|
||||
}, {
|
||||
id: 'vacuum_parallel',
|
||||
deps: ['op', 'vacuum_full'],
|
||||
type: 'int',
|
||||
label: gettext('PARALLEL'),
|
||||
min:0, max:1024,
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForVacuum(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForVacuum(state) || state.vacuum_full) {
|
||||
state.vacuum_parallel = undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 130000,
|
||||
}, {
|
||||
id: 'buffer_usage_limit',
|
||||
deps: ['op', 'vacuum_full', 'vacuum_analyze'],
|
||||
type: 'text',
|
||||
label: gettext('BUFFER USAGE LIMIT'),
|
||||
visible: function(state) {
|
||||
return state?.op ? (state.op == 'VACUUM' || state.op == 'ANALYZE') : false;
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (state?.op && ((state.op != 'VACUUM' && state.op != 'ANALYZE') || (state.op == 'VACUUM' && state.vacuum_full && !state.vacuum_analyze))) {
|
||||
state.buffer_usage_limit = '';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
helpMessage: gettext('Sizes should be specified as a string containing the numerical size followed by any one of the following memory units: kB (kilobytes), MB (megabytes), GB (gigabytes), or TB (terabytes)'),
|
||||
min_version: 160000,
|
||||
}, {
|
||||
id: 'reindex_system',
|
||||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('SYSTEM'),
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForReindex(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForReindex(state) || obj?._top?.nodeInfo?.schema) {
|
||||
state.reindex_system = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
helpMessage: gettext('This option is enabled only when the database is selected in the object explorer.'),
|
||||
}, {
|
||||
id: 'reindex_concurrently',
|
||||
deps: ['op', 'reindex_system'],
|
||||
type: 'switch',
|
||||
label: gettext('CONCURRENTLY'),
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForReindex(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForReindex(state) || state.reindex_system) {
|
||||
state.reindex_concurrently = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 120000,
|
||||
}, {
|
||||
id: 'reindex_tablespace',
|
||||
label: gettext('TABLESPACE'),
|
||||
deps: ['op', 'reindex_system'],
|
||||
type: 'select',
|
||||
options: this.fieldOptions.tablespace,
|
||||
controlProps: { allowClear: true },
|
||||
visible: function(state) {
|
||||
return obj.isApplicableForReindex(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!obj.isApplicableForReindex(state) || state.reindex_system) {
|
||||
state.reindex_tablespace = undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
min_version: 140000,
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +327,11 @@ export default class MaintenanceSchema extends BaseUISchema {
|
|||
|
||||
constructor(vacuumSchema, fieldOptions = {}) {
|
||||
super({
|
||||
op: 'VACUUM',
|
||||
verbose: true,
|
||||
vacuum_full: false,
|
||||
vacuum_freeze: false,
|
||||
vacuum_analyze: false,
|
||||
op: (fieldOptions.nodeInfo?.schema && !fieldOptions.nodeInfo?.table &&
|
||||
!fieldOptions.nodeInfo?.primary_key && !fieldOptions.nodeInfo?.unique_constraint &&
|
||||
!fieldOptions.nodeInfo?.index && !fieldOptions.nodeInfo?.partition &&
|
||||
!fieldOptions.nodeInfo?.mview) ? 'REINDEX' : 'VACUUM',
|
||||
verbose: true
|
||||
});
|
||||
|
||||
this.fieldOptions = {
|
||||
|
@ -95,6 +347,12 @@ export default class MaintenanceSchema extends BaseUISchema {
|
|||
return 'id';
|
||||
}
|
||||
|
||||
isSchemaNode() {
|
||||
return this.nodeInfo?.schema && !this.nodeInfo?.table &&
|
||||
!this.nodeInfo?.primary_key && !this.nodeInfo?.unique_constraint &&
|
||||
!this.nodeInfo?.index && !this.nodeInfo?.partition;
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [
|
||||
|
@ -107,20 +365,22 @@ export default class MaintenanceSchema extends BaseUISchema {
|
|||
{
|
||||
'label': gettext('VACUUM'),
|
||||
value: 'VACUUM',
|
||||
disabled: (obj.isSchemaNode() && !obj.nodeInfo?.mview) ? true : false
|
||||
},
|
||||
{
|
||||
'label': gettext('ANALYZE'),
|
||||
value: 'ANALYZE',
|
||||
disabled: (obj.isSchemaNode() && !obj.nodeInfo?.mview) ? true : false
|
||||
},
|
||||
{
|
||||
'label': gettext('REINDEX'),
|
||||
value: 'REINDEX',
|
||||
disabled: obj.nodeInfo?.mview?true:false
|
||||
disabled: obj.nodeInfo?.mview ? true : false
|
||||
},
|
||||
{
|
||||
'label': gettext('CLUSTER'),
|
||||
value: 'CLUSTER',
|
||||
disabled: obj.nodeInfo?.mview?true:false
|
||||
disabled: obj.nodeInfo?.mview ? true : obj.isSchemaNode() ? true : false
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -129,6 +389,14 @@ export default class MaintenanceSchema extends BaseUISchema {
|
|||
label: gettext('Type of objects'),
|
||||
schema: obj.getVacuumSchema(),
|
||||
group: gettext('Options'),
|
||||
visible: function(state) {
|
||||
if (state?.op == 'ANALYZE') {
|
||||
return obj?.nodeInfo?.server?.version >= 120000;
|
||||
} else if (state?.op == 'CLUSTER') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'verbose',
|
||||
|
@ -136,21 +404,6 @@ export default class MaintenanceSchema extends BaseUISchema {
|
|||
deps: ['op'],
|
||||
type: 'switch',
|
||||
label: gettext('Verbose Messages'),
|
||||
disabled: function(state) {
|
||||
let nodeInfo = this.nodeInfo;
|
||||
if(state?.verbose) {
|
||||
if ('primary_key' in nodeInfo || 'unique_constraint' in nodeInfo ||
|
||||
'index' in nodeInfo) {
|
||||
if (state.op == 'REINDEX') {
|
||||
state.verbose = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return state.op == 'REINDEX';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
//////////////////////////////////////////////////////////////
|
||||
|
||||
export const maintenanceSupportedNodes = [
|
||||
'database', 'table', 'primary_key',
|
||||
'unique_constraint', 'index', 'partition',
|
||||
'database', 'schema', 'table', 'primary_key',
|
||||
'unique_constraint', 'index', 'partition', 'mview'
|
||||
];
|
||||
|
|
|
@ -1,17 +1,34 @@
|
|||
{% set maintenance_options = [] %}
|
||||
{% if data.verbose %}{{ maintenance_options.append('VERBOSE') or "" }}{% endif %}
|
||||
{% if data.vacuum_full %}{{ maintenance_options.append('FULL') or "" }}{% endif %}
|
||||
{% if data.vacuum_freeze %}{{ maintenance_options.append('FREEZE') or "" }}{% endif %}
|
||||
{% if data.vacuum_analyze %}{{ maintenance_options.append('ANALYZE') or "" }}{% endif %}
|
||||
{% if data.vacuum_disable_page_skipping %}{{ maintenance_options.append('DISABLE_PAGE_SKIPPING') or "" }}{% endif %}
|
||||
{% if data.skip_locked %}{{ maintenance_options.append('SKIP_LOCKED') or "" }}{% endif %}
|
||||
{% if data.vacuum_truncate %}{{ maintenance_options.append('TRUNCATE') or "" }}{% endif %}
|
||||
{% if data.vacuum_process_toast %}{{ maintenance_options.append('PROCESS_TOAST') or "" }}{% endif %}
|
||||
{% if data.vacuum_process_main %}{{ maintenance_options.append('PROCESS_MAIN') or "" }}{% endif %}
|
||||
{% if data.vacuum_skip_database_stats %}{{ maintenance_options.append('SKIP_DATABASE_STATS') or "" }}{% endif %}
|
||||
{% if data.vacuum_only_database_stats %}{{ maintenance_options.append('ONLY_DATABASE_STATS') or "" }}{% endif %}
|
||||
{% if data.vacuum_index_cleanup %}{{ maintenance_options.append('INDEX_CLEANUP ' + data.vacuum_index_cleanup) or "" }}{% endif %}
|
||||
{% if data.vacuum_parallel %}{{ maintenance_options.append('PARALLEL ' + data.vacuum_parallel) or "" }}{% endif %}
|
||||
{% if data.buffer_usage_limit %}{{ maintenance_options.append('BUFFER_USAGE_LIMIT "' + data.buffer_usage_limit + '"') or "" }}{% endif %}
|
||||
{% if data.reindex_tablespace %}{{ maintenance_options.append('TABLESPACE "' + data.reindex_tablespace + '"') or "" }}{% endif %}
|
||||
{% if data.reindex_concurrently %}{{ maintenance_options.append('CONCURRENTLY') or "" }}{% endif %}
|
||||
{% if data.op == "VACUUM" %}
|
||||
VACUUM{% if data.vacuum_full %} FULL{% endif %}{% if data.vacuum_freeze %} FREEZE{% endif %}{% if data.verbose %} VERBOSE{% endif %}{% if data.vacuum_analyze %} ANALYZE{% endif %}{% if data.schema %} {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.table) }}{% endif %};
|
||||
VACUUM{% for option in maintenance_options %}{% if loop.first %} ({% endif %}{{ option }}{% if not loop.last %}, {% endif %}{% if loop.last %}){% endif %}{% endfor %}{% if data.schema %} {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.table) }}{% endif %};
|
||||
{% endif %}
|
||||
{% if data.op == "ANALYZE" %}
|
||||
ANALYZE{% if data.verbose %} VERBOSE{% endif %}{% if data.schema %} {{ conn|qtIdent(data.schema, data.table) }}{% endif %};
|
||||
ANALYZE{% for option in maintenance_options %}{% if loop.first %} ({% endif %}{{ option }}{% if not loop.last %}, {% endif %}{% if loop.last %}){% endif %}{% endfor %}{% if data.schema %} {{ conn|qtIdent(data.schema, data.table) }}{% endif %};
|
||||
{% endif %}
|
||||
{% if data.op == "REINDEX" %}
|
||||
{% if index_name %}
|
||||
REINDEX INDEX {{ conn|qtIdent(data.schema, index_name) }};
|
||||
REINDEX{% for option in maintenance_options %}{% if loop.first %} ({% endif %}{{ option }}{% if not loop.last %}, {% endif %}{% if loop.last %}){% endif %}{% endfor %} INDEX {{ conn|qtIdent(data.schema, index_name) }};
|
||||
{% else %}
|
||||
REINDEX{% if not data.schema %} DATABASE {{ conn|qtIdent(data.database) }}{% else %} TABLE {{ conn|qtIdent(data.schema, data.table) }}{% endif %};
|
||||
REINDEX{% for option in maintenance_options %}{% if loop.first %} ({% endif %}{{ option }}{% if not loop.last %}, {% endif %}{% if loop.last %}){% endif %}{% endfor %}{% if not data.schema and not data.reindex_system %} DATABASE {{ conn|qtIdent(data.database) }}{% elif not data.schema and data.reindex_system%} SYSTEM {{ conn|qtIdent(data.database) }}{% elif data.schema and not data.table and not data.primary_key and not data.unique_constraint and not data.index and not data.mview %} SCHEMA {{ conn|qtIdent(data.schema) }}{% else %} TABLE {{ conn|qtIdent(data.schema, data.table) }}{% endif %};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if data.op == "CLUSTER" %}
|
||||
CLUSTER{% if data.verbose %} VERBOSE {% endif %}{% if data.schema %} {{ conn|qtIdent(data.schema, data.table) }}{% endif %}{% if index_name %}
|
||||
CLUSTER{% if data.verbose %} VERBOSE{% endif %}{% if data.schema %} {{ conn|qtIdent(data.schema, data.table) }}{% endif %}{% if index_name %}
|
||||
USING {{ conn|qtIdent(index_name) }}{% endif %};
|
||||
{% endif %}
|
||||
|
|
|
@ -53,8 +53,8 @@ class BatchProcessTest(BaseTestGenerator):
|
|||
},
|
||||
cmd="VACUUM VERBOSE;\n"
|
||||
),
|
||||
expected_msg="VACUUM (VERBOSE) on database "
|
||||
"'postgres' of server " + SERVER_NAME,
|
||||
expected_msg="VACUUM on database 'postgres' of server " +
|
||||
SERVER_NAME,
|
||||
expected_details_cmd='VACUUM VERBOSE;'
|
||||
))
|
||||
]
|
||||
|
|
|
@ -34,7 +34,7 @@ class MaintenanceJobTest(BaseTestGenerator):
|
|||
cmd="VACUUM VERBOSE;\n"
|
||||
),
|
||||
url='/maintenance/job/{0}/{1}',
|
||||
expected_cmd='VACUUM VERBOSE',
|
||||
expected_cmd='VACUUM (VERBOSE)',
|
||||
expected_exit_code=[0, None]
|
||||
))
|
||||
]
|
||||
|
|
|
@ -19,6 +19,8 @@ from unittest.mock import patch, MagicMock
|
|||
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
|
||||
MAINTENANCE_URL = '/maintenance/job/{0}/{1}'
|
||||
|
||||
|
||||
class MaintenanceCreateJobTest(BaseTestGenerator):
|
||||
"""Test the BackupCreateJob class"""
|
||||
|
@ -40,10 +42,11 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
vacuum_full=False,
|
||||
verbose=True
|
||||
),
|
||||
url='/maintenance/job/{0}/{1}',
|
||||
expected_cmd_opts=['VACUUM VERBOSE;\n'],
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE);\n'],
|
||||
)),
|
||||
('When maintaining object with VACUUM FULL',
|
||||
('When maintaining object with VACUUM FULL, FREEZE, ANALYZE, '
|
||||
'DISABLE_PAGE_SKIPPING',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
|
@ -55,13 +58,130 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
vacuum_analyze=False,
|
||||
vacuum_freeze=False,
|
||||
vacuum_analyze=True,
|
||||
vacuum_freeze=True,
|
||||
vacuum_full=True,
|
||||
vacuum_disable_page_skipping=True,
|
||||
verbose=True
|
||||
),
|
||||
url='/maintenance/job/{0}/{1}',
|
||||
expected_cmd_opts=['VACUUM FULL VERBOSE;\n'],
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, FULL, FREEZE, ANALYZE, '
|
||||
'DISABLE_PAGE_SKIPPING);\n'],
|
||||
)),
|
||||
('When maintaining object with VACUUM SKIP LOCKED, TRUNCATE, '
|
||||
'INDEX CLEANUP',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
skip_locked=True,
|
||||
vacuum_truncate=True,
|
||||
vacuum_index_cleanup='OFF',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, SKIP_LOCKED, TRUNCATE, '
|
||||
'INDEX_CLEANUP OFF);\n'],
|
||||
server_min_version=120000,
|
||||
message='VACUUM SKIP_LOCKED, TRUNCATE and INDEX_CLEANUP is not '
|
||||
'supported by EPAS/PG server less than 12.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM PARALLEL',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
vacuum_parallel='15',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, PARALLEL 15);\n'],
|
||||
server_min_version=130000,
|
||||
message='VACUUM PARALLEL is not supported by EPAS/PG server '
|
||||
'less than 13.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM PROCESS TOAST',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
vacuum_process_toast=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, PROCESS_TOAST);\n'],
|
||||
server_min_version=140000,
|
||||
message='VACUUM PROCESS TOAST is not supported by EPAS/PG server '
|
||||
'less than 14.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM SKIP DATABASE STATS, '
|
||||
'PROCESS MAIN, BUFFER USAGE LIMIT',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
vacuum_process_main=True,
|
||||
vacuum_skip_database_stats=True,
|
||||
buffer_usage_limit='1MB',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, PROCESS_MAIN, '
|
||||
'SKIP_DATABASE_STATS, BUFFER_USAGE_LIMIT "1MB"'
|
||||
');\n'],
|
||||
server_min_version=160000,
|
||||
message='VACUUM SKIP_DATABASE_STATS, PROCESS_MAIN and '
|
||||
'BUFFER_USAGE_LIMIT is not supported by EPAS/PG server '
|
||||
'less than 16.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM ONLY DATABASE STATS',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
vacuum_only_database_stats=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, ONLY_DATABASE_STATS);\n'],
|
||||
server_min_version=160000,
|
||||
message='VACUUM ONLY DATABASE STATS is not supported by EPAS/PG '
|
||||
'server less than 16.0'
|
||||
)),
|
||||
('When maintaining object with ANALYZE',
|
||||
dict(
|
||||
|
@ -75,13 +195,314 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
params=dict(
|
||||
database='postgres',
|
||||
op='ANALYZE',
|
||||
vacuum_analyze=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['ANALYZE (VERBOSE);\n'],
|
||||
)),
|
||||
('When maintaining object with ANALYZE SKIP LOCKED',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='ANALYZE',
|
||||
skip_locked=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['ANALYZE (VERBOSE, SKIP_LOCKED);\n'],
|
||||
server_min_version=120000,
|
||||
message='ANALYZE SKIP_LOCKED is not supported by EPAS/PG server '
|
||||
'less than 12.0'
|
||||
)),
|
||||
('When maintaining object with ANALYZE BUFFER USAGE LIMIT',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='ANALYZE',
|
||||
buffer_usage_limit='1MB',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['ANALYZE (VERBOSE, BUFFER_USAGE_LIMIT "1MB"'
|
||||
');\n'],
|
||||
server_min_version=160000,
|
||||
message='ANALYZE BUFFER_USAGE_LIMIT is not supported by '
|
||||
'EPAS/PG server less than 16.0'
|
||||
)),
|
||||
('When maintaining object with default options on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
vacuum_analyze=False,
|
||||
vacuum_freeze=False,
|
||||
vacuum_full=False,
|
||||
verbose=True
|
||||
),
|
||||
url='/maintenance/job/{0}/{1}',
|
||||
expected_cmd_opts=['ANALYZE VERBOSE;\n'],
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE) my_schema.my_table;\n'],
|
||||
)),
|
||||
('When maintaining object with VACUUM FULL, FREEZE, ANALYZE, '
|
||||
'DISABLE_PAGE_SKIPPING on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
vacuum_analyze=True,
|
||||
vacuum_freeze=True,
|
||||
vacuum_full=True,
|
||||
vacuum_disable_page_skipping=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, FULL, FREEZE, ANALYZE, '
|
||||
'DISABLE_PAGE_SKIPPING) my_schema.my_table'
|
||||
';\n'],
|
||||
)),
|
||||
('When maintaining object with VACUUM SKIP LOCKED, TRUNCATE, '
|
||||
'INDEX CLEANUP on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
skip_locked=True,
|
||||
vacuum_truncate=True,
|
||||
vacuum_index_cleanup='OFF',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, SKIP_LOCKED, TRUNCATE, '
|
||||
'INDEX_CLEANUP OFF) my_schema.my_table;\n'],
|
||||
server_min_version=120000,
|
||||
message='VACUUM SKIP_LOCKED, TRUNCATE and INDEX_CLEANUP is not '
|
||||
'supported by EPAS/PG server less than 12.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM PARALLEL on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
vacuum_parallel='15',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, PARALLEL 15) '
|
||||
'my_schema.my_table;\n'],
|
||||
server_min_version=130000,
|
||||
message='VACUUM PARALLEL is not supported by EPAS/PG server '
|
||||
'less than 13.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM PROCESS TOAST on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
vacuum_process_toast=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, PROCESS_TOAST) '
|
||||
'my_schema.my_table;\n'],
|
||||
server_min_version=140000,
|
||||
message='VACUUM PROCESS TOAST is not supported by EPAS/PG server '
|
||||
'less than 14.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM SKIP DATABASE STATS, '
|
||||
'PROCESS MAIN, BUFFER USAGE LIMIT on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
vacuum_process_main=True,
|
||||
vacuum_skip_database_stats=True,
|
||||
buffer_usage_limit='1MB',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, PROCESS_MAIN, '
|
||||
'SKIP_DATABASE_STATS, BUFFER_USAGE_LIMIT "1MB"'
|
||||
') my_schema.my_table;\n'],
|
||||
server_min_version=160000,
|
||||
message='VACUUM SKIP_DATABASE_STATS, PROCESS_MAIN and '
|
||||
'BUFFER_USAGE_LIMIT is not supported by EPAS/PG server '
|
||||
'less than 16.0'
|
||||
)),
|
||||
('When maintaining object with VACUUM ONLY DATABASE STATS on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='VACUUM',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
vacuum_only_database_stats=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['VACUUM (VERBOSE, ONLY_DATABASE_STATS) '
|
||||
'my_schema.my_table;\n'],
|
||||
server_min_version=160000,
|
||||
message='VACUUM ONLY DATABASE STATS is not supported by EPAS/PG '
|
||||
'server less than 16.0'
|
||||
)),
|
||||
('When maintaining object with ANALYZE on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='ANALYZE',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['ANALYZE (VERBOSE) my_schema.my_table;\n'],
|
||||
)),
|
||||
('When maintaining object with ANALYZE SKIP LOCKED on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='ANALYZE',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
skip_locked=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['ANALYZE (VERBOSE, SKIP_LOCKED) '
|
||||
'my_schema.my_table;\n'],
|
||||
server_min_version=120000,
|
||||
message='ANALYZE SKIP_LOCKED is not supported by EPAS/PG server '
|
||||
'less than 12.0'
|
||||
)),
|
||||
('When maintaining object with ANALYZE BUFFER USAGE LIMIT on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='ANALYZE',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
buffer_usage_limit='1MB',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['ANALYZE (VERBOSE, BUFFER_USAGE_LIMIT "1MB"'
|
||||
') my_schema.my_table;\n'],
|
||||
server_min_version=160000,
|
||||
message='ANALYZE BUFFER_USAGE_LIMIT is not supported by '
|
||||
'EPAS/PG server less than 16.0'
|
||||
)),
|
||||
('When maintenance the object with the REINDEX SYSTEM',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='REINDEX',
|
||||
reindex_system=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE) SYSTEM postgres;\n'],
|
||||
)),
|
||||
('When maintenance the object with the REINDEX',
|
||||
dict(
|
||||
|
@ -95,14 +516,207 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
params=dict(
|
||||
database='postgres',
|
||||
op='REINDEX',
|
||||
vacuum_analyze=False,
|
||||
vacuum_freeze=False,
|
||||
vacuum_full=False,
|
||||
verbose=False
|
||||
),
|
||||
url='/maintenance/job/{0}/{1}',
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX DATABASE postgres;\n'],
|
||||
)),
|
||||
('When maintenance the object with the REINDEX CONCURRENTLY',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='REINDEX',
|
||||
reindex_concurrently=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE, CONCURRENTLY) DATABASE '
|
||||
'postgres;\n'],
|
||||
server_min_version=120000,
|
||||
message='REINDEX CONCURRENTLY is not supported by EPAS/PG server '
|
||||
'less than 12.0'
|
||||
)),
|
||||
('When maintenance the object with the REINDEX TABLESPACE',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
op='REINDEX',
|
||||
reindex_tablespace='pg_default',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE, TABLESPACE "pg_default") '
|
||||
'DATABASE postgres;\n'],
|
||||
server_min_version=140000,
|
||||
message='REINDEX TABLESPACE is not supported by EPAS/PG server '
|
||||
'less than 14.0'
|
||||
)),
|
||||
('When maintenance the object with the REINDEX SCHEMA',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
op='REINDEX',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE) SCHEMA my_schema;\n'],
|
||||
)),
|
||||
('When maintenance the object with the REINDEX TABLE',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
op='REINDEX',
|
||||
verbose=False
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX TABLE my_schema.my_table;\n'],
|
||||
)),
|
||||
('When maintenance the object with the REINDEX CONCURRENTLY TABLE',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
op='REINDEX',
|
||||
reindex_concurrently=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE, CONCURRENTLY) TABLE '
|
||||
'my_schema.my_table;\n'],
|
||||
server_min_version=120000,
|
||||
message='REINDEX CONCURRENTLY TABLE is not supported by '
|
||||
'EPAS/PG server less than 12.0'
|
||||
)),
|
||||
('When maintenance the object with the REINDEX TABLESPACE TABLE',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
op='REINDEX',
|
||||
reindex_tablespace='pg_default',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE, TABLESPACE "pg_default") '
|
||||
'TABLE my_schema.my_table;\n'],
|
||||
server_min_version=140000,
|
||||
message='REINDEX TABLESPACE TABLE is not supported by '
|
||||
'EPAS/PG server less than 14.0'
|
||||
)),
|
||||
('When maintenance the object with the REINDEX INDEX',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
index='my_index',
|
||||
op='REINDEX',
|
||||
verbose=False
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX INDEX my_schema.my_index;\n'],
|
||||
)),
|
||||
('When maintenance the object with the REINDEX CONCURRENTLY INDEX',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
index='my_index',
|
||||
op='REINDEX',
|
||||
reindex_concurrently=True,
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE, CONCURRENTLY) INDEX '
|
||||
'my_schema.my_index;\n'],
|
||||
server_min_version=120000,
|
||||
message='REINDEX CONCURRENTLY is not supported by EPAS/PG server '
|
||||
'less than 12.0'
|
||||
)),
|
||||
('When maintenance the object with the REINDEX TABLESPACE INDEX',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
index='my_index',
|
||||
op='REINDEX',
|
||||
reindex_tablespace='pg_default',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['REINDEX (VERBOSE, TABLESPACE "pg_default") '
|
||||
'INDEX my_schema.my_index;\n'],
|
||||
server_min_version=140000,
|
||||
message='REINDEX TABLESPACE is not supported by EPAS/PG server '
|
||||
'less than 14.0'
|
||||
)),
|
||||
('When maintenance the object with the CLUSTER',
|
||||
dict(
|
||||
class_params=dict(
|
||||
|
@ -115,13 +729,50 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
params=dict(
|
||||
database='postgres',
|
||||
op='CLUSTER',
|
||||
vacuum_analyze=False,
|
||||
vacuum_freeze=False,
|
||||
vacuum_full=False,
|
||||
verbose=False
|
||||
verbose=True
|
||||
),
|
||||
url='/maintenance/job/{0}/{1}',
|
||||
expected_cmd_opts=['CLUSTER;\n'],
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['CLUSTER VERBOSE;\n'],
|
||||
)),
|
||||
('When maintenance the object with the CLUSTER on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
op='CLUSTER',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['CLUSTER VERBOSE my_schema.my_table;\n'],
|
||||
)),
|
||||
('When maintenance the object with the CLUSTER on table using index',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
name='test_maintenance_server',
|
||||
port=5444,
|
||||
host='localhost',
|
||||
username='postgres'
|
||||
),
|
||||
params=dict(
|
||||
database='postgres',
|
||||
schema='my_schema',
|
||||
table='my_table',
|
||||
index='my_index',
|
||||
op='CLUSTER',
|
||||
verbose=True
|
||||
),
|
||||
url=MAINTENANCE_URL,
|
||||
expected_cmd_opts=['CLUSTER VERBOSE my_schema.my_table '
|
||||
'USING my_index;\n'],
|
||||
))
|
||||
]
|
||||
|
||||
|
@ -142,9 +793,9 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
if os.name == 'nt':
|
||||
binary_path = binary_path + '.exe'
|
||||
|
||||
retVal = does_utility_exist(binary_path)
|
||||
if retVal is not None:
|
||||
self.skipTest(retVal)
|
||||
ret_val = does_utility_exist(binary_path)
|
||||
if ret_val is not None:
|
||||
self.skipTest(ret_val)
|
||||
|
||||
@patch('pgadmin.tools.maintenance.Server')
|
||||
@patch('pgadmin.tools.maintenance.Message')
|
||||
|
@ -189,6 +840,11 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
|
|||
self.data = database_utils.get_db_data(db_owner)
|
||||
self.db_name = self.data['name']
|
||||
|
||||
if hasattr(self, 'server_min_version') and \
|
||||
server_response["data"]["version"] < \
|
||||
self.server_min_version:
|
||||
self.skipTest(self.message)
|
||||
|
||||
# Create the backup job
|
||||
response = self.tester.post(url,
|
||||
data=json.dumps(self.params),
|
||||
|
|
|
@ -17,7 +17,7 @@ class MaintenanceMessageTest(BaseTestGenerator):
|
|||
|
||||
SERVER_NAME = "server (host:port)"
|
||||
scenarios = [
|
||||
('When maintained the server',
|
||||
('When maintained the server with VACUUM on database',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
|
@ -31,67 +31,190 @@ class MaintenanceMessageTest(BaseTestGenerator):
|
|||
},
|
||||
cmd="VACUUM VERBOSE;\n"
|
||||
),
|
||||
expected_msg="VACUUM (VERBOSE) on database "
|
||||
"'postgres' of server " + SERVER_NAME,
|
||||
expected_details_cmd='VACUUM VERBOSE;'
|
||||
|
||||
expected_msg="VACUUM on database 'postgres' of server " +
|
||||
SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with FULL VERBOSE options',
|
||||
('When maintained the server with VACUUM on table ',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'op': 'VACUUM',
|
||||
'verbose': True
|
||||
},
|
||||
cmd="VACUUM FULL;\n"
|
||||
),
|
||||
expected_msg="VACUUM on table 'postgres/test_schema/test_table' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with VACUUM on constraint ',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'primary_key': 'test_pkey',
|
||||
'op': 'VACUUM',
|
||||
'vacuum_analyze': False,
|
||||
'vacuum_freeze': False,
|
||||
'vacuum_full': True,
|
||||
'verbose': True
|
||||
},
|
||||
cmd="VACUUM FULL VERBOSE;\n"
|
||||
),
|
||||
expected_msg="VACUUM (FULL, VERBOSE) on database "
|
||||
"'postgres' of server " + SERVER_NAME,
|
||||
expected_details_cmd='VACUUM FULL VERBOSE;'
|
||||
|
||||
expected_msg="VACUUM on constraint "
|
||||
"'postgres/test_schema/test_table/test_pkey' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with ANALYZE',
|
||||
('When maintained the server with VACUUM on index ',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'index': 'test_idx',
|
||||
'op': 'VACUUM',
|
||||
'verbose': True
|
||||
},
|
||||
cmd="VACUUM FULL VERBOSE;\n"
|
||||
),
|
||||
expected_msg="VACUUM on index "
|
||||
"'postgres/test_schema/test_table/test_idx' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with ANALYZE on database',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'op': 'ANALYZE',
|
||||
'vacuum_analyze': False,
|
||||
'vacuum_freeze': False,
|
||||
'vacuum_full': False,
|
||||
'verbose': True
|
||||
},
|
||||
cmd="ANALYZE VERBOSE;\n"
|
||||
),
|
||||
expected_msg="ANALYZE(VERBOSE) on database "
|
||||
"'postgres' of server " + SERVER_NAME,
|
||||
expected_details_cmd='ANALYZE VERBOSE;'
|
||||
|
||||
expected_msg="ANALYZE on database 'postgres' of server " +
|
||||
SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with REINDEX',
|
||||
('When maintained the server with ANALYZE on table ',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'op': 'ANALYZE',
|
||||
'verbose': True
|
||||
},
|
||||
cmd="ANALYZE VERBOSE;\n"
|
||||
),
|
||||
expected_msg="ANALYZE on table 'postgres/test_schema/test_table' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with ANALYZE on constraint ',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'primary_key': 'test_pkey',
|
||||
'op': 'ANALYZE',
|
||||
'verbose': True
|
||||
},
|
||||
cmd="ANALYZE FULL VERBOSE;\n"
|
||||
),
|
||||
expected_msg="ANALYZE on constraint "
|
||||
"'postgres/test_schema/test_table/test_pkey' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with ANALYZE on index ',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'index': 'test_idx',
|
||||
'op': 'ANALYZE',
|
||||
'verbose': True
|
||||
},
|
||||
cmd="ANALYZE;\n"
|
||||
),
|
||||
expected_msg="ANALYZE on index "
|
||||
"'postgres/test_schema/test_table/test_idx' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with REINDEX on database',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'op': 'REINDEX',
|
||||
'vacuum_analyze': False,
|
||||
'vacuum_freeze': False,
|
||||
'vacuum_full': False,
|
||||
'verbose': False
|
||||
},
|
||||
cmd="REINDEX (VERBOSE);\n"
|
||||
),
|
||||
expected_msg="REINDEX on database 'postgres' of server " +
|
||||
SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with REINDEX on schema',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'op': 'REINDEX',
|
||||
'verbose': False
|
||||
},
|
||||
cmd="REINDEX (VERBOSE);\n"
|
||||
),
|
||||
expected_msg="REINDEX SCHEMA on schema 'postgres/test_schema' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with REINDEX on table',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'op': 'REINDEX',
|
||||
'verbose': False
|
||||
},
|
||||
cmd="REINDEX;\n"
|
||||
),
|
||||
expected_msg="REINDEX on database "
|
||||
"'postgres' of server " + SERVER_NAME,
|
||||
expected_details_cmd='REINDEX;'
|
||||
|
||||
expected_msg="REINDEX TABLE on table "
|
||||
"'postgres/test_schema/test_table' of server " +
|
||||
SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with REINDEX on index',
|
||||
dict(
|
||||
class_params=dict(
|
||||
sid=1,
|
||||
data={
|
||||
'database': 'postgres',
|
||||
'schema': 'test_schema',
|
||||
'table': 'test_table',
|
||||
'primary_key': 'test_pkey',
|
||||
'op': 'REINDEX',
|
||||
'verbose': False
|
||||
},
|
||||
cmd="REINDEX;\n"
|
||||
),
|
||||
expected_msg="REINDEX INDEX on constraint "
|
||||
"'postgres/test_schema/test_table/test_pkey' "
|
||||
"of server " + SERVER_NAME
|
||||
)),
|
||||
('When maintained the server with CLUSTER',
|
||||
dict(
|
||||
|
@ -100,16 +223,12 @@ class MaintenanceMessageTest(BaseTestGenerator):
|
|||
data={
|
||||
'database': 'postgres',
|
||||
'op': 'CLUSTER',
|
||||
'vacuum_analyze': False,
|
||||
'vacuum_freeze': False,
|
||||
'vacuum_full': False,
|
||||
'verbose': True
|
||||
},
|
||||
cmd="CLUSTER VERBOSE;\n"
|
||||
),
|
||||
expected_msg="CLUSTER on database "
|
||||
"'postgres' of server " + SERVER_NAME,
|
||||
expected_details_cmd='CLUSTER VERBOSE;'
|
||||
expected_msg="CLUSTER on database 'postgres' of server " +
|
||||
SERVER_NAME
|
||||
|
||||
)),
|
||||
]
|
||||
|
@ -125,7 +244,3 @@ class MaintenanceMessageTest(BaseTestGenerator):
|
|||
|
||||
# Check the expected message returned
|
||||
self.assertEqual(maintenance_obj.message, self.expected_msg)
|
||||
|
||||
# Check the command
|
||||
obj_details = maintenance_obj.details(self.class_params['cmd'], None)
|
||||
self.assertIn(self.expected_details_cmd, obj_details['query'])
|
||||
|
|
|
@ -71,9 +71,6 @@ SUPPORTED_AUTH_SOURCES = [INTERNAL,
|
|||
|
||||
BINARY_PATHS = {
|
||||
"as_bin_paths": [
|
||||
{"version": "100000", "next_major_version": "110000",
|
||||
"serverType": gettext("EDB Advanced Server 10"), "binaryPath": None,
|
||||
"isDefault": False},
|
||||
{"version": "110000", "next_major_version": "120000",
|
||||
"serverType": gettext("EDB Advanced Server 11"), "binaryPath": None,
|
||||
"isDefault": False},
|
||||
|
@ -88,12 +85,12 @@ BINARY_PATHS = {
|
|||
"isDefault": False},
|
||||
{"version": "150000", "next_major_version": "160000",
|
||||
"serverType": gettext("EDB Advanced Server 15"), "binaryPath": None,
|
||||
"isDefault": False},
|
||||
{"version": "160000", "next_major_version": "170000",
|
||||
"serverType": gettext("EDB Advanced Server 16"), "binaryPath": None,
|
||||
"isDefault": False}
|
||||
],
|
||||
"pg_bin_paths": [
|
||||
{"version": "100000", "next_major_version": "110000",
|
||||
"serverType": gettext("PostgreSQL 10"), "binaryPath": None,
|
||||
"isDefault": False},
|
||||
{"version": "110000", "next_major_version": "120000",
|
||||
"serverType": gettext("PostgreSQL 11"), "binaryPath": None,
|
||||
"isDefault": False},
|
||||
|
@ -108,6 +105,9 @@ BINARY_PATHS = {
|
|||
"isDefault": False},
|
||||
{"version": "150000", "next_major_version": "160000",
|
||||
"serverType": gettext("PostgreSQL 15"), "binaryPath": None,
|
||||
"isDefault": False},
|
||||
{"version": "160000", "next_major_version": "170000",
|
||||
"serverType": gettext("PostgreSQL 16"), "binaryPath": None,
|
||||
"isDefault": False}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ def get_version_mapping_directories():
|
|||
:param server_type:
|
||||
:return:
|
||||
"""
|
||||
return ({'name': "15_plus", 'number': 150000},
|
||||
return ({'name': "16_plus", 'number': 160000},
|
||||
{'name': "15_plus", 'number': 150000},
|
||||
{'name': "14_plus", 'number': 140000},
|
||||
{'name': "13_plus", 'number': 130000},
|
||||
{'name': "12_plus", 'number': 120000},
|
||||
|
|
|
@ -281,8 +281,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
|
|||
default_binary_path = self.server['default_binary_paths']
|
||||
if default_binary_path is not None:
|
||||
def get_server_version_string():
|
||||
server_version = {150000: '15', 140000: '14', 130000: '13',
|
||||
120000: '12', 110000: '11', 100000: '10'}
|
||||
server_version = {160000: '16', 150000: '15', 140000: '14',
|
||||
130000: '13', 120000: '12', 110000: '11'}
|
||||
for k, v in server_version.items():
|
||||
if k <= self.server_information['server_version']:
|
||||
return v
|
||||
|
|
Loading…
Reference in New Issue