mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added support to drop databases using the 'WITH (FORCE)' option. #6367
This commit is contained in:
@@ -26,16 +26,12 @@ When using main browser window, the following keyboard shortcuts are available:
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+d | Delete object |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+m | Delete/Drop multiple objects |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Ctrl+[ | Dialog tab backward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Ctrl+] | Dialog tab forward |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+g | Direct debugging |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+u | Drop Cascade multiple objects |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+e | Edit object properties |
|
||||
+----------------------------+-------------------------------------------------------+
|
||||
| Shift+Alt+f | File main menu |
|
||||
|
@@ -58,12 +58,14 @@ following options (in alphabetical order):
|
||||
| *Create* | Click *Create* to access a context menu that provides context-sensitive selections. |
|
||||
| | Your selection opens a *Create* dialog for creating a new object. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete/Drop* | Click to delete the currently selected object from the server. |
|
||||
| *Delete* | Click to delete the currently selected object from the server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Cascade)* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Force)* | Click to delete the currently selected database with force option. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Disconnect from server* | Click to disconnect from the currently selected server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Drop Cascade* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Properties...* | Click to review or modify the currently selected object's properties. |
|
||||
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Refresh* | Click to refresh the currently selected object. |
|
||||
|
@@ -20,6 +20,7 @@ Bundled PostgreSQL Utilities
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #6367 <https://github.com/pgadmin-org/pgadmin4/issues/6367>`_ - Added support to drop databases using the 'WITH (FORCE)' option.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
@@ -49,14 +49,16 @@ following selections (options appear in alphabetical order):
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Debugging* | Click through to open the :ref:`Debug <debugger>` tool or to select *Set breakpoint* to stop or pause a script execution. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete/Drop* | Click to delete the currently selected object from the server. |
|
||||
| *Delete* | Click to delete the currently selected object from the server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Cascade)* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Delete (Force)* | Click to delete the currently selected database with force option. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Disconnect Database...* | Click to terminate a database connection. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Disconnect from server* | Click to disconnect from the currently selected server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Drop Cascade* | Click to delete the currently selected object and all dependent objects from the server. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Debugging* | Click to access the :ref:`Debugger <debugger>` tool. |
|
||||
+---------------------------+---------------------------------------------------------------------------------------------------------------------------+
|
||||
| *Grant Wizard* | Click to access the :ref:`Grant Wizard <grant_wizard>` tool. |
|
||||
|
@@ -343,36 +343,6 @@ def register_browser_preferences(self):
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'grid_menu_drop_multiple',
|
||||
gettext('Delete/Drop multiple objects'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 77, 'char': 'm'}
|
||||
},
|
||||
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'grid_menu_drop_cascade_multiple',
|
||||
gettext('Drop Cascade multiple objects'),
|
||||
'keyboardshortcut',
|
||||
{
|
||||
'alt': True,
|
||||
'shift': True,
|
||||
'control': False,
|
||||
'key': {'key_code': 85, 'char': 'u'}
|
||||
},
|
||||
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
|
||||
fields=fields
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'keyboard_shortcuts',
|
||||
'context_menu',
|
||||
|
@@ -195,7 +195,9 @@ class DatabaseView(PGChildNodeView):
|
||||
],
|
||||
'vopts': [
|
||||
{}, {'get': 'variable_options'}
|
||||
]
|
||||
],
|
||||
'delete': [{'delete': 'delete'},
|
||||
{'delete': 'delete'}]
|
||||
})
|
||||
|
||||
def check_precondition(action=None):
|
||||
@@ -1002,7 +1004,8 @@ class DatabaseView(PGChildNodeView):
|
||||
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, self._DELETE_SQL]),
|
||||
datname=res, conn=self.conn
|
||||
datname=res, conn=self.conn,
|
||||
with_force=self.cmd == 'delete'
|
||||
)
|
||||
|
||||
status, msg = default_conn.execute_scalar(sql)
|
||||
|
@@ -22,6 +22,14 @@ define('pgadmin.node.database', [
|
||||
'pgadmin.authenticate.kerberos', 'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, pgAdmin, pgBrowser, Kerberos) {
|
||||
|
||||
function canDeleteWithForce(itemNodeData, item) {
|
||||
let treeData = pgBrowser.tree.getTreeNodeHierarchy(item),
|
||||
server = treeData['server'],
|
||||
canDisconnect = !_.isUndefined(itemNodeData?.canDisconn) ? itemNodeData.canDisconn : true;
|
||||
|
||||
return (canDisconnect && server && server.version >= 130000);
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['coll-database']) {
|
||||
pgBrowser.Nodes['coll-database'] =
|
||||
pgBrowser.Collection.extend({
|
||||
@@ -33,6 +41,7 @@ define('pgadmin.node.database', [
|
||||
canDrop: true,
|
||||
selectParentNodeOnDelete: true,
|
||||
canDropCascade: false,
|
||||
canDropForce: canDeleteWithForce,
|
||||
statsPrettifyFields: [gettext('Size'), gettext('Size of temporary files')],
|
||||
});
|
||||
}
|
||||
@@ -90,9 +99,14 @@ define('pgadmin.node.database', [
|
||||
data_disabled: gettext('Selected database is already connected.'),
|
||||
},
|
||||
},{
|
||||
name: 'delete_database_force', node: 'database', module: this,
|
||||
applies: ['object', 'context'], callback: 'delete_database_force',
|
||||
category: 'delete', priority: 2, label: gettext('Delete (Force)'),
|
||||
enable : canDeleteWithForce,
|
||||
}, {
|
||||
name: 'disconnect_database', node: 'database', module: this,
|
||||
applies: ['object', 'context'], callback: 'disconnect_database',
|
||||
category: 'drop', priority: 5, label: gettext('Disconnect from database'),
|
||||
category: 'disconnect', priority: 5, label: gettext('Disconnect from database'),
|
||||
enable : 'is_connected',data: {
|
||||
data_disabled: gettext('Selected database is already disconnected.'),
|
||||
},
|
||||
@@ -123,7 +137,6 @@ define('pgadmin.node.database', [
|
||||
// If server is less than 10 then do not allow 'create' menu
|
||||
return server && server.version >= 100000;
|
||||
},
|
||||
|
||||
is_not_connected: function(node) {
|
||||
return (node && !node.connected && node.allowConn);
|
||||
},
|
||||
@@ -310,6 +323,10 @@ define('pgadmin.node.database', [
|
||||
if (!d.allowConn) return;
|
||||
pgBrowser.Node.callbacks.refresh.apply(this, arguments);
|
||||
},
|
||||
|
||||
delete_database_force: function(args, item) {
|
||||
pgBrowser.Node.callbacks.delete_obj.apply(this, [{'url': 'delete'}, item]);
|
||||
}
|
||||
},
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
let c_types = ()=>getNodeAjaxOptions('get_ctypes', this, treeNodeInfo, itemNodeData, {
|
||||
@@ -437,7 +454,6 @@ define('pgadmin.node.database', [
|
||||
} else {
|
||||
Notify.success(res.info);
|
||||
}
|
||||
// obj.trigger('connected', obj, _item, _data);
|
||||
pgBrowser.Events.trigger(
|
||||
'pgadmin:database:connected', _item, _data
|
||||
);
|
||||
|
@@ -4,5 +4,5 @@ SELECT db.datname as name FROM pg_catalog.pg_database as db WHERE db.oid = {{did
|
||||
{% endif %}
|
||||
{# Using name from above query we will drop the database #}
|
||||
{% if datname %}
|
||||
DROP DATABASE IF EXISTS {{ conn|qtIdent(datname) }};
|
||||
DROP DATABASE IF EXISTS {{ conn|qtIdent(datname) }}{% if with_force %} WITH (FORCE){%endif%};
|
||||
{% endif %}
|
||||
|
@@ -1,10 +0,0 @@
|
||||
{# We need database name before we execute drop #}
|
||||
{% if db_ids %}
|
||||
SELECT db.datname as name FROM pg_catalog.pg_database as db WHERE db.oid in {{db_ids}};
|
||||
{% endif %}
|
||||
{# Using name from above query we will drop the database #}
|
||||
{% if dbname_array %}
|
||||
{% for db in dbname_array %}
|
||||
DROP DATABASE {{ conn|qtIdent(db.name) }};
|
||||
{% endfor %}
|
||||
{% endif %}
|
@@ -0,0 +1,64 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import uuid
|
||||
import json
|
||||
|
||||
from pgadmin.utils import server_utils
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression import parent_node_dict
|
||||
from regression.python_test_utils import test_utils as utils
|
||||
|
||||
|
||||
class DatabaseMultipleDeleteForceTestCase(BaseTestGenerator):
|
||||
""" This class will delete the multiple database with force option under
|
||||
last added server. """
|
||||
scenarios = [
|
||||
# Fetching default URL for database node.
|
||||
('Delete with Force URL', dict(url='/browser/database/delete/'))
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
if self.server_information['server_version'] < 130000:
|
||||
message = "Delete with Force are not supported by PG < 130000."
|
||||
self.skipTest(message)
|
||||
|
||||
self.db_names = ["db_delete_%s" % str(uuid.uuid4())[1:8],
|
||||
"db_delete_%s" % str(uuid.uuid4())[1:8]]
|
||||
|
||||
self.db_ids = [utils.create_database(self.server, self.db_names[0]),
|
||||
utils.create_database(self.server, self.db_names[1])]
|
||||
|
||||
self.server_id = parent_node_dict["server"][-1]["server_id"]
|
||||
|
||||
def runTest(self):
|
||||
""" This function will delete the databases."""
|
||||
server_response = server_utils.connect_server(self, self.server_id)
|
||||
if server_response["data"]["connected"]:
|
||||
data = {'ids': self.db_ids}
|
||||
response = self.tester.delete(
|
||||
self.url + str(utils.SERVER_GROUP) + '/' +
|
||||
str(self.server_id) + '/',
|
||||
follow_redirects=True,
|
||||
data=json.dumps(data),
|
||||
content_type='html/json')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
else:
|
||||
raise Exception("Could not connect to server to delete the "
|
||||
"database.")
|
||||
|
||||
def tearDown(self):
|
||||
"""This function drop the added databases"""
|
||||
connection = utils.get_db_connection(self.server['db'],
|
||||
self.server['username'],
|
||||
self.server['db_password'],
|
||||
self.server['host'],
|
||||
self.server['port'],
|
||||
self.server['sslmode'])
|
||||
utils.drop_database_multiple(connection, self.db_names)
|
@@ -39,8 +39,6 @@ _.extend(pgBrowser.keyboardNavigation, {
|
||||
'sub_menu_refresh': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_refresh').value),
|
||||
'context_menu': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'context_menu').value),
|
||||
'direct_debugging': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'direct_debugging').value),
|
||||
'drop_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_multiple').value),
|
||||
'drop_cascade_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_cascade_multiple').value),
|
||||
'add_grid_row': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'add_grid_row').value),
|
||||
'open_quick_search': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'open_quick_search').value),
|
||||
|
||||
@@ -62,8 +60,6 @@ _.extend(pgBrowser.keyboardNavigation, {
|
||||
'bindSubMenuRefresh': {'shortcuts': this.keyboardShortcut.sub_menu_refresh, 'bindElem': '#tree'}, // Sub menu - Refresh object,
|
||||
'bindContextMenu': {'shortcuts': this.keyboardShortcut.context_menu}, // Sub menu - Open context menu,
|
||||
'bindDirectDebugging': {'shortcuts': this.keyboardShortcut.direct_debugging}, // Sub menu - Direct Debugging
|
||||
'bindDropMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_multiple_objects}, // Grid Menu Drop Multiple
|
||||
'bindDropCascadeMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_cascade_multiple_objects}, // Grid Menu Drop Cascade Multiple
|
||||
'bindAddGridRow': {'shortcuts': this.keyboardShortcut.add_grid_row}, // Subnode Grid Add Row
|
||||
'bindOpenQuickSearch': {'shortcuts': this.keyboardShortcut.open_quick_search}, // Subnode Grid Refresh Row
|
||||
};
|
||||
|
@@ -144,7 +144,7 @@ define('pgadmin.browser.node', [
|
||||
applies: ['object', 'context'],
|
||||
callback: 'delete_obj',
|
||||
priority: self.dropPriority,
|
||||
label: (self.dropAsRemove) ? gettext('Remove %s', self.label) : gettext('Delete/Drop'),
|
||||
label: (self.dropAsRemove) ? gettext('Remove %s', self.label) : gettext('Delete'),
|
||||
data: {
|
||||
'url': 'drop',
|
||||
data_disabled: gettext('The selected tree node does not support this option.'),
|
||||
@@ -162,8 +162,8 @@ define('pgadmin.browser.node', [
|
||||
module: self,
|
||||
applies: ['object', 'context'],
|
||||
callback: 'delete_obj',
|
||||
priority: 3,
|
||||
label: gettext('Drop Cascade'),
|
||||
priority: 2,
|
||||
label: gettext('Delete (Cascade)'),
|
||||
data: {
|
||||
'url': 'delete',
|
||||
},
|
||||
@@ -657,11 +657,14 @@ define('pgadmin.browser.node', [
|
||||
|
||||
let msg, title;
|
||||
|
||||
if (input.url == 'delete') {
|
||||
if (input.url == 'delete' && d._type === 'database') {
|
||||
msg = gettext('Delete database with the force option will attempt to terminate all existing connections to the "%s" database. Are you sure you want to proceed?', d.label);
|
||||
title = gettext('Delete FORCE %s?', obj.label);
|
||||
|
||||
msg = gettext('Are you sure you want to drop %s "%s" and all the objects that depend on it?',
|
||||
} else if (input.url == 'delete') {
|
||||
msg = gettext('Are you sure you want to delete %s "%s" and all the objects that depend on it?',
|
||||
obj.label.toLowerCase(), d.label);
|
||||
title = gettext('DROP CASCADE %s?', obj.label);
|
||||
title = gettext('Delete CASCADE %s?', obj.label);
|
||||
|
||||
if (!(_.isFunction(obj.canDropCascade) ?
|
||||
obj.canDropCascade.apply(obj, [d, i]) : obj.canDropCascade)) {
|
||||
@@ -676,8 +679,8 @@ define('pgadmin.browser.node', [
|
||||
msg = gettext('Are you sure you want to remove %s "%s"?', obj.label.toLowerCase(), d.label);
|
||||
title = gettext('Remove %s?', obj.label);
|
||||
} else {
|
||||
msg = gettext('Are you sure you want to drop %s "%s"?', obj.label.toLowerCase(), d.label);
|
||||
title = gettext('Drop %s?', obj.label);
|
||||
msg = gettext('Are you sure you want to delete %s "%s"?', obj.label.toLowerCase(), d.label);
|
||||
title = gettext('Delete %s?', obj.label);
|
||||
}
|
||||
|
||||
if (!(_.isFunction(obj.canDrop) ?
|
||||
|
@@ -21,8 +21,10 @@ import PropTypes from 'prop-types';
|
||||
import { PgIconButton } from '../../static/js/components/Buttons';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import DeleteSweepIcon from '@material-ui/icons/DeleteSweep';
|
||||
import DeleteForeverIcon from '@material-ui/icons/DeleteForever';
|
||||
import EmptyPanelMessage from '../../static/js/components/EmptyPanelMessage';
|
||||
import Loader from 'sources/components/Loader';
|
||||
import { evalFunc } from '../../static/js/utils';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
emptyPanel: {
|
||||
@@ -139,7 +141,7 @@ export function CollectionNodeView({
|
||||
|
||||
if (selRows.length === 0) {
|
||||
Notify.alert(
|
||||
gettext('Drop Multiple'),
|
||||
gettext('Delete Multiple'),
|
||||
gettext('Please select at least one object to delete.')
|
||||
);
|
||||
return;
|
||||
@@ -150,23 +152,31 @@ export function CollectionNodeView({
|
||||
if (type === 'dropCascade') {
|
||||
url = selNode.generate_url(selItem, 'delete');
|
||||
msg = gettext(
|
||||
'Are you sure you want to drop all the selected objects and all the objects that depend on them?'
|
||||
'Are you sure you want to delete all the selected objects and all the objects that depend on them?'
|
||||
);
|
||||
title = gettext('DROP CASCADE multiple objects?');
|
||||
title = gettext('Delete CASCADE multiple objects?');
|
||||
} else if (type === 'dropForce') {
|
||||
url = selNode.generate_url(selItem, 'delete');
|
||||
msg = gettext(
|
||||
'Delete databases with the force option will attempt to terminate all the existing connections to the selected databases. Are you sure you want to proceed?'
|
||||
);
|
||||
title = gettext('Delete FORCE multiple objects?');
|
||||
} else {
|
||||
url = selNode.generate_url(selItem, 'drop');
|
||||
msg = gettext('Are you sure you want to drop all the selected objects?');
|
||||
title = gettext('DROP multiple objects?');
|
||||
msg = gettext('Are you sure you want to delete all the selected objects?');
|
||||
title = gettext('Delete multiple objects?');
|
||||
}
|
||||
|
||||
const api = getApiInstance();
|
||||
let dropNodeProperties = function () {
|
||||
setLoaderText(gettext('Deleting Objects...'));
|
||||
api
|
||||
.delete(url, {
|
||||
data: JSON.stringify({ ids: selRows }),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
})
|
||||
.then(function (res) {
|
||||
setLoaderText('');
|
||||
if (res.success == 0) {
|
||||
Notify.alert(res.errormsg, res.info);
|
||||
}
|
||||
@@ -174,8 +184,9 @@ export function CollectionNodeView({
|
||||
setReload(!reload);
|
||||
})
|
||||
.catch(function (error) {
|
||||
setLoaderText('');
|
||||
Notify.alert(
|
||||
gettext('Error dropping %s', selectedItemData._label.toLowerCase()),
|
||||
gettext('Error deleting %s', selectedItemData._label.toLowerCase()),
|
||||
_.isUndefined(error.response) ? error.message : error.response.data.errormsg
|
||||
);
|
||||
});
|
||||
@@ -200,7 +211,7 @@ export function CollectionNodeView({
|
||||
|
||||
let tableColumns = [];
|
||||
let column = {};
|
||||
setLoaderText('Loading...');
|
||||
setLoaderText(gettext('Loading...'));
|
||||
|
||||
if (itemNodeData._type.indexOf('coll-') > -1 && !_.isUndefined(nodeObj.getSchema)) {
|
||||
schemaRef.current = nodeObj.getSchema?.call(nodeObj, treeNodeInfo, itemNodeData);
|
||||
@@ -269,41 +280,59 @@ export function CollectionNodeView({
|
||||
}, [itemNodeData, node, item, reload]);
|
||||
|
||||
const CustomHeader = () => {
|
||||
const canDrop = evalFunc(node, node.canDrop, itemNodeData, item, treeNodeInfo);
|
||||
const canDropCascade = evalFunc(node, node.canDropCascade, itemNodeData, item, treeNodeInfo);
|
||||
const canDropForce = evalFunc(node, node.canDropForce, itemNodeData, item, treeNodeInfo);
|
||||
return (
|
||||
<Box >
|
||||
<PgIconButton
|
||||
className={classes.dropButton}
|
||||
icon={<DeleteIcon/>}
|
||||
aria-label="Delete/Drop"
|
||||
title={gettext('Delete/Drop')}
|
||||
aria-label="Delete"
|
||||
title={gettext('Delete')}
|
||||
onClick={() => {
|
||||
onDrop('drop');
|
||||
}}
|
||||
disabled={
|
||||
(selectedObject.length > 0)
|
||||
? !node.canDrop
|
||||
? !canDrop
|
||||
: true
|
||||
}
|
||||
></PgIconButton>
|
||||
<PgIconButton
|
||||
{node.type !== 'coll-database' ? <PgIconButton
|
||||
className={classes.dropButton}
|
||||
icon={<DeleteSweepIcon />}
|
||||
aria-label="Drop Cascade"
|
||||
title={gettext('Drop Cascade')}
|
||||
aria-label="Delete Cascade"
|
||||
title={gettext('Delete (Cascade)')}
|
||||
onClick={() => {
|
||||
onDrop('dropCascade');
|
||||
}}
|
||||
disabled={
|
||||
(selectedObject.length > 0)
|
||||
? !node.canDropCascade
|
||||
? !canDropCascade
|
||||
: true
|
||||
}
|
||||
></PgIconButton>
|
||||
></PgIconButton> :
|
||||
<PgIconButton
|
||||
className={classes.dropButton}
|
||||
icon={<DeleteForeverIcon />}
|
||||
aria-label="Delete Force"
|
||||
title={gettext('Delete (Force)')}
|
||||
onClick={() => {
|
||||
onDrop('dropForce');
|
||||
}}
|
||||
disabled={
|
||||
(selectedObject.length > 0)
|
||||
? !canDropForce
|
||||
: true
|
||||
}
|
||||
></PgIconButton>}
|
||||
</Box>);
|
||||
};
|
||||
|
||||
return (
|
||||
<Theme className='obj_properties'>
|
||||
<Loader message={loaderText}/>
|
||||
<Box className={classes.propertiesPanel}>
|
||||
{data.length > 0 ?
|
||||
(
|
||||
|
@@ -358,9 +358,9 @@ function checkBinaryPathExists(binaryPathArray, selectedServerVersion) {
|
||||
}
|
||||
|
||||
/* If a function, then evaluate */
|
||||
export function evalFunc(obj, func, param) {
|
||||
export function evalFunc(obj, func, ...param) {
|
||||
if(_.isFunction(func)) {
|
||||
return func.apply(obj, [param]);
|
||||
return func.apply(obj, [...param]);
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
@@ -564,7 +564,11 @@ def drop_database(connection, database_name):
|
||||
if pg_cursor.fetchall():
|
||||
old_isolation_level = connection.isolation_level
|
||||
set_isolation_level(connection, 0)
|
||||
pg_cursor.execute('''DROP DATABASE "%s"''' % database_name)
|
||||
if connection.info.server_version >= 130000:
|
||||
pg_cursor.execute(
|
||||
'''DROP DATABASE "%s" WITH (FORCE)''' % database_name)
|
||||
else:
|
||||
pg_cursor.execute('''DROP DATABASE "%s"''' % database_name)
|
||||
set_isolation_level(connection, old_isolation_level)
|
||||
connection.commit()
|
||||
connection.close()
|
||||
@@ -594,7 +598,11 @@ def drop_database_multiple(connection, database_names):
|
||||
if pg_cursor.fetchall():
|
||||
old_isolation_level = connection.isolation_level
|
||||
set_isolation_level(connection, 0)
|
||||
pg_cursor.execute('''DROP DATABASE "%s"''' % database_name)
|
||||
if connection.info.server_version >= 130000:
|
||||
pg_cursor.execute(
|
||||
'''DROP DATABASE "%s" WITH (FORCE)''' % database_name)
|
||||
else:
|
||||
pg_cursor.execute('''DROP DATABASE "%s"''' % database_name)
|
||||
set_isolation_level(connection, old_isolation_level)
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
Reference in New Issue
Block a user