diff options
author | Andres Freund <andres@anarazel.de> | 2015-05-19 21:07:28 +0200 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2015-05-19 23:18:57 +0200 |
commit | 9bc77c45199c7d2e525cd5b1457d5a57f6e9edb0 (patch) | |
tree | 06b8809dd701d4e82663ddb025ad0fb28813a6e0 /src/backend/utils/adt/ruleutils.c | |
parent | 0740cbd7593d871858c352fab29a59cf7fa54b00 (diff) | |
download | postgresql-9bc77c45199c7d2e525cd5b1457d5a57f6e9edb0.tar.gz postgresql-9bc77c45199c7d2e525cd5b1457d5a57f6e9edb0.zip |
Various fixes around ON CONFLICT for rule deparsing.
Neither the deparsing of the new alias for INSERT's target table, nor of
the inference clause was supported. Also fixup a typo in an error
message.
Add regression tests to test those code paths.
Author: Peter Geoghegan
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 79 |
1 files changed, 77 insertions, 2 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 0a77400a801..8cdef086a0b 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5392,6 +5392,10 @@ get_insert_query_def(Query *query, deparse_context *context) } appendStringInfo(buf, "INSERT INTO %s ", generate_relation_name(rte->relid, NIL)); + /* INSERT requires AS keyword for target alias */ + if (rte->alias != NULL) + appendStringInfo(buf, "AS %s ", + quote_identifier(rte->alias->aliasname)); /* * Add the insert-column-names list. To handle indirection properly, we @@ -5479,13 +5483,38 @@ get_insert_query_def(Query *query, deparse_context *context) { OnConflictExpr *confl = query->onConflict; + appendStringInfo(buf, " ON CONFLICT"); + + if (confl->arbiterElems) + { + /* Add the single-VALUES expression list */ + appendStringInfoChar(buf, '('); + get_rule_expr((Node *) confl->arbiterElems, context, false); + appendStringInfoChar(buf, ')'); + + /* Add a WHERE clause (for partial indexes) if given */ + if (confl->arbiterWhere != NULL) + { + appendContextKeyword(context, " WHERE ", + -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); + get_rule_expr(confl->arbiterWhere, context, false); + } + } + else + { + char *constraint = get_constraint_name(confl->constraint); + + appendStringInfo(buf, " ON CONSTRAINT %s", + quote_qualified_identifier(NULL, constraint)); + } + if (confl->action == ONCONFLICT_NOTHING) { - appendStringInfoString(buf, " ON CONFLICT DO NOTHING"); + appendStringInfoString(buf, " DO NOTHING"); } else { - appendStringInfoString(buf, " ON CONFLICT DO UPDATE SET "); + appendStringInfoString(buf, " DO UPDATE SET "); /* Deparse targetlist */ get_update_query_targetlist_def(query, confl->onConflictSet, context, rte); @@ -7886,6 +7915,52 @@ get_rule_expr(Node *node, deparse_context *context, } break; + case T_InferenceElem: + { + InferenceElem *iexpr = (InferenceElem *) node; + bool varprefix = context->varprefix; + bool need_parens; + + /* + * InferenceElem can only refer to target relation, so a + * prefix is never useful. + */ + context->varprefix = false; + + /* + * Parenthesize the element unless it's a simple Var or a bare + * function call. Follows pg_get_indexdef_worker(). + */ + need_parens = !IsA(iexpr->expr, Var); + if (IsA(iexpr->expr, FuncExpr) && + ((FuncExpr *) iexpr->expr)->funcformat == + COERCE_EXPLICIT_CALL) + need_parens = false; + + if (need_parens) + appendStringInfoChar(buf, '('); + get_rule_expr((Node *) iexpr->expr, + context, false); + if (need_parens) + appendStringInfoChar(buf, ')'); + + context->varprefix = varprefix; + + if (iexpr->infercollid) + appendStringInfo(buf, " COLLATE %s", + generate_collation_name(iexpr->infercollid)); + + /* Add the operator class name, if not default */ + if (iexpr->inferopclass) + { + Oid inferopclass = iexpr->inferopclass; + Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass); + + get_opclass_name(inferopclass, inferopcinputtype, buf); + } + } + break; + case T_List: { char *sep; |