@@ -176,6 +176,7 @@ typedef struct CopyStateData
176
176
*/
177
177
StringInfoData line_buf ;
178
178
bool line_buf_converted ; /* converted to server encoding? */
179
+ bool line_buf_valid ; /* contains the row being processed? */
179
180
180
181
/*
181
182
* Finally, raw_buf holds raw data read from the data source (file or
@@ -283,7 +284,8 @@ static void CopyFromInsertBatch(CopyState cstate, EState *estate,
283
284
CommandId mycid , int hi_options ,
284
285
ResultRelInfo * resultRelInfo , TupleTableSlot * myslot ,
285
286
BulkInsertState bistate ,
286
- int nBufferedTuples , HeapTuple * bufferedTuples );
287
+ int nBufferedTuples , HeapTuple * bufferedTuples ,
288
+ int firstBufferedLineNo );
287
289
static bool CopyReadLine (CopyState cstate );
288
290
static bool CopyReadLineText (CopyState cstate );
289
291
static int CopyReadAttributesText (CopyState cstate );
@@ -1776,8 +1778,18 @@ CopyFromErrorCallback(void *arg)
1776
1778
}
1777
1779
else
1778
1780
{
1779
- /* error is relevant to a particular line */
1780
- if (cstate -> line_buf_converted || !cstate -> need_transcoding )
1781
+ /*
1782
+ * Error is relevant to a particular line.
1783
+ *
1784
+ * If line_buf still contains the correct line, and it's already
1785
+ * transcoded, print it. If it's still in a foreign encoding,
1786
+ * it's quite likely that the error is precisely a failure to do
1787
+ * encoding conversion (ie, bad data). We dare not try to convert
1788
+ * it, and at present there's no way to regurgitate it without
1789
+ * conversion. So we have to punt and just report the line number.
1790
+ */
1791
+ if (cstate -> line_buf_valid &&
1792
+ (cstate -> line_buf_converted || !cstate -> need_transcoding ))
1781
1793
{
1782
1794
char * lineval ;
1783
1795
@@ -1788,14 +1800,6 @@ CopyFromErrorCallback(void *arg)
1788
1800
}
1789
1801
else
1790
1802
{
1791
- /*
1792
- * Here, the line buffer is still in a foreign encoding, and
1793
- * indeed it's quite likely that the error is precisely a
1794
- * failure to do encoding conversion (ie, bad data). We dare
1795
- * not try to convert it, and at present there's no way to
1796
- * regurgitate it without conversion. So we have to punt and
1797
- * just report the line number.
1798
- */
1799
1803
errcontext ("COPY %s, line %d" ,
1800
1804
cstate -> cur_relname , cstate -> cur_lineno );
1801
1805
}
@@ -1865,6 +1869,7 @@ CopyFrom(CopyState cstate)
1865
1869
#define MAX_BUFFERED_TUPLES 1000
1866
1870
HeapTuple * bufferedTuples = NULL ; /* initialize to silence warning */
1867
1871
Size bufferedTuplesSize = 0 ;
1872
+ int firstBufferedLineNo = 0 ;
1868
1873
1869
1874
Assert (cstate -> rel );
1870
1875
@@ -2064,6 +2069,8 @@ CopyFrom(CopyState cstate)
2064
2069
if (useHeapMultiInsert )
2065
2070
{
2066
2071
/* Add this tuple to the tuple buffer */
2072
+ if (nBufferedTuples == 0 )
2073
+ firstBufferedLineNo = cstate -> cur_lineno ;
2067
2074
bufferedTuples [nBufferedTuples ++ ] = tuple ;
2068
2075
bufferedTuplesSize += tuple -> t_len ;
2069
2076
@@ -2078,7 +2085,8 @@ CopyFrom(CopyState cstate)
2078
2085
{
2079
2086
CopyFromInsertBatch (cstate , estate , mycid , hi_options ,
2080
2087
resultRelInfo , myslot , bistate ,
2081
- nBufferedTuples , bufferedTuples );
2088
+ nBufferedTuples , bufferedTuples ,
2089
+ firstBufferedLineNo );
2082
2090
nBufferedTuples = 0 ;
2083
2091
bufferedTuplesSize = 0 ;
2084
2092
}
@@ -2114,7 +2122,8 @@ CopyFrom(CopyState cstate)
2114
2122
if (nBufferedTuples > 0 )
2115
2123
CopyFromInsertBatch (cstate , estate , mycid , hi_options ,
2116
2124
resultRelInfo , myslot , bistate ,
2117
- nBufferedTuples , bufferedTuples );
2125
+ nBufferedTuples , bufferedTuples ,
2126
+ firstBufferedLineNo );
2118
2127
2119
2128
/* Done, clean up */
2120
2129
error_context_stack = errcontext .previous ;
@@ -2157,10 +2166,19 @@ static void
2157
2166
CopyFromInsertBatch (CopyState cstate , EState * estate , CommandId mycid ,
2158
2167
int hi_options , ResultRelInfo * resultRelInfo ,
2159
2168
TupleTableSlot * myslot , BulkInsertState bistate ,
2160
- int nBufferedTuples , HeapTuple * bufferedTuples )
2169
+ int nBufferedTuples , HeapTuple * bufferedTuples ,
2170
+ int firstBufferedLineNo )
2161
2171
{
2162
2172
MemoryContext oldcontext ;
2163
2173
int i ;
2174
+ int save_cur_lineno ;
2175
+
2176
+ /*
2177
+ * Print error context information correctly, if one of the operations
2178
+ * below fail.
2179
+ */
2180
+ cstate -> line_buf_valid = false;
2181
+ save_cur_lineno = cstate -> cur_lineno ;
2164
2182
2165
2183
/*
2166
2184
* heap_multi_insert leaks memory, so switch to short-lived memory context
@@ -2185,6 +2203,7 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid,
2185
2203
{
2186
2204
List * recheckIndexes ;
2187
2205
2206
+ cstate -> cur_lineno = firstBufferedLineNo + i ;
2188
2207
ExecStoreTuple (bufferedTuples [i ], myslot , InvalidBuffer , false);
2189
2208
recheckIndexes =
2190
2209
ExecInsertIndexTuples (myslot , & (bufferedTuples [i ]-> t_self ),
@@ -2204,10 +2223,16 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid,
2204
2223
resultRelInfo -> ri_TrigDesc -> trig_insert_after_row )
2205
2224
{
2206
2225
for (i = 0 ; i < nBufferedTuples ; i ++ )
2226
+ {
2227
+ cstate -> cur_lineno = firstBufferedLineNo + i ;
2207
2228
ExecARInsertTriggers (estate , resultRelInfo ,
2208
2229
bufferedTuples [i ],
2209
2230
NIL );
2231
+ }
2210
2232
}
2233
+
2234
+ /* reset cur_lineno to where we were */
2235
+ cstate -> cur_lineno = save_cur_lineno ;
2211
2236
}
2212
2237
2213
2238
/*
@@ -2715,6 +2740,7 @@ CopyReadLine(CopyState cstate)
2715
2740
bool result ;
2716
2741
2717
2742
resetStringInfo (& cstate -> line_buf );
2743
+ cstate -> line_buf_valid = true;
2718
2744
2719
2745
/* Mark that encoding conversion hasn't occurred yet */
2720
2746
cstate -> line_buf_converted = false;
0 commit comments