diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 3a8d8d3..c0eaee8 100644 *** a/src/backend/commands/copy.c --- b/src/backend/commands/copy.c *************** BeginCopyFrom(Relation rel, *** 2211,2240 **** } /* ! * Read next tuple from file for COPY FROM. Return false if no more tuples. * ! * valus and nulls arrays must be the same length as columns of the ! * relation passed to BeginCopyFrom. Oid of the tuple is returned with ! * tupleOid separately. */ bool ! NextCopyFrom(CopyState cstate, Datum *values, bool *nulls, Oid *tupleOid) { - TupleDesc tupDesc; - Form_pg_attribute *attr; - AttrNumber num_phys_attrs, - attr_count, - num_defaults = cstate->num_defaults; - FmgrInfo *in_functions = cstate->in_functions; - Oid *typioparams = cstate->typioparams; - int i; - int nfields; char **field_strings; ! bool isnull; ! bool file_has_oids = cstate->file_has_oids; ! int *defmap = cstate->defmap; ! ExprState **defexprs = cstate->defexprs; ! ExprContext *econtext; /* used for ExecEvalExpr for default atts */ /* on input just throw the header line away */ if (cstate->cur_lineno == 0 && cstate->header_line) --- 2211,2236 ---- } /* ! * Read raw fields in the next line for COPY FROM in text or csv mode. ! * Return false if no more lines. * ! * An internal buffer is returned via fields, so the caller must not free it. ! * Since the function returns all fields in the input file, nfields could be ! * smaller or larger than the number of columns. Oid of the tuple is returned ! * with tupleOid separately. */ bool ! NextLineCopyFrom(CopyState cstate, char ***fields, int *nfields, Oid *tupleOid) { char **field_strings; ! ListCell *cur; ! int fldct; ! int fieldno; ! char *string; ! bool done; ! ! /* only available for text or csv input */ ! Assert(!cstate->binary); /* on input just throw the header line away */ if (cstate->cur_lineno == 0 && cstate->header_line) *************** NextCopyFrom(CopyState cstate, Datum *va *** 2244,2270 **** return false; /* done */ } - tupDesc = RelationGetDescr(cstate->rel); - attr = tupDesc->attrs; - num_phys_attrs = tupDesc->natts; - attr_count = list_length(cstate->attnumlist); - nfields = file_has_oids ? (attr_count + 1) : attr_count; - /* XXX: Indentation is not adjusted to keep the patch small. */ cstate->cur_lineno++; - /* Initialize all values for row to NULL */ - MemSet(values, 0, num_phys_attrs * sizeof(Datum)); - MemSet(nulls, true, num_phys_attrs * sizeof(bool)); - - if (!cstate->binary) - { - ListCell *cur; - int fldct; - int fieldno; - char *string; - bool done; - /* Actually read the line into memory here */ done = CopyReadLine(cstate); --- 2240,2248 ---- *************** NextCopyFrom(CopyState cstate, Datum *va *** 2282,2298 **** else fldct = CopyReadAttributesText(cstate); - /* check for overflowing fields */ - if (nfields > 0 && fldct > nfields) - ereport(ERROR, - (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), - errmsg("extra data after last expected column"))); - fieldno = 0; field_strings = cstate->raw_fields; /* Read the OID field if present */ ! if (file_has_oids) { if (fieldno >= fldct) ereport(ERROR, --- 2260,2270 ---- else fldct = CopyReadAttributesText(cstate); fieldno = 0; field_strings = cstate->raw_fields; /* Read the OID field if present */ ! if (cstate->file_has_oids) { if (fieldno >= fldct) ereport(ERROR, *************** NextCopyFrom(CopyState cstate, Datum *va *** 2319,2324 **** --- 2291,2299 ---- } } + *fields = &field_strings[fieldno]; + *nfields = fldct - fieldno; + /* Loop to read the user attributes on the line. */ foreach(cur, cstate->attnumlist) { *************** NextCopyFrom(CopyState cstate, Datum *va *** 2326,2344 **** int m = attnum - 1; if (fieldno >= fldct) ! ereport(ERROR, ! (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), ! errmsg("missing data for column \"%s\"", ! NameStr(attr[m]->attname)))); ! string = field_strings[fieldno++]; ! if (cstate->csv_mode && string == NULL && cstate->force_notnull_flags[m]) { /* Go ahead and read the NULL string */ ! string = cstate->null_print; } cstate->cur_attname = NameStr(attr[m]->attname); cstate->cur_attval = string; values[m] = InputFunctionCall(&in_functions[m], --- 2301,2393 ---- int m = attnum - 1; if (fieldno >= fldct) ! break; ! /* ! * FIXME: force_notnull_flags won't work for extra columsn ! * because we cannot specify it for unnamed columns... ! */ ! if (cstate->csv_mode && field_strings[fieldno] == NULL && cstate->force_notnull_flags[m]) { /* Go ahead and read the NULL string */ ! field_strings[fieldno] = cstate->null_print; } + fieldno++; + } + /* XXX: End of only-indentation changes. */ + + return true; + } + + /* + * Read next tuple from file for COPY FROM. Return false if no more tuples. + * + * values and nulls arrays must be the same length as columns of the + * relation passed to BeginCopyFrom. Oid of the tuple is returned with + * tupleOid separately. + */ + bool + NextCopyFrom(CopyState cstate, Datum *values, bool *nulls, Oid *tupleOid) + { + TupleDesc tupDesc; + Form_pg_attribute *attr; + AttrNumber num_phys_attrs, + attr_count, + num_defaults = cstate->num_defaults; + FmgrInfo *in_functions = cstate->in_functions; + Oid *typioparams = cstate->typioparams; + int i; + bool isnull; + bool file_has_oids = cstate->file_has_oids; + int *defmap = cstate->defmap; + ExprState **defexprs = cstate->defexprs; + ExprContext *econtext; /* used for ExecEvalExpr for default atts */ + + tupDesc = RelationGetDescr(cstate->rel); + attr = tupDesc->attrs; + num_phys_attrs = tupDesc->natts; + attr_count = list_length(cstate->attnumlist); + + /* XXX: Indentation is not adjusted to keep the patch small. */ + /* Initialize all values for row to NULL */ + MemSet(values, 0, num_phys_attrs * sizeof(Datum)); + MemSet(nulls, true, num_phys_attrs * sizeof(bool)); + + if (!cstate->binary) + { + char **field_strings; + ListCell *cur; + int fldct; + int fieldno; + char *string; + + /* read raw fields in the next line */ + if (!NextLineCopyFrom(cstate, &field_strings, &fldct, tupleOid)) + return false; + + /* check for overflowing fields */ + if (attr_count > 0 && fldct > attr_count) + ereport(ERROR, + (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), + errmsg("extra data after last expected column"))); + + fieldno = 0; + + /* Loop to read the user attributes on the line. */ + foreach(cur, cstate->attnumlist) + { + int attnum = lfirst_int(cur); + int m = attnum - 1; + + if (fieldno >= fldct) + ereport(ERROR, + (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), + errmsg("missing data for column \"%s\"", + NameStr(attr[m]->attname)))); + string = field_strings[fieldno++]; + cstate->cur_attname = NameStr(attr[m]->attname); cstate->cur_attval = string; values[m] = InputFunctionCall(&in_functions[m], *************** NextCopyFrom(CopyState cstate, Datum *va *** 2351,2357 **** cstate->cur_attval = NULL; } ! Assert(fieldno == nfields); } else { --- 2400,2406 ---- cstate->cur_attval = NULL; } ! Assert(fieldno == attr_count); } else { *************** NextCopyFrom(CopyState cstate, Datum *va *** 2359,2364 **** --- 2408,2415 ---- int16 fld_count; ListCell *cur; + cstate->cur_lineno++; + if (!CopyGetInt16(cstate, &fld_count)) { /* EOF detected (end of file, or protocol-level EOF) */ diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index 8340e3d..ba5f69b 100644 *** a/src/include/commands/copy.h --- b/src/include/commands/copy.h *************** extern CopyState BeginCopyFrom(Relation *** 28,33 **** --- 28,35 ---- extern void EndCopyFrom(CopyState cstate); extern bool NextCopyFrom(CopyState cstate, Datum *values, bool *nulls, Oid *tupleOid); + extern bool NextLineCopyFrom(CopyState cstate, + char ***fields, int *nfields, Oid *tupleOid); extern void CopyFromErrorCallback(void *arg); extern DestReceiver *CreateCopyDestReceiver(void);