Re: [pgAdmin][RM4590] Schema Backup fails with names that requires quoting
Aditya Toshniwal <[email protected]>
| Newsgroups | gmane.comp.db.postgresql.pgadmin.devel |
|---|---|
| Message-ID | <CAM9w-_mwnOMS2HDySELRsQqUYF9X4aFbOauwJqAzMHB2iTYLSw@mail.gmail.com> |
Hi Hackers, Attached is the updated patch. Tested on MacOS, Windows 7, Ubuntu 16 and works fine. Kindly review. On Wed, Oct 9, 2019 at 1:48 PM Akshay Joshi <[email protected]> wrote: > Hi Aditya > > I have tried your patch on MAC. Backup job is completed successfully but > got the following message: > pg_dump: last built-in OID is 16383 > pg_dump: no matching schemas were found > > Please verify it once again and send the modified patch. > > On Tue, Oct 8, 2019 at 5:46 PM Aditya Toshniwal < > [email protected]> wrote: > >> Hi Hackers, >> >> Turned out to be an issue only on Mac. Backup works fine for other OS. >> Attached is the patch to fix the issue on Mac. Code is changed to add >> extra pairs of quotes wherever required on MacOS. >> >> Kindly review. >> >> On Thu, Oct 3, 2019 at 3:53 PM Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the patch to fix the schema backup with names that requires >>> double quotes. >>> Command line has special meaning for double quotes and so the command is >>> run without the double quotes if applied on objects. Code is changed to add >>> extra pairs of quotes to save our object quotes. >>> >>> Also fixed a test case which was failing if certain paths had spaces in >>> between. >>> >>> Kindly review. >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Sr. Software Engineer | EnterpriseDB India | Pune >>> "Don't Complain about Heat, Plant a TREE" >>> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Sr. Software Engineer | EnterpriseDB India | Pune >> "Don't Complain about Heat, Plant a TREE" >> > > > -- > *Thanks & Regards* > *Akshay Joshi* > > *Sr. Software Architect* > *EnterpriseDB Software India Private Limited* > *Mobile: +91 976-788-8246* > -- Thanks and Regards, Aditya Toshniwal Sr. Software Engineer | EnterpriseDB India | Pune "Don't Complain about Heat, Plant a TREE"
RM4590_V3.patch
(application/octet-stream, 6.2 KB)
diff --git a/web/pgadmin/misc/bgprocess/__init__.py b/web/pgadmin/misc/bgprocess/__init__.py
index 765ad54b..be17a830 100644
--- a/web/pgadmin/misc/bgprocess/__init__.py
+++ b/web/pgadmin/misc/bgprocess/__init__.py
@@ -120,3 +120,18 @@ def stop_process(pid):
return success_return()
except LookupError as lerr:
return gone(errormsg=str(lerr))
+
+
+def escape_dquotes_process_arg(arg):
+ # Double quotes has special meaning for shell command line and they are
+ # run without the double quotes. Add extra quotes to save our double
+ # quotes from stripping.
+
+ # This cannot be at common place as this file executes
+ # separately from pgadmin
+ dq_id = "#DQ#"
+
+ if arg.startswith('"') and arg.endswith('"'):
+ return r'{0}{1}{0}'.format(dq_id, arg)
+ else:
+ return arg
diff --git a/web/pgadmin/misc/bgprocess/process_executor.py b/web/pgadmin/misc/bgprocess/process_executor.py
old mode 100644
new mode 100755
index 6ac73ee8..8f3c423d
--- a/web/pgadmin/misc/bgprocess/process_executor.py
+++ b/web/pgadmin/misc/bgprocess/process_executor.py
@@ -60,6 +60,22 @@ else:
)
+def unescape_dquotes_process_arg(arg):
+ # Double quotes has special meaning for shell command line and they are
+ # run without the double quotes.
+ #
+ # Remove the saviour #DQ#
+
+ # This cannot be at common place as this file executes
+ # separately from pgadmin
+ dq_id = "#DQ#"
+
+ if arg.startswith(dq_id) and arg.endswith(dq_id):
+ return '{0}'.format(arg[len(dq_id):-len(dq_id)])
+ else:
+ return arg
+
+
def _log_exception():
type_, value_, traceback_ = info = sys.exc_info()
@@ -274,14 +290,14 @@ def update_status(**kw):
raise ValueError("Please verify pid and db_file arguments.")
-def execute():
+def execute(argv):
"""
This function will execute the background process
Returns:
None
"""
- command = sys.argv[1:]
+ command = argv[1:]
args = dict()
_log('Initialize the process execution: {0}'.format(command))
@@ -363,7 +379,7 @@ def execute():
process_stderr.log(data[1])
# If executable not found or invalid arguments passed
- except OSError:
+ except OSError as e:
info = _log_exception()
args.update({'exit_code': 500})
if process_stderr:
@@ -421,6 +437,10 @@ def convert_environment_variables(env):
if __name__ == '__main__':
+ argv = [
+ unescape_dquotes_process_arg(arg) for arg in sys.argv
+ ]
+
_sys_encoding = sys.getdefaultencoding()
if not _sys_encoding or _sys_encoding == 'ascii':
# Fall back to 'utf-8', if we couldn't determine the default encoding,
@@ -466,7 +486,7 @@ if __name__ == '__main__':
# Let's do the job assigning to it.
try:
_log('Executing the command now from the detached child...')
- execute()
+ execute(argv)
except Exception:
_log_exception()
else:
@@ -500,7 +520,7 @@ if __name__ == '__main__':
}
cmd = [sys.executable]
- cmd.extend(sys.argv)
+ cmd.extend(argv)
_log('[PARENT] Command executings: {0}'.format(cmd))
@@ -549,7 +569,7 @@ if __name__ == '__main__':
w.close()
_log('[CHILD] Start executing the background process...')
- execute()
+ execute(argv)
except Exception:
_log_exception()
sys.exit(1)
diff --git a/web/pgadmin/setup/tests/test_export_import_servers.py b/web/pgadmin/setup/tests/test_export_import_servers.py
index 564384ad..b4d6d4e3 100644
--- a/web/pgadmin/setup/tests/test_export_import_servers.py
+++ b/web/pgadmin/setup/tests/test_export_import_servers.py
@@ -36,13 +36,13 @@ class ImportExportServersTestCase(BaseTestGenerator):
# Load the servers
os.system(
- "python %s --load-servers %s 2> %s" %
+ "python \"%s\" --load-servers \"%s\" 2> %s" %
(setup, os.path.join(path, "servers.json"), os.devnull)
)
# And dump them again
tf = tempfile.NamedTemporaryFile(delete=False)
- os.system("python %s --dump-servers %s 2> %s" %
+ os.system("python \"%s\" --dump-servers \"%s\" 2> %s" %
(setup, tf.name, os.devnull))
# Compare the JSON files, ignoring servers that exist in our
diff --git a/web/pgadmin/tools/backup/__init__.py b/web/pgadmin/tools/backup/__init__.py
index ac7b4ff3..23b96548 100644
--- a/web/pgadmin/tools/backup/__init__.py
+++ b/web/pgadmin/tools/backup/__init__.py
@@ -24,6 +24,7 @@ from pgadmin.utils.ajax import make_json_response, bad_request
from config import PG_DEFAULT_DRIVER
from pgadmin.model import Server
+from pgadmin.misc.bgprocess import escape_dquotes_process_arg
# set template path for sql scripts
MODULE_NAME = 'backup'
@@ -419,14 +420,19 @@ def create_backup_objects_job(sid):
if 'schemas' in data:
for s in data['schemas']:
- args.extend(['--schema', s])
+ args.extend(['--schema', r'{0}'.format(
+ driver.qtIdent(conn, s).replace('"', '\"'))])
if 'tables' in data:
for s, t in data['tables']:
args.extend([
- '--table', driver.qtIdent(conn, s, t)
+ '--table', r'{0}'.format(
+ driver.qtIdent(conn, s, t).replace('"', '\"'))
])
+ escaped_args = [
+ escape_dquotes_process_arg(arg) for arg in args
+ ]
try:
if backup_obj_type == 'objects':
args.append(data['database'])
@@ -439,7 +445,7 @@ def create_backup_objects_job(sid):
*args,
database=data['database']
),
- cmd=utility, args=args
+ cmd=utility, args=escaped_args
)
else:
p = BatchProcess(
@@ -452,7 +458,7 @@ def create_backup_objects_job(sid):
) else data['file'],
*args
),
- cmd=utility, args=args
+ cmd=utility, args=escaped_args
)
manager.export_password_env(p.id)