diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2016-11-10 14:13:43 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2016-11-10 14:13:43 -0500 |
commit | 279c439c7fbc1bcb52173d92dd3b1fbe63e497ab (patch) | |
tree | cf45b8dbbbbbb477793c0fd0939de6cc3502327b /src/backend/commands/copy.c | |
parent | e1b449bea909fa70211841d508cfaf91d18a6abb (diff) | |
download | postgresql-279c439c7fbc1bcb52173d92dd3b1fbe63e497ab.tar.gz postgresql-279c439c7fbc1bcb52173d92dd3b1fbe63e497ab.zip |
Support "COPY view FROM" for views with INSTEAD OF INSERT triggers.
We just pass the data to the INSTEAD trigger.
Haribabu Kommi, reviewed by Dilip Kumar
Patch: <CAJrrPGcSQkrNkO+4PhLm4B8UQQQmU9YVUuqmtgM=pmzMfxWaWQ@mail.gmail.com>
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r-- | src/backend/commands/copy.c | 104 |
1 files changed, 62 insertions, 42 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index b4140eb68a7..3c819062328 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -864,8 +864,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed) * statement. * * In the case that columns are specified in the attribute list, - * create a ColumnRef and ResTarget for each column and add them to - * the target list for the resulting SELECT statement. + * create a ColumnRef and ResTarget for each column and add them + * to the target list for the resulting SELECT statement. */ if (!stmt->attlist) { @@ -2269,13 +2269,21 @@ CopyFrom(CopyState cstate) Assert(cstate->rel); - if (cstate->rel->rd_rel->relkind != RELKIND_RELATION) + /* + * The target must be a plain relation or have an INSTEAD OF INSERT row + * trigger. (Currently, such triggers are only allowed on views, so we + * only hint about them in the view case.) + */ + if (cstate->rel->rd_rel->relkind != RELKIND_RELATION && + !(cstate->rel->trigdesc && + cstate->rel->trigdesc->trig_insert_instead_row)) { if (cstate->rel->rd_rel->relkind == RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot copy to view \"%s\"", - RelationGetRelationName(cstate->rel)))); + RelationGetRelationName(cstate->rel)), + errhint("To enable copying to a view, provide an INSTEAD OF INSERT trigger."))); else if (cstate->rel->rd_rel->relkind == RELKIND_MATVIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -2496,52 +2504,64 @@ CopyFrom(CopyState cstate) if (!skip_tuple) { - /* Check the constraints of the tuple */ - if (cstate->rel->rd_att->constr) - ExecConstraints(resultRelInfo, slot, estate); - - if (useHeapMultiInsert) + if (resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_insert_instead_row) { - /* Add this tuple to the tuple buffer */ - if (nBufferedTuples == 0) - firstBufferedLineNo = cstate->cur_lineno; - bufferedTuples[nBufferedTuples++] = tuple; - bufferedTuplesSize += tuple->t_len; - - /* - * If the buffer filled up, flush it. Also flush if the total - * size of all the tuples in the buffer becomes large, to - * avoid using large amounts of memory for the buffers when - * the tuples are exceptionally wide. - */ - if (nBufferedTuples == MAX_BUFFERED_TUPLES || - bufferedTuplesSize > 65535) - { - CopyFromInsertBatch(cstate, estate, mycid, hi_options, - resultRelInfo, myslot, bistate, - nBufferedTuples, bufferedTuples, - firstBufferedLineNo); - nBufferedTuples = 0; - bufferedTuplesSize = 0; - } + /* Pass the data to the INSTEAD ROW INSERT trigger */ + ExecIRInsertTriggers(estate, resultRelInfo, slot); } else { - List *recheckIndexes = NIL; + /* Check the constraints of the tuple */ + if (cstate->rel->rd_att->constr) + ExecConstraints(resultRelInfo, slot, estate); + + if (useHeapMultiInsert) + { + /* Add this tuple to the tuple buffer */ + if (nBufferedTuples == 0) + firstBufferedLineNo = cstate->cur_lineno; + bufferedTuples[nBufferedTuples++] = tuple; + bufferedTuplesSize += tuple->t_len; + + /* + * If the buffer filled up, flush it. Also flush if the + * total size of all the tuples in the buffer becomes + * large, to avoid using large amounts of memory for the + * buffer when the tuples are exceptionally wide. + */ + if (nBufferedTuples == MAX_BUFFERED_TUPLES || + bufferedTuplesSize > 65535) + { + CopyFromInsertBatch(cstate, estate, mycid, hi_options, + resultRelInfo, myslot, bistate, + nBufferedTuples, bufferedTuples, + firstBufferedLineNo); + nBufferedTuples = 0; + bufferedTuplesSize = 0; + } + } + else + { + List *recheckIndexes = NIL; - /* OK, store the tuple and create index entries for it */ - heap_insert(cstate->rel, tuple, mycid, hi_options, bistate); + /* OK, store the tuple and create index entries for it */ + heap_insert(cstate->rel, tuple, mycid, hi_options, bistate); - if (resultRelInfo->ri_NumIndices > 0) - recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), - estate, false, NULL, - NIL); + if (resultRelInfo->ri_NumIndices > 0) + recheckIndexes = ExecInsertIndexTuples(slot, + &(tuple->t_self), + estate, + false, + NULL, + NIL); - /* AFTER ROW INSERT Triggers */ - ExecARInsertTriggers(estate, resultRelInfo, tuple, - recheckIndexes); + /* AFTER ROW INSERT Triggers */ + ExecARInsertTriggers(estate, resultRelInfo, tuple, + recheckIndexes); - list_free(recheckIndexes); + list_free(recheckIndexes); + } } /* |