aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/copyfromparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/copyfromparse.c')
-rw-r--r--src/backend/commands/copyfromparse.c85
1 files changed, 77 insertions, 8 deletions
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 91b564c2bcb..c346486cd31 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -842,9 +842,10 @@ NextCopyFromRawFields(CopyFromState cstate, char ***fields, int *nfields)
/*
* Read next tuple from file for COPY FROM. Return false if no more tuples.
*
- * 'econtext' is used to evaluate default expression for each column not
- * read from the file. It can be NULL when no default values are used, i.e.
- * when all columns are read from the file.
+ * 'econtext' is used to evaluate default expression for each column that is
+ * either not read from the file or is using the DEFAULT option of COPY FROM.
+ * It can be NULL when no default values are used, i.e. when all columns are
+ * read from the file, and DEFAULT option is unset.
*
* 'values' and 'nulls' arrays must be the same length as columns of the
* relation passed to BeginCopyFrom. This function fills the arrays.
@@ -870,6 +871,7 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
/* Initialize all values for row to NULL */
MemSet(values, 0, num_phys_attrs * sizeof(Datum));
MemSet(nulls, true, num_phys_attrs * sizeof(bool));
+ cstate->defaults = (bool *) palloc0(num_phys_attrs * sizeof(bool));
if (!cstate->opts.binary)
{
@@ -938,12 +940,27 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
cstate->cur_attname = NameStr(att->attname);
cstate->cur_attval = string;
- values[m] = InputFunctionCall(&in_functions[m],
- string,
- typioparams[m],
- att->atttypmod);
+
if (string != NULL)
nulls[m] = false;
+
+ if (cstate->defaults[m])
+ {
+ /*
+ * The caller must supply econtext and have switched into the
+ * per-tuple memory context in it.
+ */
+ Assert(econtext != NULL);
+ Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory);
+
+ values[m] = ExecEvalExpr(defexprs[m], econtext, &nulls[m]);
+ }
+ else
+ values[m] = InputFunctionCall(&in_functions[m],
+ string,
+ typioparams[m],
+ att->atttypmod);
+
cstate->cur_attname = NULL;
cstate->cur_attval = NULL;
}
@@ -1019,10 +1036,12 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
Assert(econtext != NULL);
Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory);
- values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
+ values[defmap[i]] = ExecEvalExpr(defexprs[defmap[i]], econtext,
&nulls[defmap[i]]);
}
+ pfree(cstate->defaults);
+
return true;
}
@@ -1663,6 +1682,31 @@ CopyReadAttributesText(CopyFromState cstate)
if (input_len == cstate->opts.null_print_len &&
strncmp(start_ptr, cstate->opts.null_print, input_len) == 0)
cstate->raw_fields[fieldno] = NULL;
+ /* Check whether raw input matched default marker */
+ else if (cstate->opts.default_print &&
+ input_len == cstate->opts.default_print_len &&
+ strncmp(start_ptr, cstate->opts.default_print, input_len) == 0)
+ {
+ /* fieldno is 0-indexed and attnum is 1-indexed */
+ int m = list_nth_int(cstate->attnumlist, fieldno) - 1;
+
+ if (cstate->defexprs[m] != NULL)
+ {
+ /* defaults contain entries for all physical attributes */
+ cstate->defaults[m] = true;
+ }
+ else
+ {
+ TupleDesc tupDesc = RelationGetDescr(cstate->rel);
+ Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected DEFAULT in COPY data"),
+ errdetail("Column \"%s\" has no DEFAULT value.",
+ NameStr(att->attname))));
+ }
+ }
else
{
/*
@@ -1852,6 +1896,31 @@ endfield:
if (!saw_quote && input_len == cstate->opts.null_print_len &&
strncmp(start_ptr, cstate->opts.null_print, input_len) == 0)
cstate->raw_fields[fieldno] = NULL;
+ /* Check whether raw input matched default marker */
+ else if (cstate->opts.default_print &&
+ input_len == cstate->opts.default_print_len &&
+ strncmp(start_ptr, cstate->opts.default_print, input_len) == 0)
+ {
+ /* fieldno is 0-index and attnum is 1-index */
+ int m = list_nth_int(cstate->attnumlist, fieldno) - 1;
+
+ if (cstate->defexprs[m] != NULL)
+ {
+ /* defaults contain entries for all physical attributes */
+ cstate->defaults[m] = true;
+ }
+ else
+ {
+ TupleDesc tupDesc = RelationGetDescr(cstate->rel);
+ Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected DEFAULT in COPY data"),
+ errdetail("Column \"%s\" has no DEFAULT value.",
+ NameStr(att->attname))));
+ }
+ }
fieldno++;
/* Done if we hit EOL instead of a delim */