]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix(copy): correctly escape non-printable chars
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 25 May 2022 21:10:04 +0000 (22:10 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 28 May 2022 01:02:30 +0000 (02:02 +0100)
Postgres was doing the right thing with them, but the format was wrong.

docs/news.rst
psycopg_c/psycopg_c/_psycopg/copy.pyx

index e556be1b6c33ef6b1a05037c6714d1a1206d20a1..2ea5328e292f7a0ca5899c02a6f3248a06ae9558 100644 (file)
@@ -30,6 +30,13 @@ Psycopg 3.1 (unreleased)
 - Drop support for Python 3.6.
 
 
+Psycopg 3.0.15 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Fix wrong escaping of unprintable chars in COPY (nonetheless correctly
+  interpreted by PostgreSQL).
+
+
 Current release
 ---------------
 
index c5d05240b9b9aab7279076aeaaed7c4a0c64ead5..b943095d11cdea669ab8c7df903126150c4befae 100644 (file)
@@ -158,7 +158,8 @@ def format_row_text(
         # Now from pos to pos + size there is a textual representation: it may
         # contain chars to escape. Scan to find how many such chars there are.
         for j in range(size):
-            nesc += copy_escape_lut[target[j]]
+            if copy_escape_lut[target[j]]:
+                nesc += 1
 
         # If there is any char to escape, walk backwards pushing the chars
         # forward and interspersing backslashes.
@@ -166,12 +167,14 @@ def format_row_text(
             tmpsize = size + nesc
             target = <unsigned char *>CDumper.ensure_size(out, pos, tmpsize)
             for j in range(<int>size - 1, -1, -1):
-                target[j + nesc] = target[j]
-                if copy_escape_lut[target[j]] != 0:
+                if copy_escape_lut[target[j]]:
+                    target[j + nesc] = copy_escape_lut[target[j]]
                     nesc -= 1
                     target[j + nesc] = b"\\"
                     if nesc <= 0:
                         break
+                else:
+                    target[j + nesc] = target[j]
             pos += tmpsize
         else:
             pos += size
@@ -293,24 +296,24 @@ cdef extern from *:
 /* handle chars to (un)escape in text copy representation */
 /* '\b', '\t', '\n', '\v', '\f', '\r', '\\' */
 
-/* Which char to prepend a backslash when escaping */
+/* Escaping chars */
 static const char copy_escape_lut[] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0,   0,   0,   0,   0,   0,   0,   0,  98, 116, 110, 118, 102, 114,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  92,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 };
 
 /* Conversion of escaped to unescaped chars */