jagged_csv_api-20110204.patch
application/octet-stream
Filename: jagged_csv_api-20110204.patch
Type: application/octet-stream
Part: 0
Message:
Re: exposing COPY API
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 0 | 0 |
| src/include/commands/copy.h | 0 | 0 |
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);