diff options
Diffstat (limited to 'contrib/postgres_fdw/deparse.c')
-rw-r--r-- | contrib/postgres_fdw/deparse.c | 101 |
1 files changed, 69 insertions, 32 deletions
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 7fc1f797ab2..f005e0f26fb 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -11,6 +11,9 @@ * One saving grace is that we only need deparse logic for node types that * we consider safe to send. * + * We assume that the remote session's search_path is exactly "pg_catalog", + * and thus we need schema-qualify all and only names outside pg_catalog. + * * Portions Copyright (c) 2012-2013, PostgreSQL Global Development Group * * IDENTIFICATION @@ -25,6 +28,7 @@ #include "access/htup_details.h" #include "access/sysattr.h" #include "access/transam.h" +#include "catalog/pg_namespace.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" @@ -73,6 +77,7 @@ static void deparseParam(StringInfo buf, Param *node, PlannerInfo *root); static void deparseArrayRef(StringInfo buf, ArrayRef *node, PlannerInfo *root); static void deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root); static void deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root); +static void deparseOperatorName(StringInfo buf, Form_pg_operator opform); static void deparseDistinctExpr(StringInfo buf, DistinctExpr *node, PlannerInfo *root); static void deparseScalarArrayOpExpr(StringInfo buf, ScalarArrayOpExpr *node, @@ -321,6 +326,18 @@ foreign_expr_walker(Node *node, foreign_expr_cxt *context) /* * Return true if given object is one of PostgreSQL's built-in objects. * + * We use FirstBootstrapObjectId as the cutoff, so that we only consider + * objects with hand-assigned OIDs to be "built in", not for instance any + * function or type defined in the information_schema. + * + * Our constraints for dealing with types are tighter than they are for + * functions or operators: we want to accept only types that are in pg_catalog + * (else format_type might incorrectly fail to schema-qualify their names), + * and we want to be sure that the remote server will use the same OID as + * we do (since we must transmit a numeric type OID when passing a value of + * the type as a query parameter). Both of these are reasons to reject + * objects created post-bootstrap. + * * XXX there is a problem with this, which is that the set of built-in * objects expands over time. Something that is built-in to us might not * be known to the remote server, if it's of an older version. But keeping @@ -329,7 +346,7 @@ foreign_expr_walker(Node *node, foreign_expr_cxt *context) static bool is_builtin(Oid oid) { - return (oid < FirstNormalObjectId); + return (oid < FirstBootstrapObjectId); } @@ -563,6 +580,10 @@ deparseRelation(StringInfo buf, Oid relid) relname = defGetString(def); } + /* + * Note: we could skip printing the schema name if it's pg_catalog, + * but that doesn't seem worth the trouble. + */ if (nspname == NULL) nspname = get_namespace_name(get_rel_namespace(relid)); if (relname == NULL) @@ -832,9 +853,6 @@ deparseArrayRef(StringInfo buf, ArrayRef *node, PlannerInfo *root) * Here not only explicit function calls and explicit casts but also implicit * casts are deparsed to avoid problems caused by different cast settings * between local and remote. - * - * Function name is always qualified by schema name to avoid problems caused - * by different setting of search_path on remote side. */ static void deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root) @@ -842,7 +860,6 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root) HeapTuple proctup; Form_pg_proc procform; const char *proname; - const char *schemaname; bool use_variadic; bool first; ListCell *arg; @@ -851,7 +868,6 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root) if (!HeapTupleIsValid(proctup)) elog(ERROR, "cache lookup failed for function %u", node->funcid); procform = (Form_pg_proc) GETSTRUCT(proctup); - proname = NameStr(procform->proname); /* Check if need to print VARIADIC (cf. ruleutils.c) */ if (OidIsValid(procform->provariadic)) @@ -864,11 +880,18 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root) else use_variadic = false; + /* Print schema name only if it's not pg_catalog */ + if (procform->pronamespace != PG_CATALOG_NAMESPACE) + { + const char *schemaname; + + schemaname = get_namespace_name(procform->pronamespace); + appendStringInfo(buf, "%s.", quote_identifier(schemaname)); + } + /* Deparse the function name ... */ - schemaname = get_namespace_name(procform->pronamespace); - appendStringInfo(buf, "%s.%s(", - quote_identifier(schemaname), - quote_identifier(proname)); + proname = NameStr(procform->proname); + appendStringInfo(buf, "%s(", quote_identifier(proname)); /* ... and all the arguments */ first = true; foreach(arg, node->args) @@ -887,16 +910,13 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root) /* * Deparse given operator expression into buf. To avoid problems around - * priority of operations, we always parenthesize the arguments. Also we use - * OPERATOR(schema.operator) notation to determine remote operator exactly. + * priority of operations, we always parenthesize the arguments. */ static void deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root) { HeapTuple tuple; Form_pg_operator form; - const char *opnspname; - char *opname; char oprkind; ListCell *arg; @@ -905,10 +925,6 @@ deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root) if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for operator %u", node->opno); form = (Form_pg_operator) GETSTRUCT(tuple); - - opnspname = quote_identifier(get_namespace_name(form->oprnamespace)); - /* opname is not a SQL identifier, so we don't need to quote it. */ - opname = NameStr(form->oprname); oprkind = form->oprkind; /* Sanity check. */ @@ -927,8 +943,8 @@ deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root) appendStringInfoChar(buf, ' '); } - /* Deparse fully qualified operator name. */ - appendStringInfo(buf, "OPERATOR(%s.%s)", opnspname, opname); + /* Deparse operator name. */ + deparseOperatorName(buf, form); /* Deparse right operand. */ if (oprkind == 'l' || oprkind == 'b') @@ -944,6 +960,34 @@ deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root) } /* + * Print the name of an operator. + */ +static void +deparseOperatorName(StringInfo buf, Form_pg_operator opform) +{ + char *opname; + + /* opname is not a SQL identifier, so we should not quote it. */ + opname = NameStr(opform->oprname); + + /* Print schema name only if it's not pg_catalog */ + if (opform->oprnamespace != PG_CATALOG_NAMESPACE) + { + const char *opnspname; + + opnspname = get_namespace_name(opform->oprnamespace); + /* Print fully qualified operator name. */ + appendStringInfo(buf, "OPERATOR(%s.%s)", + quote_identifier(opnspname), opname); + } + else + { + /* Just print operator name. */ + appendStringInfo(buf, "%s", opname); + } +} + +/* * Deparse IS DISTINCT FROM. */ static void @@ -960,9 +1004,7 @@ deparseDistinctExpr(StringInfo buf, DistinctExpr *node, PlannerInfo *root) /* * Deparse given ScalarArrayOpExpr expression into buf. To avoid problems - * around priority of operations, we always parenthesize the arguments. Also - * we use OPERATOR(schema.operator) notation to determine remote operator - * exactly. + * around priority of operations, we always parenthesize the arguments. */ static void deparseScalarArrayOpExpr(StringInfo buf, @@ -971,8 +1013,6 @@ deparseScalarArrayOpExpr(StringInfo buf, { HeapTuple tuple; Form_pg_operator form; - const char *opnspname; - char *opname; Expr *arg1; Expr *arg2; @@ -982,10 +1022,6 @@ deparseScalarArrayOpExpr(StringInfo buf, elog(ERROR, "cache lookup failed for operator %u", node->opno); form = (Form_pg_operator) GETSTRUCT(tuple); - opnspname = quote_identifier(get_namespace_name(form->oprnamespace)); - /* opname is not a SQL identifier, so we don't need to quote it. */ - opname = NameStr(form->oprname); - /* Sanity check. */ Assert(list_length(node->args) == 2); @@ -995,10 +1031,11 @@ deparseScalarArrayOpExpr(StringInfo buf, /* Deparse left operand. */ arg1 = linitial(node->args); deparseExpr(buf, arg1, root); + appendStringInfoChar(buf, ' '); - /* Deparse fully qualified operator name plus decoration. */ - appendStringInfo(buf, " OPERATOR(%s.%s) %s (", - opnspname, opname, node->useOr ? "ANY" : "ALL"); + /* Deparse operator name plus decoration. */ + deparseOperatorName(buf, form); + appendStringInfo(buf, " %s (", node->useOr ? "ANY" : "ALL"); /* Deparse right operand. */ arg2 = lsecond(node->args); |