@@ -842,9 +842,10 @@ NextCopyFromRawFields(CopyFromState cstate, char ***fields, int *nfields)
842
842
/*
843
843
* Read next tuple from file for COPY FROM. Return false if no more tuples.
844
844
*
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.
848
849
*
849
850
* 'values' and 'nulls' arrays must be the same length as columns of the
850
851
* relation passed to BeginCopyFrom. This function fills the arrays.
@@ -870,6 +871,7 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
870
871
/* Initialize all values for row to NULL */
871
872
MemSet (values , 0 , num_phys_attrs * sizeof (Datum ));
872
873
MemSet (nulls , true, num_phys_attrs * sizeof (bool ));
874
+ cstate -> defaults = (bool * ) palloc0 (num_phys_attrs * sizeof (bool ));
873
875
874
876
if (!cstate -> opts .binary )
875
877
{
@@ -938,12 +940,27 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
938
940
939
941
cstate -> cur_attname = NameStr (att -> attname );
940
942
cstate -> cur_attval = string ;
941
- values [m ] = InputFunctionCall (& in_functions [m ],
942
- string ,
943
- typioparams [m ],
944
- att -> atttypmod );
943
+
945
944
if (string != NULL )
946
945
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
+
947
964
cstate -> cur_attname = NULL ;
948
965
cstate -> cur_attval = NULL ;
949
966
}
@@ -1019,10 +1036,12 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
1019
1036
Assert (econtext != NULL );
1020
1037
Assert (CurrentMemoryContext == econtext -> ecxt_per_tuple_memory );
1021
1038
1022
- values [defmap [i ]] = ExecEvalExpr (defexprs [i ], econtext ,
1039
+ values [defmap [i ]] = ExecEvalExpr (defexprs [defmap [ i ] ], econtext ,
1023
1040
& nulls [defmap [i ]]);
1024
1041
}
1025
1042
1043
+ pfree (cstate -> defaults );
1044
+
1026
1045
return true;
1027
1046
}
1028
1047
@@ -1663,6 +1682,31 @@ CopyReadAttributesText(CopyFromState cstate)
1663
1682
if (input_len == cstate -> opts .null_print_len &&
1664
1683
strncmp (start_ptr , cstate -> opts .null_print , input_len ) == 0 )
1665
1684
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
+ }
1666
1710
else
1667
1711
{
1668
1712
/*
@@ -1852,6 +1896,31 @@ CopyReadAttributesCSV(CopyFromState cstate)
1852
1896
if (!saw_quote && input_len == cstate -> opts .null_print_len &&
1853
1897
strncmp (start_ptr , cstate -> opts .null_print , input_len ) == 0 )
1854
1898
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
+ }
1855
1924
1856
1925
fieldno ++ ;
1857
1926
/* Done if we hit EOL instead of a delim */
0 commit comments