diff options
| author | Andrew Dunstan | 2023-03-13 14:01:56 +0000 |
|---|---|---|
| committer | Andrew Dunstan | 2023-03-13 14:01:56 +0000 |
| commit | 9f8377f7a27910bf0f35bf5169a8046731948a79 (patch) | |
| tree | e0a19449e4cebb8923dfcd1bba95a1d3363faa32 /contrib | |
| parent | 7b14e20b12cc8358cad9bdd05dd6b7de7f73c431 (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 'contrib')
| -rw-r--r-- | contrib/file_fdw/data/copy_default.csv | 3 | ||||
| -rw-r--r-- | contrib/file_fdw/expected/file_fdw.out | 17 | ||||
| -rw-r--r-- | contrib/file_fdw/file_fdw.c | 20 | ||||
| -rw-r--r-- | contrib/file_fdw/sql/file_fdw.sql | 11 |
4 files changed, 48 insertions, 3 deletions
diff --git a/contrib/file_fdw/data/copy_default.csv b/contrib/file_fdw/data/copy_default.csv new file mode 100644 index 0000000000..5e83a15db4 --- /dev/null +++ b/contrib/file_fdw/data/copy_default.csv @@ -0,0 +1,3 @@ +1,value,2022-07-04 +2,\D,2022-07-03 +3,\D,\D diff --git a/contrib/file_fdw/expected/file_fdw.out b/contrib/file_fdw/expected/file_fdw.out index 36d76ba26c..f5ae29732a 100644 --- a/contrib/file_fdw/expected/file_fdw.out +++ b/contrib/file_fdw/expected/file_fdw.out @@ -424,6 +424,23 @@ SELECT a, c FROM gft1; (2 rows) DROP FOREIGN TABLE gft1; +-- copy default tests +\set filename :abs_srcdir '/data/copy_default.csv' +CREATE FOREIGN TABLE copy_default ( + id integer, + text_value text not null default 'test', + ts_value timestamp without time zone not null default '2022-07-05' +) SERVER file_server +OPTIONS (format 'csv', filename :'filename', default '\D'); +SELECT id, text_value, ts_value FROM copy_default; + id | text_value | ts_value +----+------------+-------------------------- + 1 | value | Mon Jul 04 00:00:00 2022 + 2 | test | Sun Jul 03 00:00:00 2022 + 3 | test | Tue Jul 05 00:00:00 2022 +(3 rows) + +DROP FOREIGN TABLE copy_default; -- privilege tests SET ROLE regress_file_fdw_superuser; SELECT * FROM agg_text ORDER BY a; diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index 2d2b0b6a6b..99b21e8316 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -72,6 +72,7 @@ static const struct FileFdwOption valid_options[] = { {"quote", ForeignTableRelationId}, {"escape", ForeignTableRelationId}, {"null", ForeignTableRelationId}, + {"default", ForeignTableRelationId}, {"encoding", ForeignTableRelationId}, {"force_not_null", AttributeRelationId}, {"force_null", AttributeRelationId}, @@ -712,6 +713,9 @@ static TupleTableSlot * fileIterateForeignScan(ForeignScanState *node) { FileFdwExecutionState *festate = (FileFdwExecutionState *) node->fdw_state; + EState *estate = CreateExecutorState(); + ExprContext *econtext; + MemoryContext oldcontext; TupleTableSlot *slot = node->ss.ss_ScanTupleSlot; bool found; ErrorContextCallback errcallback; @@ -728,15 +732,25 @@ fileIterateForeignScan(ForeignScanState *node) * ExecStoreVirtualTuple. If we don't find another row in the file, we * just skip the last step, leaving the slot empty as required. * - * We can pass ExprContext = NULL because we read all columns from the - * file, so no need to evaluate default expressions. + * We pass ExprContext because there might be a use of the DEFAULT option + * in COPY FROM, so we may need to evaluate default expressions. */ ExecClearTuple(slot); - found = NextCopyFrom(festate->cstate, NULL, + econtext = GetPerTupleExprContext(estate); + + /* + * DEFAULT expressions need to be evaluated in a per-tuple context, so + * switch in case we are doing that. + */ + oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + found = NextCopyFrom(festate->cstate, econtext, slot->tts_values, slot->tts_isnull); if (found) ExecStoreVirtualTuple(slot); + /* Switch back to original memory context */ + MemoryContextSwitchTo(oldcontext); + /* Remove error callback. */ error_context_stack = errcallback.previous; diff --git a/contrib/file_fdw/sql/file_fdw.sql b/contrib/file_fdw/sql/file_fdw.sql index 46670397ca..f0548e14e1 100644 --- a/contrib/file_fdw/sql/file_fdw.sql +++ b/contrib/file_fdw/sql/file_fdw.sql @@ -233,6 +233,17 @@ OPTIONS (format 'csv', filename :'filename', delimiter ','); SELECT a, c FROM gft1; DROP FOREIGN TABLE gft1; +-- copy default tests +\set filename :abs_srcdir '/data/copy_default.csv' +CREATE FOREIGN TABLE copy_default ( + id integer, + text_value text not null default 'test', + ts_value timestamp without time zone not null default '2022-07-05' +) SERVER file_server +OPTIONS (format 'csv', filename :'filename', default '\D'); +SELECT id, text_value, ts_value FROM copy_default; +DROP FOREIGN TABLE copy_default; + -- privilege tests SET ROLE regress_file_fdw_superuser; SELECT * FROM agg_text ORDER BY a; |
