*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.295 2008/01/01 19:45:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.296 2008/03/08 01:16:26 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
for (;;)
{
bool found_delim = false;
- bool in_quote = false;
bool saw_quote = false;
char *start_ptr;
char *end_ptr;
start_ptr = cur_ptr;
fieldvals[fieldno] = output_ptr;
- /* Scan data for field */
+ /* Scan data for field,
+ *
+ * The loop starts in "not quote" mode and then toggles between
+ * that and "in quote" mode.
+ * The loop exits normally if it is in "not quote" mode and a
+ * delimiter or line end is seen.
+ */
for (;;)
{
char c;
- end_ptr = cur_ptr;
- if (cur_ptr >= line_end_ptr)
- break;
- c = *cur_ptr++;
- /* unquoted field delimiter */
- if (c == delimc && !in_quote)
- {
- found_delim = true;
- break;
- }
- /* start of quoted field (or part of field) */
- if (c == quotec && !in_quote)
+ /* Not in quote */
+ for (;;)
{
- saw_quote = true;
- in_quote = true;
- continue;
+ end_ptr = cur_ptr;
+ if (cur_ptr >= line_end_ptr)
+ goto endfield;
+ c = *cur_ptr++;
+ /* unquoted field delimiter */
+ if (c == delimc)
+ {
+ found_delim = true;
+ goto endfield;
+ }
+ /* start of quoted field (or part of field) */
+ if (c == quotec)
+ {
+ saw_quote = true;
+ break;
+ }
+ /* Add c to output string */
+ *output_ptr++ = c;
}
- /* escape within a quoted field */
- if (c == escapec && in_quote)
+
+ /* In quote */
+ for (;;)
{
- /*
- * peek at the next char if available, and escape it if it is
- * an escape char or a quote char
- */
- if (cur_ptr < line_end_ptr)
- {
- char nextc = *cur_ptr;
+ end_ptr = cur_ptr;
+ if (cur_ptr >= line_end_ptr)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unterminated CSV quoted field")));
+
+ c = *cur_ptr++;
- if (nextc == escapec || nextc == quotec)
+ /* escape within a quoted field */
+ if (c == escapec)
+ {
+ /*
+ * peek at the next char if available, and escape it if it is
+ * an escape char or a quote char
+ */
+ if (cur_ptr < line_end_ptr)
{
- *output_ptr++ = nextc;
- cur_ptr++;
- continue;
+ char nextc = *cur_ptr;
+
+ if (nextc == escapec || nextc == quotec)
+ {
+ *output_ptr++ = nextc;
+ cur_ptr++;
+ continue;
+ }
}
}
- }
+ /*
+ * end of quoted field. Must do this test after testing for escape
+ * in case quote char and escape char are the same (which is the
+ * common case).
+ */
+ if (c == quotec)
+ break;
- /*
- * end of quoted field. Must do this test after testing for escape
- * in case quote char and escape char are the same (which is the
- * common case).
- */
- if (c == quotec && in_quote)
- {
- in_quote = false;
- continue;
+ /* Add c to output string */
+ *output_ptr++ = c;
}
-
- /* Add c to output string */
- *output_ptr++ = c;
}
+ endfield:
/* Terminate attribute value in output area */
*output_ptr++ = '\0';
- /* Shouldn't still be in quote mode */
- if (in_quote)
- ereport(ERROR,
- (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
- errmsg("unterminated CSV quoted field")));
-
/* Check whether raw input matched null marker */
input_len = end_ptr - start_ptr;
if (!saw_quote && input_len == cstate->null_print_len &&