From: Daniele Varrazzo Date: Wed, 25 May 2022 21:10:04 +0000 (+0100) Subject: fix(copy): correctly escape non-printable chars X-Git-Tag: 3.1~67^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34c2c65d8e2db26992968ceeb286925b69450ec7;p=thirdparty%2Fpsycopg.git fix(copy): correctly escape non-printable chars Postgres was doing the right thing with them, but the format was wrong. --- diff --git a/docs/news.rst b/docs/news.rst index e556be1b6..2ea5328e2 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -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 --------------- diff --git a/psycopg_c/psycopg_c/_psycopg/copy.pyx b/psycopg_c/psycopg_c/_psycopg/copy.pyx index c5d05240b..b943095d1 100644 --- a/psycopg_c/psycopg_c/_psycopg/copy.pyx +++ b/psycopg_c/psycopg_c/_psycopg/copy.pyx @@ -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 = CDumper.ensure_size(out, pos, tmpsize) for j in range(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 */