diff options
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 69 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 80 |
2 files changed, 87 insertions, 62 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 8faae1d0693..4d7fee0ecb9 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -203,7 +203,6 @@ static void ri_GenerateQual(StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype); -static void ri_add_cast_to(StringInfo buf, Oid typid); static void ri_GenerateQualCollation(StringInfo buf, Oid collation); static int ri_NullCheck(HeapTuple tup, const RI_ConstraintInfo *riinfo, bool rel_is_pk); @@ -2134,13 +2133,10 @@ quoteRelationName(char *buffer, Relation rel) /* * ri_GenerateQual --- generate a WHERE clause equating two variables * - * The idea is to append " sep leftop op rightop" to buf. The complexity - * comes from needing to be sure that the parser will select the desired - * operator. We always name the operator using OPERATOR(schema.op) syntax - * (readability isn't a big priority here), so as to avoid search-path - * uncertainties. We have to emit casts too, if either input isn't already - * the input type of the operator; else we are at the mercy of the parser's - * heuristics for ambiguous-operator resolution. + * This basically appends " sep leftop op rightop" to buf, adding casts + * and schema qualification as needed to ensure that the parser will select + * the operator we specify. leftop and rightop should be parenthesized + * if they aren't variables or parameters. */ static void ri_GenerateQual(StringInfo buf, @@ -2149,60 +2145,9 @@ ri_GenerateQual(StringInfo buf, Oid opoid, const char *rightop, Oid rightoptype) { - HeapTuple opertup; - Form_pg_operator operform; - char *oprname; - char *nspname; - - opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid)); - if (!HeapTupleIsValid(opertup)) - elog(ERROR, "cache lookup failed for operator %u", opoid); - operform = (Form_pg_operator) GETSTRUCT(opertup); - Assert(operform->oprkind == 'b'); - oprname = NameStr(operform->oprname); - - nspname = get_namespace_name(operform->oprnamespace); - - appendStringInfo(buf, " %s %s", sep, leftop); - if (leftoptype != operform->oprleft) - ri_add_cast_to(buf, operform->oprleft); - appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname)); - appendStringInfoString(buf, oprname); - appendStringInfo(buf, ") %s", rightop); - if (rightoptype != operform->oprright) - ri_add_cast_to(buf, operform->oprright); - - ReleaseSysCache(opertup); -} - -/* - * Add a cast specification to buf. We spell out the type name the hard way, - * intentionally not using format_type_be(). This is to avoid corner cases - * for CHARACTER, BIT, and perhaps other types, where specifying the type - * using SQL-standard syntax results in undesirable data truncation. By - * doing it this way we can be certain that the cast will have default (-1) - * target typmod. - */ -static void -ri_add_cast_to(StringInfo buf, Oid typid) -{ - HeapTuple typetup; - Form_pg_type typform; - char *typname; - char *nspname; - - typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); - if (!HeapTupleIsValid(typetup)) - elog(ERROR, "cache lookup failed for type %u", typid); - typform = (Form_pg_type) GETSTRUCT(typetup); - - typname = NameStr(typform->typname); - nspname = get_namespace_name(typform->typnamespace); - - appendStringInfo(buf, "::%s.%s", - quote_identifier(nspname), quote_identifier(typname)); - - ReleaseSysCache(typetup); + appendStringInfo(buf, " %s ", sep); + generate_operator_clause(buf, leftop, leftoptype, opoid, + rightop, rightoptype); } /* diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index b58ee3c3876..2cd54ec33fe 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -462,6 +462,7 @@ static char *generate_function_name(Oid funcid, int nargs, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); +static void add_cast_to(StringInfo buf, Oid typid); static char *generate_qualified_type_name(Oid typid); static text *string_to_text(char *str); static char *flatten_reloptions(Oid relid); @@ -10850,6 +10851,85 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2) } /* + * generate_operator_clause --- generate a binary-operator WHERE clause + * + * This is used for internally-generated-and-executed SQL queries, where + * precision is essential and readability is secondary. The basic + * requirement is to append "leftop op rightop" to buf, where leftop and + * rightop are given as strings and are assumed to yield types leftoptype + * and rightoptype; the operator is identified by OID. The complexity + * comes from needing to be sure that the parser will select the desired + * operator when the query is parsed. We always name the operator using + * OPERATOR(schema.op) syntax, so as to avoid search-path uncertainties. + * We have to emit casts too, if either input isn't already the input type + * of the operator; else we are at the mercy of the parser's heuristics for + * ambiguous-operator resolution. The caller must ensure that leftop and + * rightop are suitable arguments for a cast operation; it's best to insert + * parentheses if they aren't just variables or parameters. + */ +void +generate_operator_clause(StringInfo buf, + const char *leftop, Oid leftoptype, + Oid opoid, + const char *rightop, Oid rightoptype) +{ + HeapTuple opertup; + Form_pg_operator operform; + char *oprname; + char *nspname; + + opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid)); + if (!HeapTupleIsValid(opertup)) + elog(ERROR, "cache lookup failed for operator %u", opoid); + operform = (Form_pg_operator) GETSTRUCT(opertup); + Assert(operform->oprkind == 'b'); + oprname = NameStr(operform->oprname); + + nspname = get_namespace_name(operform->oprnamespace); + + appendStringInfoString(buf, leftop); + if (leftoptype != operform->oprleft) + add_cast_to(buf, operform->oprleft); + appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname)); + appendStringInfoString(buf, oprname); + appendStringInfo(buf, ") %s", rightop); + if (rightoptype != operform->oprright) + add_cast_to(buf, operform->oprright); + + ReleaseSysCache(opertup); +} + +/* + * Add a cast specification to buf. We spell out the type name the hard way, + * intentionally not using format_type_be(). This is to avoid corner cases + * for CHARACTER, BIT, and perhaps other types, where specifying the type + * using SQL-standard syntax results in undesirable data truncation. By + * doing it this way we can be certain that the cast will have default (-1) + * target typmod. + */ +static void +add_cast_to(StringInfo buf, Oid typid) +{ + HeapTuple typetup; + Form_pg_type typform; + char *typname; + char *nspname; + + typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(typetup)) + elog(ERROR, "cache lookup failed for type %u", typid); + typform = (Form_pg_type) GETSTRUCT(typetup); + + typname = NameStr(typform->typname); + nspname = get_namespace_name(typform->typnamespace); + + appendStringInfo(buf, "::%s.%s", + quote_identifier(nspname), quote_identifier(typname)); + + ReleaseSysCache(typetup); +} + +/* * generate_qualified_type_name * Compute the name to display for a type specified by OID * |