This is an automated email from the ASF dual-hosted git repository.

yjhjstz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 45496ef56ca7d12ada45f89a75d7102eaf1027f1
Author: Zhenghua Lyu <[email protected]>
AuthorDate: Mon Aug 22 09:48:12 2022 +0800

    Escape database name for dbconn.
    
    This is really a bug of the Python Package PyGreSQL,
    see issue: https://github.com/PyGreSQL/PyGreSQL/issues/77
    
    As a workaround, let's modify GPDB's code to manually
    escape before passing args to pgdb.
---
 gpMgmt/bin/gppylib/db/dbconn.py       | 11 ++++++++++-
 src/test/regress/input/gpcopy.source  |  2 ++
 src/test/regress/output/gpcopy.source |  1 +
 src/test/regress/test_dbconn.py       | 30 ++++++++++++++++++++++++++++++
 4 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/gpMgmt/bin/gppylib/db/dbconn.py b/gpMgmt/bin/gppylib/db/dbconn.py
index 7d3f839f68..f6633827b7 100644
--- a/gpMgmt/bin/gppylib/db/dbconn.py
+++ b/gpMgmt/bin/gppylib/db/dbconn.py
@@ -210,7 +210,16 @@ def connect(dburl, utility=False, verbose=False,
         'password': dburl.pgpass,
         'host': dburl.pghost,
         'port': dburl.pgport,
-        'database': dburl.pgdb,
+        # dbname is very subtle, Package pgdb contains a bug it will only 
escape the string when
+        #   1. a space in the dbname, and
+        #   2. there are other keyword arguments of pgdb.connect method
+        # See issue https://github.com/PyGreSQL/PyGreSQL/issues/77 for details
+        # The code here is test if there is space, if so, we know pgdb will 
escape, let's not do here
+        # if not, let's do escape here since pgdb forget to do.
+        #
+        # NB: we always provide port keyword argument to connect method of 
pgdb, thus
+        # we will always enter the code path of pgdb.connect of the above 
escape logic.
+        'database': dburl.pgdb if ' ' in dburl.pgdb else 
dburl.pgdb.replace('\\', '\\\\').replace("'", "\\'"),
     }
 
     # building options
diff --git a/src/test/regress/input/gpcopy.source 
b/src/test/regress/input/gpcopy.source
index d8b2f5e078..12f0baa34c 100644
--- a/src/test/regress/input/gpcopy.source
+++ b/src/test/regress/input/gpcopy.source
@@ -1324,6 +1324,8 @@ DROP DATABASE IF EXISTS "funny copy""db'with\\quotes";
 reset client_min_messages;
 CREATE DATABASE "funny copy""db'with\\quotes";
 
+\! python3 test_dbconn.py 1
+
 \c "funny copy""db'with\\quotes"
 -- echo will behave differently on different platforms, force to use bash with 
-E option
 COPY (SELECT 'data1') TO PROGRAM 'cat > /tmp/gpcopyenvtest; /usr/bin/env bash 
-c ''echo -E database in COPY TO: $GP_DATABASE >> /tmp/gpcopyenvtest '' ' 
ESCAPE 'OFF';
diff --git a/src/test/regress/output/gpcopy.source 
b/src/test/regress/output/gpcopy.source
index 3de1b63621..b1ef7e5af6 100755
--- a/src/test/regress/output/gpcopy.source
+++ b/src/test/regress/output/gpcopy.source
@@ -1643,6 +1643,7 @@ set client_min_messages='warning';
 DROP DATABASE IF EXISTS "funny copy""db'with\\quotes";
 reset client_min_messages;
 CREATE DATABASE "funny copy""db'with\\quotes";
+\! python3 test_dbconn.py 1
 \c "funny copy""db'with\\quotes"
 -- echo will behave differently on different platforms, force to use bash with 
-E option
 COPY (SELECT 'data1') TO PROGRAM 'cat > /tmp/gpcopyenvtest; /usr/bin/env bash 
-c ''echo -E database in COPY TO: $GP_DATABASE >> /tmp/gpcopyenvtest '' ' 
ESCAPE 'OFF';
diff --git a/src/test/regress/test_dbconn.py b/src/test/regress/test_dbconn.py
new file mode 100644
index 0000000000..d9c9700dae
--- /dev/null
+++ b/src/test/regress/test_dbconn.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+#-*- coding: utf-8 -*-
+
+# This is just to test we can use dbconn to connect a database
+# whose name contains special chars. This test needs to have
+# a cluster running so seems not easy under unittest. Previously,
+# I try to create a UDF to test it udner regress test, however,
+# import dbconn, its dependency package will import sys and access
+# argv, which is not allowed in plpython. So finally, I create
+# the python script in this directory, and use \! to run it and
+# test in regress/dispatch and regress/gpcopy.
+
+import sys
+from gppylib.db import dbconn
+
+dbnames = ['funny\"db\'with\\\\quotes',    # from regress/dispatch
+           'funny copy\"db\'with\\\\quotes'# from regress/gpcopy
+]
+
+def test_connect_special_dbname(dbname):
+    url = dbconn.DbURL(dbname=dbname)
+    conn = dbconn.connect(url)
+    count = dbconn.querySingleton(conn, "select 1")
+    result = (count == 1)
+    conn.close()
+
+
+if __name__ == "__main__":
+    dbname = dbnames[int(sys.argv[1])]
+    test_connect_special_dbname(dbname)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to