Skip to content

Commit 73a55e0

Browse files
Add support for restoring plain SQL database dumps. #5871
1 parent 53077b6 commit 73a55e0

File tree

8 files changed

+213
-49
lines changed

8 files changed

+213
-49
lines changed

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 [, 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={tabGroup.id}
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: 64 additions & 14 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
"""
268268
add args to the list.
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,58 @@ 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+
add args to the list.
358+
:param data: Data.
359+
:param manager: Manager.
360+
:param server: Server.
361+
:param driver: Driver.
362+
:param conn: Connection.
363+
:param filepath: File.
364+
:return: args list.
365+
"""
366+
args = [
367+
'--host',
368+
manager.local_bind_host if manager.use_ssh_tunnel else server.host,
369+
'--port',
370+
str(manager.local_bind_port) if manager.use_ssh_tunnel
371+
else str(server.port),
372+
'--username', server.username, '--dbname',
373+
data['database'],
374+
'--file', fs_short_path(filepath)
375+
]
376+
377+
return args
378+
379+
380+
def use_restore_utility(data, manager, server, driver, conn, filepath):
381+
utility = manager.utility('restore')
382+
ret_val = does_utility_exist(utility)
383+
if ret_val:
384+
return ret_val, None, None
385+
386+
args = get_restore_util_args(data, manager, server, driver, conn, filepath)
387+
388+
return None, utility, args
389+
390+
391+
def use_sql_utility(data, manager, server, filepath):
392+
utility = manager.utility('sql')
393+
ret_val = does_utility_exist(utility)
394+
if ret_val:
395+
return ret_val, None, None
396+
397+
args = get_sql_util_args(data, manager, server, filepath)
398+
399+
return None, utility, args
400+
401+
355402
@blueprint.route('/job/<int:sid>', methods=['POST'], endpoint='create_job')
356403
@pga_login_required
357404
def create_restore_job(sid):
@@ -364,24 +411,27 @@ def create_restore_job(sid):
364411
Returns:
365412
None
366413
"""
367-
is_error, errmsg, data, _file = _get_create_req_data()
414+
is_error, errmsg, data, filepath = _get_create_req_data()
368415
if is_error:
369416
return errmsg
370417

371418
is_error, errmsg, driver, manager, conn, _, server = _connect_server(sid)
372419
if is_error:
373420
return errmsg
374421

375-
utility = manager.utility('restore')
376-
ret_val = does_utility_exist(utility)
377-
if ret_val:
422+
if data['format'] == 'plain':
423+
error_msg, utility, args = use_sql_utility(
424+
data, manager, server, filepath)
425+
else:
426+
error_msg, utility, args = use_restore_utility(
427+
data, manager, server, driver, conn, filepath)
428+
429+
if error_msg is not None:
378430
return make_json_response(
379431
success=0,
380-
errormsg=ret_val
432+
errormsg=error_msg
381433
)
382434

383-
args = _set_args_param_values(data, manager, server, driver, conn, _file)
384-
385435
try:
386436
p = BatchProcess(
387437
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)