mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
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
This commit is contained in:
3
contrib/file_fdw/data/copy_default.csv
Normal file
3
contrib/file_fdw/data/copy_default.csv
Normal file
@ -0,0 +1,3 @@
|
||||
1,value,2022-07-04
|
||||
2,\D,2022-07-03
|
||||
3,\D,\D
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user