(gdb) bt #0 CopyGetData (cstate=0x555743f07418, databuf=0x555743faaf50, minread=1, maxread=65536) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:247 #1 0x00005557425c18da in CopyLoadRawBuf (cstate=0x555743f07418) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:627 #2 0x00005557425c1a95 in CopyLoadInputBuf (cstate=0x555743f07418) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:689 #3 0x00005557425c2df2 in CopyReadLineText (cstate=0x555743f07418) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:1186 #4 0x00005557425c29cf in CopyReadLine (cstate=0x555743f07418) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:1044 #5 0x00005557425c1f20 in NextCopyFromRawFields (cstate=0x555743f07418, fields=0x7ffd4b9f0d88, nfields=0x7ffd4b9f0d64) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:820 #6 0x00005557425c21f3 in NextCopyFrom (cstate=0x555743f07418, econtext=0x555743fbb298, values=0x555743fa69f8, nulls=0x555743fa6a00) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfromparse.c:882 #7 0x00005557425bebfc in CopyFrom (cstate=0x555743f07418) at /mnt/workspace/postgresql/build/../src/backend/commands/copyfrom.c:859 #8 0x00005557425bb88d in DoCopy (pstate=0x555743f01840, stmt=0x555743ee1518, stmt_location=0, stmt_len=29, processed=0x7ffd4b9f11a0) at /mnt/workspace/postgresql/build/../src/backend/commands/copy.c:298 #9 0x0000555742905c21 in standard_ProcessUtility (pstmt=0x555743ee18e0, queryString=0x555743ee09d0 "COPY tbl FROM STDIN WITH csv;", readOnlyTree=false, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x555743ee19d0, qc=0x7ffd4b9f1510) at /mnt/workspace/postgresql/build/../src/backend/tcop/utility.c:742 #10 0x00005557429055b9 in ProcessUtility (pstmt=0x555743ee18e0, queryString=0x555743ee09d0 "COPY tbl FROM STDIN WITH csv;", readOnlyTree=false, context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x555743ee19d0, qc=0x7ffd4b9f1510) at /mnt/workspace/postgresql/build/../src/backend/tcop/utility.c:530
#0 handleCopyIn (conn=0x5618b20ac2b0, copystream=0x5618b20b5390, isbinary=false, res=0x7ffcd76cf5b0) at /mnt/workspace/postgresql/build/../src/bin/psql/copy.c:514 #1 0x00005618b053aa9d in HandleCopyResult (resultp=0x7ffcd76cf608) at /mnt/workspace/postgresql/build/../src/bin/psql/common.c:939 #2 0x00005618b053bc79 in ExecQueryAndProcessResults ( query=0x5618b20da760 "COPY tbl FROM STDIN WITH csv;", elapsed_msec=0x7ffcd76cf698, svpt_gone_p=0x7ffcd76cf68c, is_watch=false, opt=0x0, printQueryFout=0x0) at /mnt/workspace/postgresql/build/../src/bin/psql/common.c:1565 #3 0x00005618b053b19f in SendQuery ( query=0x5618b20da760 "COPY tbl FROM STDIN WITH csv;") at /mnt/workspace/postgresql/build/../src/bin/psql/common.c:1172 #4 0x00005618b053e4e0 in do_copy ( args=0x5618b20da4c0 "tbl FROM '/tmp/tbl.csv' WITH csv;")
从上面的信息我们可以得知,\copy 命令被转换成 COPY ... FROM STDIN WITH csv;,随后在 handleCopyIn() 函数中读取文件内容并发送到服务器端。
if (!fgresult) copydone = true; else { int linelen;
linelen = strlen(fgresult); buflen += linelen;
/* current line is done? */ if (buf[buflen - 1] == '\n') { /* check for EOF marker, but not on a partial line */ if (at_line_begin) { /* * 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 */ if ((linelen == 3 && memcmp(fgresult, "\\.\n", 3) == 0) || (linelen == 4 && memcmp(fgresult, "\\.\r\n", 4) == 0)) { copydone = true; } }
A documentation warning might be the appropriate response. I don’t see any plausible way for psql to actually fix the problem, short of a protocol change to allow the backend to tell it how the data stream is going to be parsed.