summaryrefslogtreecommitdiff
path: root/src/backend/commands/copy.c
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2023-03-13 10:01:56 -0400
committerAndrew Dunstan <andrew@dunslane.net>2023-03-13 10:01:56 -0400
commit9f8377f7a27910bf0f35bf5169a8046731948a79 (patch)
treee0a19449e4cebb8923dfcd1bba95a1d3363faa32 /src/backend/commands/copy.c
parent7b14e20b12cc8358cad9bdd05dd6b7de7f73c431 (diff)
Add a DEFAULT option to COPY FROM
This allows for a string which if an input field matches causes the column's default value to be inserted. The advantage of this is that the default can be inserted in some rows and not others, for which non-default data is available. The file_fdw extension is also modified to take allow use of this option. Israel Barth Rubio Discussion: https://postgr.es/m/CAO_rXXAcqesk6DsvioOZ5zmeEmpUN5ktZf-9=9yu+DTr0Xr8Uw@mail.gmail.com
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r--src/backend/commands/copy.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f3bbd91fe3e..167d31a2d99 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -464,6 +464,12 @@ ProcessCopyOptions(ParseState *pstate,
errorConflictingDefElem(defel, pstate);
opts_out->null_print = defGetString(defel);
}
+ else if (strcmp(defel->defname, "default") == 0)
+ {
+ if (opts_out->default_print)
+ errorConflictingDefElem(defel, pstate);
+ opts_out->default_print = defGetString(defel);
+ }
else if (strcmp(defel->defname, "header") == 0)
{
if (header_specified)
@@ -577,6 +583,11 @@ ProcessCopyOptions(ParseState *pstate,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cannot specify NULL in BINARY mode")));
+ if (opts_out->binary && opts_out->default_print)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("cannot specify DEFAULT in BINARY mode")));
+
/* Set defaults for omitted options */
if (!opts_out->delim)
opts_out->delim = opts_out->csv_mode ? "," : "\t";
@@ -612,6 +623,17 @@ ProcessCopyOptions(ParseState *pstate,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("COPY null representation cannot use newline or carriage return")));
+ if (opts_out->default_print)
+ {
+ opts_out->default_print_len = strlen(opts_out->default_print);
+
+ if (strchr(opts_out->default_print, '\r') != NULL ||
+ strchr(opts_out->default_print, '\n') != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("COPY default representation cannot use newline or carriage return")));
+ }
+
/*
* Disallow unsafe delimiter characters in non-CSV mode. We can't allow
* backslash because it would be ambiguous. We can't allow the other
@@ -705,6 +727,35 @@ ProcessCopyOptions(ParseState *pstate,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("CSV quote character must not appear in the NULL specification")));
+
+ if (opts_out->default_print)
+ {
+ if (!is_from)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("COPY DEFAULT only available using COPY FROM")));
+
+ /* Don't allow the delimiter to appear in the default string. */
+ if (strchr(opts_out->default_print, opts_out->delim[0]) != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("COPY delimiter must not appear in the DEFAULT specification")));
+
+ /* Don't allow the CSV quote char to appear in the default string. */
+ if (opts_out->csv_mode &&
+ strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("CSV quote character must not appear in the DEFAULT specification")));
+
+ /* Don't allow the NULL and DEFAULT string to be the same */
+ if (opts_out->null_print_len == opts_out->default_print_len &&
+ strncmp(opts_out->null_print, opts_out->default_print,
+ opts_out->null_print_len) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("NULL specification and DEFAULT specification cannot be the same")));
+ }
}
/*