Skip to content

Commit 7a25da9

Browse files
Add support for restoring plain SQL database dumps. #5871
1 parent d7faa85 commit 7a25da9

File tree

9 files changed

+232
-50
lines changed

9 files changed

+232
-50
lines changed

docs/en_US/restore_dialog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ restore process:
2727

2828
* Select *Custom or tar* to restore from a custom archive file to create a
2929
copy of the backed-up object.
30+
* Select *Plain* to restore a plain SQL backup. When selecting this option
31+
all the other options will not be applicable.
3032
* Select *Directory* to restore from a compressed directory-format archive.
3133

3234
* Enter the complete path to the backup file in the *Filename* field.

web/pgadmin/static/js/SchemaView/FormView.jsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
} from './hooks';
3333
import { registerView, View } from './registry';
3434
import { createFieldControls, listenDepChanges } from './utils';
35+
import FormViewTab from './FormViewTab';
3536

3637
const ErrorMessageBox = () => {
3738
const [key, setKey] = useState(0);
@@ -181,14 +182,8 @@ export default function FormView({
181182
action={(ref) => ref?.updateIndicator()}
182183
>{
183184
finalGroups.map((tabGroup, idx) =>
184-
<Tab
185-
key={tabGroup.id}
186-
label={tabGroup.label}
187-
data-test={tabGroup.id}
188-
className={
189-
tabGroup.hasError &&
190-
tabValue != idx ? 'tab-with-error' : ''
191-
}
185+
<FormViewTab
186+
key={tabGroup.id} tabGroup={tabGroup} idx={idx} tabValue={tabValue}
192187
/>
193188
)
194189
}{hasSQLTab &&
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/////////////////////////////////////////////////////////////
2+
//
3+
// pgAdmin 4 - PostgreSQL Tools
4+
//
5+
// Copyright (C) 2013 - 2025, The pgAdmin Development Team
6+
// This software is released under the PostgreSQL Licence
7+
//
8+
//////////////////////////////////////////////////////////////
9+
10+
import { Tab } from '@mui/material';
11+
import React, { useContext, useState } from 'react';
12+
import { useFieldOptions, useSchemaStateSubscriber } from './hooks';
13+
import { SchemaStateContext } from './SchemaState';
14+
import PropTypes from 'prop-types';
15+
16+
export default function FormViewTab({tabGroup, idx, tabValue, ...props}) {
17+
const accessPath = [tabGroup.id];
18+
const [refreshKey, setRefreshKey] = useState(0);
19+
const subscriberManager = useSchemaStateSubscriber(setRefreshKey);
20+
const schemaState = useContext(SchemaStateContext);
21+
const options = useFieldOptions(accessPath, schemaState, subscriberManager);
22+
23+
return (
24+
<Tab
25+
key={refreshKey}
26+
label={tabGroup.label}
27+
data-test={tabGroup.id}
28+
iconPosition='start'
29+
disabled={options.disabled}
30+
className={
31+
tabGroup.hasError &&
32+
tabValue != idx ? 'tab-with-error' : ''
33+
}
34+
{...props}
35+
/>
36+
);
37+
};
38+
39+
FormViewTab.muiName = Tab.muiName;
40+
41+
FormViewTab.propTypes = {
42+
tabGroup: PropTypes.object,
43+
idx: PropTypes.number,
44+
tabValue: PropTypes.number,
45+
};

web/pgadmin/static/js/Theme/index.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,13 +788,17 @@ function getFinalTheme(baseTheme) {
788788
MuiTab: {
789789
styleOverrides: {
790790
root: {
791-
'&.MuiTab-textColorPrimary':{
791+
'&:not(.Mui-disabled).MuiTab-textColorPrimary':{
792792
color: baseTheme.palette.text.primary,
793793
},
794794
'&.Mui-selected': {
795795
color: baseTheme.otherVars.activeColor,
796796
},
797-
}
797+
},
798+
icon: {
799+
fontSize: '1rem',
800+
marginRight: '2px',
801+
},
798802
}
799803
},
800804
MuiBackdrop: {

web/pgadmin/tools/restore/__init__.py

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,18 @@ def _get_create_req_data():
141141
data = json.loads(request.data)
142142

143143
try:
144-
_file = filename_with_file_manager_path(data['file'])
144+
filepath = filename_with_file_manager_path(data['file'])
145145
except Exception as e:
146146
return True, internal_server_error(errormsg=str(e)), data, None
147147

148-
if _file is None:
148+
if filepath is None:
149149
return True, make_json_response(
150150
status=410,
151151
success=0,
152152
errormsg=_("File could not be found.")
153-
), data, _file
153+
), data, filepath
154154

155-
return False, '', data, _file
155+
return False, '', data, filepath
156156

157157

158158
def _connect_server(sid):
@@ -263,15 +263,15 @@ def set_multiple(key, param, data, args, driver, conn, with_schema=True):
263263
return False
264264

265265

266-
def _set_args_param_values(data, manager, server, driver, conn, _file):
266+
def get_restore_util_args(data, manager, server, driver, conn, filepath):
267267
"""
268-
add args to the list.
268+
return the args for the command
269269
:param data: Data.
270270
:param manager: Manager.
271271
:param server: Server.
272272
:param driver: Driver.
273273
:param conn: Connection.
274-
:param _file: File.
274+
:param filepath: File.
275275
:return: args list.
276276
"""
277277
args = []
@@ -347,11 +347,56 @@ def _set_args_param_values(data, manager, server, driver, conn, _file):
347347
False)
348348
set_multiple('indexes', '--index', data, args, driver, conn, False)
349349

350-
args.append(fs_short_path(_file))
350+
args.append(fs_short_path(filepath))
351351

352352
return args
353353

354354

355+
def get_sql_util_args(data, manager, server, filepath):
356+
"""
357+
return the args for the command
358+
:param data: Data.
359+
:param manager: Manager.
360+
:param server: Server.
361+
:param filepath: File.
362+
:return: args list.
363+
"""
364+
args = [
365+
'--host',
366+
manager.local_bind_host if manager.use_ssh_tunnel else server.host,
367+
'--port',
368+
str(manager.local_bind_port) if manager.use_ssh_tunnel
369+
else str(server.port),
370+
'--username', server.username, '--dbname',
371+
data['database'],
372+
'--file', fs_short_path(filepath)
373+
]
374+
375+
return args
376+
377+
378+
def use_restore_utility(data, manager, server, driver, conn, filepath):
379+
utility = manager.utility('restore')
380+
ret_val = does_utility_exist(utility)
381+
if ret_val:
382+
return ret_val, None, None
383+
384+
args = get_restore_util_args(data, manager, server, driver, conn, filepath)
385+
386+
return None, utility, args
387+
388+
389+
def use_sql_utility(data, manager, server, filepath):
390+
utility = manager.utility('sql')
391+
ret_val = does_utility_exist(utility)
392+
if ret_val:
393+
return ret_val, None, None
394+
395+
args = get_sql_util_args(data, manager, server, filepath)
396+
397+
return None, utility, args
398+
399+
355400
@blueprint.route('/job/<int:sid>', methods=['POST'], endpoint='create_job')
356401
@pga_login_required
357402
def create_restore_job(sid):
@@ -364,24 +409,27 @@ def create_restore_job(sid):
364409
Returns:
365410
None
366411
"""
367-
is_error, errmsg, data, _file = _get_create_req_data()
412+
is_error, errmsg, data, filepath = _get_create_req_data()
368413
if is_error:
369414
return errmsg
370415

371416
is_error, errmsg, driver, manager, conn, _, server = _connect_server(sid)
372417
if is_error:
373418
return errmsg
374419

375-
utility = manager.utility('restore')
376-
ret_val = does_utility_exist(utility)
377-
if ret_val:
420+
if data['format'] == 'plain':
421+
error_msg, utility, args = use_sql_utility(
422+
data, manager, server, filepath)
423+
else:
424+
error_msg, utility, args = use_restore_utility(
425+
data, manager, server, driver, conn, filepath)
426+
427+
if error_msg is not None:
378428
return make_json_response(
379429
success=0,
380-
errormsg=ret_val
430+
errormsg=error_msg
381431
)
382432

383-
args = _set_args_param_values(data, manager, server, driver, conn, _file)
384-
385433
try:
386434
p = BatchProcess(
387435
desc=RestoreMessage(

web/pgadmin/tools/restore/static/js/restore.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ define('tools.restore', [
8181
()=>getRestoreDisableOptionSchema({nodeInfo: treeNodeInfo}),
8282
()=>getRestoreMiscellaneousSchema({nodeInfo: treeNodeInfo}),
8383
{
84-
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData)
84+
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
85+
nodeType: itemNodeData._type,
8586
},
8687
treeNodeInfo,
8788
pgBrowser

0 commit comments

Comments
 (0)