summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-05-23 07:49:59 -0400
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-05-23 07:53:01 -0400
commitfcf91c06e0f836b0db52f2d6f40dd735dd42c7e3 (patch)
tree0d839503d5d5d0b80c04a0c639f5e0d5742df563 /src
parente7e005ed90f7e417696a9388717f91b55fd195bb (diff)
Print line number correctly in COPY.
When COPY uses the multi-insert method to insert a batch of tuples into the heap at a time, incorrect line number was printed if something went wrong in inserting the index tuples (primary key failure, for exampl), or processing after row triggers. Fixes bug #8173 reported by Lloyd Albin. Backpatch to 9.2, where the multi- insert code was added.
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/copy.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index cd6b13c09f3..ac26e811a3e 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -176,6 +176,7 @@ typedef struct CopyStateData
*/
StringInfoData line_buf;
bool line_buf_converted; /* converted to server encoding? */
+ bool line_buf_valid; /* contains the row being processed? */
/*
* Finally, raw_buf holds raw data read from the data source (file or
@@ -283,7 +284,8 @@ static void CopyFromInsertBatch(CopyState cstate, EState *estate,
CommandId mycid, int hi_options,
ResultRelInfo *resultRelInfo, TupleTableSlot *myslot,
BulkInsertState bistate,
- int nBufferedTuples, HeapTuple *bufferedTuples);
+ int nBufferedTuples, HeapTuple *bufferedTuples,
+ int firstBufferedLineNo);
static bool CopyReadLine(CopyState cstate);
static bool CopyReadLineText(CopyState cstate);
static int CopyReadAttributesText(CopyState cstate);
@@ -1776,8 +1778,18 @@ CopyFromErrorCallback(void *arg)
}
else
{
- /* error is relevant to a particular line */
- if (cstate->line_buf_converted || !cstate->need_transcoding)
+ /*
+ * Error is relevant to a particular line.
+ *
+ * If line_buf still contains the correct line, and it's already
+ * transcoded, print it. If it's still in a foreign encoding,
+ * it's quite likely that the error is precisely a failure to do
+ * encoding conversion (ie, bad data). We dare not try to convert
+ * it, and at present there's no way to regurgitate it without
+ * conversion. So we have to punt and just report the line number.
+ */
+ if (cstate->line_buf_valid &&
+ (cstate->line_buf_converted || !cstate->need_transcoding))
{
char *lineval;
@@ -1788,14 +1800,6 @@ CopyFromErrorCallback(void *arg)
}
else
{
- /*
- * Here, the line buffer is still in a foreign encoding, and
- * indeed it's quite likely that the error is precisely a
- * failure to do encoding conversion (ie, bad data). We dare
- * not try to convert it, and at present there's no way to
- * regurgitate it without conversion. So we have to punt and
- * just report the line number.
- */
errcontext("COPY %s, line %d",
cstate->cur_relname, cstate->cur_lineno);
}
@@ -1865,6 +1869,7 @@ CopyFrom(CopyState cstate)
#define MAX_BUFFERED_TUPLES 1000
HeapTuple *bufferedTuples = NULL; /* initialize to silence warning */
Size bufferedTuplesSize = 0;
+ int firstBufferedLineNo = 0;
Assert(cstate->rel);
@@ -2064,6 +2069,8 @@ CopyFrom(CopyState cstate)
if (useHeapMultiInsert)
{
/* Add this tuple to the tuple buffer */
+ if (nBufferedTuples == 0)
+ firstBufferedLineNo = cstate->cur_lineno;
bufferedTuples[nBufferedTuples++] = tuple;
bufferedTuplesSize += tuple->t_len;
@@ -2078,7 +2085,8 @@ CopyFrom(CopyState cstate)
{
CopyFromInsertBatch(cstate, estate, mycid, hi_options,
resultRelInfo, myslot, bistate,
- nBufferedTuples, bufferedTuples);
+ nBufferedTuples, bufferedTuples,
+ firstBufferedLineNo);
nBufferedTuples = 0;
bufferedTuplesSize = 0;
}
@@ -2114,7 +2122,8 @@ CopyFrom(CopyState cstate)
if (nBufferedTuples > 0)
CopyFromInsertBatch(cstate, estate, mycid, hi_options,
resultRelInfo, myslot, bistate,
- nBufferedTuples, bufferedTuples);
+ nBufferedTuples, bufferedTuples,
+ firstBufferedLineNo);
/* Done, clean up */
error_context_stack = errcontext.previous;
@@ -2157,10 +2166,19 @@ static void
CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid,
int hi_options, ResultRelInfo *resultRelInfo,
TupleTableSlot *myslot, BulkInsertState bistate,
- int nBufferedTuples, HeapTuple *bufferedTuples)
+ int nBufferedTuples, HeapTuple *bufferedTuples,
+ int firstBufferedLineNo)
{
MemoryContext oldcontext;
int i;
+ int save_cur_lineno;
+
+ /*
+ * Print error context information correctly, if one of the operations
+ * below fail.
+ */
+ cstate->line_buf_valid = false;
+ save_cur_lineno = cstate->cur_lineno;
/*
* heap_multi_insert leaks memory, so switch to short-lived memory context
@@ -2185,6 +2203,7 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid,
{
List *recheckIndexes;
+ cstate->cur_lineno = firstBufferedLineNo + i;
ExecStoreTuple(bufferedTuples[i], myslot, InvalidBuffer, false);
recheckIndexes =
ExecInsertIndexTuples(myslot, &(bufferedTuples[i]->t_self),
@@ -2204,10 +2223,16 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid,
resultRelInfo->ri_TrigDesc->trig_insert_after_row)
{
for (i = 0; i < nBufferedTuples; i++)
+ {
+ cstate->cur_lineno = firstBufferedLineNo + i;
ExecARInsertTriggers(estate, resultRelInfo,
bufferedTuples[i],
NIL);
+ }
}
+
+ /* reset cur_lineno to where we were */
+ cstate->cur_lineno = save_cur_lineno;
}
/*
@@ -2715,6 +2740,7 @@ CopyReadLine(CopyState cstate)
bool result;
resetStringInfo(&cstate->line_buf);
+ cstate->line_buf_valid = true;
/* Mark that encoding conversion hasn't occurred yet */
cstate->line_buf_converted = false;