diff options
Diffstat (limited to 'src/backend/commands/copyfromparse.c')
-rw-r--r-- | src/backend/commands/copyfromparse.c | 85 |
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 */ |