diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2024-09-30 17:57:12 -0400 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2024-09-30 17:57:12 -0400 |
| commit | 7702337489810f645b3501d99215c2b525c5abca (patch) | |
| tree | 6f7491e11685972ddb619064e31efa2538ab8436 /src/bin/psql/copy.c | |
| parent | a19f83f87966f763991cc76404f8e42a36e7e842 (diff) | |
Do not treat \. as an EOF marker in CSV mode for COPY IN.
Since backslash is (typically) not special in CSV data, we should
not be treating \. as special either. The server historically did
this to keep CSV and TEXT modes more alike and to support V2 protocol;
but V2 protocol is long dead, and the inconsistency with CSV standards
is annoying. Remove that behavior in CopyReadLineText, and make some
minor consequent code simplifications.
On the client side, we need to fix psql so that it does not check
for \. except when reading data from STDIN (that is, the script
source). We must do that regardless of TEXT/CSV mode or there is
no way to end the COPY short of script EOF. Also, be careful
not to send the \. to the server in that case.
This is a small compatibility break in that other applications
beside psql may need similar adjustment. Also, using an older
version of psql with a v18 server may result in misbehavior
during CSV-mode COPY IN.
Daniel Vérité, reviewed by vignesh C, Robert Haas, and myself
Discussion: https://postgr.es/m/ed659f37-a9dd-42a7-82b9-0da562cc4006@manitou-mail.org
Diffstat (limited to 'src/bin/psql/copy.c')
| -rw-r--r-- | src/bin/psql/copy.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 961ae326949..e020e4d665d 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -620,20 +620,29 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) /* current line is done? */ if (buf[buflen - 1] == '\n') { - /* check for EOF marker, but not on a partial line */ - if (at_line_begin) + /* + * When at the beginning of the line and the data is + * inlined, check for EOF marker. If the marker is found, + * we must stop at this point. If not, the \. line can be + * sent to the server, and we let it decide whether it's + * an EOF or not depending on the format: in TEXT mode, \. + * will be interpreted as an EOF, in CSV, it will not. + */ + if (at_line_begin && copystream == pset.cur_cmd_source) { - /* - * This code erroneously assumes '\.' on a line alone - * inside a quoted CSV string terminates the \copy. - * https://www.postgresql.org/message-id/E1TdNVQ-0001ju-GO@wrigleys.postgresql.org - * - * https://www.postgresql.org/message-id/bfcd57e4-8f23-4c3e-a5db-2571d09208e2@beta.fastmail.com - */ if ((linelen == 3 && memcmp(fgresult, "\\.\n", 3) == 0) || (linelen == 4 && memcmp(fgresult, "\\.\r\n", 4) == 0)) { copydone = true; + + /* + * Remove the EOF marker from the data sent. In + * CSV mode, the EOF marker must be removed, + * otherwise it would be interpreted by the server + * as valid data. + */ + *fgresult = '\0'; + buflen -= linelen; } } |
