From f26ab219e28ceb88b29f9165800879548dcc6646 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Tue, 1 Sep 2026 14:20:16 -0500 Subject: [PATCH] Fix spurious errors in COPY FROM (FORMAT {text,csv}). The SIMD path for these commands reads ahead into the input buffer via CopyLoadInputBuf(), which reports encoding and conversion errors. The problem is that the errant data might lie beyond the end-of-copy marker, which we aren't copying and thus needn't error for. To fix, add a "speculative" parameter to CopyLoadInputBuf() that defers these errors, and use it in the SIMD path. The errors are instead reported only if we actually reach the errant data. Testing indicates this does not meaningfully impact performance. Oversight in commit e0a3a3fd53. Reviewed-by: Greg Burd Reviewed-by: Nazir Bilal Yavuz Discussion: https://postgr.es/m/apWOr1kgVSqweBnU%40nathan Backpatch-through: 19 --- src/backend/commands/copyfromparse.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c index 500810577ad..0701af16f65 100644 --- a/src/backend/commands/copyfromparse.c +++ b/src/backend/commands/copyfromparse.c @@ -167,7 +167,7 @@ static int CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread); static inline bool CopyGetInt32(CopyFromState cstate, int32 *val); static inline bool CopyGetInt16(CopyFromState cstate, int16 *val); -static void CopyLoadInputBuf(CopyFromState cstate); +static void CopyLoadInputBuf(CopyFromState cstate, bool speculative); static int CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes); void @@ -651,9 +651,14 @@ CopyLoadRawBuf(CopyFromState cstate) * * If INPUT_BUF_BYTES(cstate) > 0, the unprocessed bytes are moved to the start * of the buffer and then we load more data after that. + * + * If "speculative" is true, this function skips reporting any encoding or + * conversion errors, provided there are still data for the caller to process. + * Such callers must be prepared for this function to return without loading + * anything. */ static void -CopyLoadInputBuf(CopyFromState cstate) +CopyLoadInputBuf(CopyFromState cstate, bool speculative) { int nbytes = INPUT_BUF_BYTES(cstate); @@ -681,10 +686,16 @@ CopyLoadInputBuf(CopyFromState cstate) /* * If we reached an invalid byte sequence, or we're at an incomplete * multi-byte character but there is no more raw input data, report - * conversion error. + * conversion error. As an exception, if "speculative" is true and + * there are still data for the caller to process, just return + * instead. */ if (cstate->input_reached_error) + { + if (speculative && INPUT_BUF_BYTES(cstate) > 0) + return; CopyConversionError(cstate); + } /* no more input, and everything has been converted */ if (cstate->input_reached_eof) @@ -1381,7 +1392,7 @@ CopyReadLineTextSIMDHelper(CopyFromState cstate, bool is_csv, { REFILL_LINEBUF; - CopyLoadInputBuf(cstate); + CopyLoadInputBuf(cstate, true); /* update our local variables */ *hit_eof_p = cstate->input_reached_eof; input_buf_ptr = cstate->input_buf_index; @@ -1566,7 +1577,7 @@ CopyReadLineText(CopyFromState cstate, bool is_csv) { REFILL_LINEBUF; - CopyLoadInputBuf(cstate); + CopyLoadInputBuf(cstate, false); /* update our local variables */ hit_eof = cstate->input_reached_eof; input_buf_ptr = cstate->input_buf_index;