aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteHandler.c
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2017-04-06 08:33:16 -0400
committerPeter Eisentraut <peter_e@gmx.net>2017-04-06 08:41:37 -0400
commit3217327053638085d24dd4d276e7c1f7ac2c4c6b (patch)
tree513d1264a2935b05e28b0d8322d73a0411a3d02f /src/backend/rewrite/rewriteHandler.c
parent6bad580d9e678a0b604883e14d8401d469b06566 (diff)
downloadpostgresql-3217327053638085d24dd4d276e7c1f7ac2c4c6b.tar.gz
postgresql-3217327053638085d24dd4d276e7c1f7ac2c4c6b.zip
Identity columns
This is the SQL standard-conforming variant of PostgreSQL's serial columns. It fixes a few usability issues that serial columns have: - CREATE TABLE / LIKE copies default but refers to same sequence - cannot add/drop serialness with ALTER TABLE - dropping default does not drop sequence - need to grant separate privileges to sequence - other slight weirdnesses because serial is some kind of special macro Reviewed-by: Vitaly Burovoy <vitaly.burovoy@gmail.com>
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r--src/backend/rewrite/rewriteHandler.c56
1 files changed, 52 insertions, 4 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 424be0c7684..cb860ec4e51 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -21,6 +21,7 @@
#include "postgres.h"
#include "access/sysattr.h"
+#include "catalog/dependency.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
@@ -61,6 +62,7 @@ static Query *rewriteRuleAction(Query *parsetree,
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static List *rewriteTargetListIU(List *targetList,
CmdType commandType,
+ OverridingKind override,
Relation target_relation,
int result_rti,
List **attrno_list);
@@ -709,6 +711,7 @@ adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
static List *
rewriteTargetListIU(List *targetList,
CmdType commandType,
+ OverridingKind override,
Relation target_relation,
int result_rti,
List **attrno_list)
@@ -789,6 +792,7 @@ rewriteTargetListIU(List *targetList,
for (attrno = 1; attrno <= numattrs; attrno++)
{
TargetEntry *new_tle = new_tles[attrno - 1];
+ bool apply_default;
att_tup = target_relation->rd_att->attrs[attrno - 1];
@@ -801,12 +805,51 @@ rewriteTargetListIU(List *targetList,
* it's an INSERT and there's no tlist entry for the column, or the
* tlist entry is a DEFAULT placeholder node.
*/
- if ((new_tle == NULL && commandType == CMD_INSERT) ||
- (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)))
+ apply_default = ((new_tle == NULL && commandType == CMD_INSERT) ||
+ (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)));
+
+ if (commandType == CMD_INSERT)
+ {
+ if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && !apply_default)
+ {
+ if (override != OVERRIDING_SYSTEM_VALUE)
+ ereport(ERROR,
+ (errcode(ERRCODE_GENERATED_ALWAYS),
+ errmsg("cannot insert into column \"%s\"", NameStr(att_tup->attname)),
+ errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
+ NameStr(att_tup->attname)),
+ errhint("Use OVERRIDING SYSTEM VALUE to override.")));
+ }
+
+ if (att_tup->attidentity == ATTRIBUTE_IDENTITY_BY_DEFAULT && override == OVERRIDING_USER_VALUE)
+ apply_default = true;
+ }
+
+ if (commandType == CMD_UPDATE)
+ {
+ if (att_tup->attidentity == ATTRIBUTE_IDENTITY_ALWAYS && !apply_default)
+ ereport(ERROR,
+ (errcode(ERRCODE_GENERATED_ALWAYS),
+ errmsg("column \"%s\" can only be updated to DEFAULT", NameStr(att_tup->attname)),
+ errdetail("Column \"%s\" is an identity column defined as GENERATED ALWAYS.",
+ NameStr(att_tup->attname))));
+ }
+
+ if (apply_default)
{
Node *new_expr;
- new_expr = build_column_default(target_relation, attrno);
+ if (att_tup->attidentity)
+ {
+ NextValueExpr *nve = makeNode(NextValueExpr);
+
+ nve->seqid = getOwnedSequence(RelationGetRelid(target_relation), attrno);
+ nve->typeId = att_tup->atttypid;
+
+ new_expr = (Node *) nve;
+ }
+ else
+ new_expr = build_column_default(target_relation, attrno);
/*
* If there is no default (ie, default is effectively NULL), we
@@ -3232,6 +3275,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
/* Process the main targetlist ... */
parsetree->targetList = rewriteTargetListIU(parsetree->targetList,
parsetree->commandType,
+ parsetree->override,
rt_entry_relation,
parsetree->resultRelation,
&attrnos);
@@ -3244,6 +3288,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
parsetree->targetList =
rewriteTargetListIU(parsetree->targetList,
parsetree->commandType,
+ parsetree->override,
rt_entry_relation,
parsetree->resultRelation, NULL);
}
@@ -3254,6 +3299,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
parsetree->onConflict->onConflictSet =
rewriteTargetListIU(parsetree->onConflict->onConflictSet,
CMD_UPDATE,
+ parsetree->override,
rt_entry_relation,
parsetree->resultRelation,
NULL);
@@ -3263,7 +3309,9 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
{
parsetree->targetList =
rewriteTargetListIU(parsetree->targetList,
- parsetree->commandType, rt_entry_relation,
+ parsetree->commandType,
+ parsetree->override,
+ rt_entry_relation,
parsetree->resultRelation, NULL);
rewriteTargetListUD(parsetree, rt_entry, rt_entry_relation);
}