mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Generated columns
This is an SQL-standard feature that allows creating columns that are computed from expressions rather than assigned, similar to a view or materialized view but on a column basis. This implements one kind of generated column: stored (computed on write). Another kind, virtual (computed on read), is planned for the future, and some room is left for it. Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/b151f851-4019-bdb1-699e-ebab07d2f40a@2ndquadrant.com
This commit is contained in:
@ -32,6 +32,7 @@
|
||||
#include "commands/trigger.h"
|
||||
#include "executor/execPartition.h"
|
||||
#include "executor/executor.h"
|
||||
#include "executor/nodeModifyTable.h"
|
||||
#include "executor/tuptable.h"
|
||||
#include "foreign/fdwapi.h"
|
||||
#include "libpq/libpq.h"
|
||||
@ -2922,6 +2923,21 @@ CopyFrom(CopyState cstate)
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Compute stored generated columns
|
||||
*
|
||||
* Switch memory context so that the new tuple is in the same
|
||||
* context as the old one.
|
||||
*/
|
||||
if (resultRelInfo->ri_RelationDesc->rd_att->constr &&
|
||||
resultRelInfo->ri_RelationDesc->rd_att->constr->has_generated_stored)
|
||||
{
|
||||
ExecComputeStoredGenerated(estate, slot);
|
||||
MemoryContextSwitchTo(batchcontext);
|
||||
tuple = ExecCopySlotHeapTuple(slot);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target is a plain table, check the constraints of
|
||||
* the tuple.
|
||||
@ -3271,7 +3287,7 @@ BeginCopyFrom(ParseState *pstate,
|
||||
fmgr_info(in_func_oid, &in_functions[attnum - 1]);
|
||||
|
||||
/* Get default info if needed */
|
||||
if (!list_member_int(cstate->attnumlist, attnum))
|
||||
if (!list_member_int(cstate->attnumlist, attnum) && !att->attgenerated)
|
||||
{
|
||||
/* attribute is NOT to be copied from input */
|
||||
/* use default value if one exists */
|
||||
@ -4876,6 +4892,11 @@ CopyAttributeOutCSV(CopyState cstate, char *string,
|
||||
* or NIL if there was none (in which case we want all the non-dropped
|
||||
* columns).
|
||||
*
|
||||
* We don't include generated columns in the generated full list and we don't
|
||||
* allow them to be specified explicitly. They don't make sense for COPY
|
||||
* FROM, but we could possibly allow them for COPY TO. But this way it's at
|
||||
* least ensured that whatever we copy out can be copied back in.
|
||||
*
|
||||
* rel can be NULL ... it's only used for error reports.
|
||||
*/
|
||||
static List *
|
||||
@ -4893,6 +4914,8 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
|
||||
{
|
||||
if (TupleDescAttr(tupDesc, i)->attisdropped)
|
||||
continue;
|
||||
if (TupleDescAttr(tupDesc, i)->attgenerated)
|
||||
continue;
|
||||
attnums = lappend_int(attnums, i + 1);
|
||||
}
|
||||
}
|
||||
@ -4917,6 +4940,12 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
|
||||
continue;
|
||||
if (namestrcmp(&(att->attname), name) == 0)
|
||||
{
|
||||
if (att->attgenerated)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("column \"%s\" is a generated column",
|
||||
name),
|
||||
errdetail("Generated columns cannot be used in COPY.")));
|
||||
attnum = att->attnum;
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user