@@ -842,9 +842,10 @@ NextCopyFromRawFields(CopyFromState cstate, char ***fields, int *nfields)
842842/*
843843 * Read next tuple from file for COPY FROM. Return false if no more tuples.
844844 *
845- * 'econtext' is used to evaluate default expression for each column not
846- * read from the file. It can be NULL when no default values are used, i.e.
847- * when all columns are read from the file.
845+ * 'econtext' is used to evaluate default expression for each column that is
846+ * either not read from the file or is using the DEFAULT option of COPY FROM.
847+ * It can be NULL when no default values are used, i.e. when all columns are
848+ * read from the file, and DEFAULT option is unset.
848849 *
849850 * 'values' and 'nulls' arrays must be the same length as columns of the
850851 * relation passed to BeginCopyFrom. This function fills the arrays.
@@ -870,6 +871,7 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
870871 /* Initialize all values for row to NULL */
871872 MemSet (values , 0 , num_phys_attrs * sizeof (Datum ));
872873 MemSet (nulls , true, num_phys_attrs * sizeof (bool ));
874+ cstate -> defaults = (bool * ) palloc0 (num_phys_attrs * sizeof (bool ));
873875
874876 if (!cstate -> opts .binary )
875877 {
@@ -938,12 +940,27 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
938940
939941 cstate -> cur_attname = NameStr (att -> attname );
940942 cstate -> cur_attval = string ;
941- values [m ] = InputFunctionCall (& in_functions [m ],
942- string ,
943- typioparams [m ],
944- att -> atttypmod );
943+
945944 if (string != NULL )
946945 nulls [m ] = false;
946+
947+ if (cstate -> defaults [m ])
948+ {
949+ /*
950+ * The caller must supply econtext and have switched into the
951+ * per-tuple memory context in it.
952+ */
953+ Assert (econtext != NULL );
954+ Assert (CurrentMemoryContext == econtext -> ecxt_per_tuple_memory );
955+
956+ values [m ] = ExecEvalExpr (defexprs [m ], econtext , & nulls [m ]);
957+ }
958+ else
959+ values [m ] = InputFunctionCall (& in_functions [m ],
960+ string ,
961+ typioparams [m ],
962+ att -> atttypmod );
963+
947964 cstate -> cur_attname = NULL ;
948965 cstate -> cur_attval = NULL ;
949966 }
@@ -1019,10 +1036,12 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
10191036 Assert (econtext != NULL );
10201037 Assert (CurrentMemoryContext == econtext -> ecxt_per_tuple_memory );
10211038
1022- values [defmap [i ]] = ExecEvalExpr (defexprs [i ], econtext ,
1039+ values [defmap [i ]] = ExecEvalExpr (defexprs [defmap [ i ] ], econtext ,
10231040 & nulls [defmap [i ]]);
10241041 }
10251042
1043+ pfree (cstate -> defaults );
1044+
10261045 return true;
10271046}
10281047
@@ -1663,6 +1682,31 @@ CopyReadAttributesText(CopyFromState cstate)
16631682 if (input_len == cstate -> opts .null_print_len &&
16641683 strncmp (start_ptr , cstate -> opts .null_print , input_len ) == 0 )
16651684 cstate -> raw_fields [fieldno ] = NULL ;
1685+ /* Check whether raw input matched default marker */
1686+ else if (cstate -> opts .default_print &&
1687+ input_len == cstate -> opts .default_print_len &&
1688+ strncmp (start_ptr , cstate -> opts .default_print , input_len ) == 0 )
1689+ {
1690+ /* fieldno is 0-indexed and attnum is 1-indexed */
1691+ int m = list_nth_int (cstate -> attnumlist , fieldno ) - 1 ;
1692+
1693+ if (cstate -> defexprs [m ] != NULL )
1694+ {
1695+ /* defaults contain entries for all physical attributes */
1696+ cstate -> defaults [m ] = true;
1697+ }
1698+ else
1699+ {
1700+ TupleDesc tupDesc = RelationGetDescr (cstate -> rel );
1701+ Form_pg_attribute att = TupleDescAttr (tupDesc , m );
1702+
1703+ ereport (ERROR ,
1704+ (errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
1705+ errmsg ("unexpected DEFAULT in COPY data" ),
1706+ errdetail ("Column \"%s\" has no DEFAULT value." ,
1707+ NameStr (att -> attname ))));
1708+ }
1709+ }
16661710 else
16671711 {
16681712 /*
@@ -1852,6 +1896,31 @@ CopyReadAttributesCSV(CopyFromState cstate)
18521896 if (!saw_quote && input_len == cstate -> opts .null_print_len &&
18531897 strncmp (start_ptr , cstate -> opts .null_print , input_len ) == 0 )
18541898 cstate -> raw_fields [fieldno ] = NULL ;
1899+ /* Check whether raw input matched default marker */
1900+ else if (cstate -> opts .default_print &&
1901+ input_len == cstate -> opts .default_print_len &&
1902+ strncmp (start_ptr , cstate -> opts .default_print , input_len ) == 0 )
1903+ {
1904+ /* fieldno is 0-index and attnum is 1-index */
1905+ int m = list_nth_int (cstate -> attnumlist , fieldno ) - 1 ;
1906+
1907+ if (cstate -> defexprs [m ] != NULL )
1908+ {
1909+ /* defaults contain entries for all physical attributes */
1910+ cstate -> defaults [m ] = true;
1911+ }
1912+ else
1913+ {
1914+ TupleDesc tupDesc = RelationGetDescr (cstate -> rel );
1915+ Form_pg_attribute att = TupleDescAttr (tupDesc , m );
1916+
1917+ ereport (ERROR ,
1918+ (errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
1919+ errmsg ("unexpected DEFAULT in COPY data" ),
1920+ errdetail ("Column \"%s\" has no DEFAULT value." ,
1921+ NameStr (att -> attname ))));
1922+ }
1923+ }
18551924
18561925 fieldno ++ ;
18571926 /* Done if we hit EOL instead of a delim */
0 commit comments