1111 * One saving grace is that we only need deparse logic for node types that
1212 * we consider safe to send.
1313 *
14+ * We assume that the remote session's search_path is exactly "pg_catalog",
15+ * and thus we need schema-qualify all and only names outside pg_catalog.
16+ *
1417 * Portions Copyright (c) 2012-2013, PostgreSQL Global Development Group
1518 *
1619 * IDENTIFICATION
2528#include "access/htup_details.h"
2629#include "access/sysattr.h"
2730#include "access/transam.h"
31+ #include "catalog/pg_namespace.h"
2832#include "catalog/pg_operator.h"
2933#include "catalog/pg_proc.h"
3034#include "catalog/pg_type.h"
@@ -73,6 +77,7 @@ static void deparseParam(StringInfo buf, Param *node, PlannerInfo *root);
7377static void deparseArrayRef (StringInfo buf , ArrayRef * node , PlannerInfo * root );
7478static void deparseFuncExpr (StringInfo buf , FuncExpr * node , PlannerInfo * root );
7579static void deparseOpExpr (StringInfo buf , OpExpr * node , PlannerInfo * root );
80+ static void deparseOperatorName (StringInfo buf , Form_pg_operator opform );
7681static void deparseDistinctExpr (StringInfo buf , DistinctExpr * node ,
7782 PlannerInfo * root );
7883static void deparseScalarArrayOpExpr (StringInfo buf , ScalarArrayOpExpr * node ,
@@ -321,6 +326,18 @@ foreign_expr_walker(Node *node, foreign_expr_cxt *context)
321326/*
322327 * Return true if given object is one of PostgreSQL's built-in objects.
323328 *
329+ * We use FirstBootstrapObjectId as the cutoff, so that we only consider
330+ * objects with hand-assigned OIDs to be "built in", not for instance any
331+ * function or type defined in the information_schema.
332+ *
333+ * Our constraints for dealing with types are tighter than they are for
334+ * functions or operators: we want to accept only types that are in pg_catalog
335+ * (else format_type might incorrectly fail to schema-qualify their names),
336+ * and we want to be sure that the remote server will use the same OID as
337+ * we do (since we must transmit a numeric type OID when passing a value of
338+ * the type as a query parameter). Both of these are reasons to reject
339+ * objects created post-bootstrap.
340+ *
324341 * XXX there is a problem with this, which is that the set of built-in
325342 * objects expands over time. Something that is built-in to us might not
326343 * 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)
329346static bool
330347is_builtin (Oid oid )
331348{
332- return (oid < FirstNormalObjectId );
349+ return (oid < FirstBootstrapObjectId );
333350}
334351
335352
@@ -563,6 +580,10 @@ deparseRelation(StringInfo buf, Oid relid)
563580 relname = defGetString (def );
564581 }
565582
583+ /*
584+ * Note: we could skip printing the schema name if it's pg_catalog,
585+ * but that doesn't seem worth the trouble.
586+ */
566587 if (nspname == NULL )
567588 nspname = get_namespace_name (get_rel_namespace (relid ));
568589 if (relname == NULL )
@@ -832,17 +853,13 @@ deparseArrayRef(StringInfo buf, ArrayRef *node, PlannerInfo *root)
832853 * Here not only explicit function calls and explicit casts but also implicit
833854 * casts are deparsed to avoid problems caused by different cast settings
834855 * between local and remote.
835- *
836- * Function name is always qualified by schema name to avoid problems caused
837- * by different setting of search_path on remote side.
838856 */
839857static void
840858deparseFuncExpr (StringInfo buf , FuncExpr * node , PlannerInfo * root )
841859{
842860 HeapTuple proctup ;
843861 Form_pg_proc procform ;
844862 const char * proname ;
845- const char * schemaname ;
846863 bool use_variadic ;
847864 bool first ;
848865 ListCell * arg ;
@@ -851,7 +868,6 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root)
851868 if (!HeapTupleIsValid (proctup ))
852869 elog (ERROR , "cache lookup failed for function %u" , node -> funcid );
853870 procform = (Form_pg_proc ) GETSTRUCT (proctup );
854- proname = NameStr (procform -> proname );
855871
856872 /* Check if need to print VARIADIC (cf. ruleutils.c) */
857873 if (OidIsValid (procform -> provariadic ))
@@ -864,11 +880,18 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root)
864880 else
865881 use_variadic = false;
866882
883+ /* Print schema name only if it's not pg_catalog */
884+ if (procform -> pronamespace != PG_CATALOG_NAMESPACE )
885+ {
886+ const char * schemaname ;
887+
888+ schemaname = get_namespace_name (procform -> pronamespace );
889+ appendStringInfo (buf , "%s." , quote_identifier (schemaname ));
890+ }
891+
867892 /* Deparse the function name ... */
868- schemaname = get_namespace_name (procform -> pronamespace );
869- appendStringInfo (buf , "%s.%s(" ,
870- quote_identifier (schemaname ),
871- quote_identifier (proname ));
893+ proname = NameStr (procform -> proname );
894+ appendStringInfo (buf , "%s(" , quote_identifier (proname ));
872895 /* ... and all the arguments */
873896 first = true;
874897 foreach (arg , node -> args )
@@ -887,16 +910,13 @@ deparseFuncExpr(StringInfo buf, FuncExpr *node, PlannerInfo *root)
887910
888911/*
889912 * Deparse given operator expression into buf. To avoid problems around
890- * priority of operations, we always parenthesize the arguments. Also we use
891- * OPERATOR(schema.operator) notation to determine remote operator exactly.
913+ * priority of operations, we always parenthesize the arguments.
892914 */
893915static void
894916deparseOpExpr (StringInfo buf , OpExpr * node , PlannerInfo * root )
895917{
896918 HeapTuple tuple ;
897919 Form_pg_operator form ;
898- const char * opnspname ;
899- char * opname ;
900920 char oprkind ;
901921 ListCell * arg ;
902922
@@ -905,10 +925,6 @@ deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root)
905925 if (!HeapTupleIsValid (tuple ))
906926 elog (ERROR , "cache lookup failed for operator %u" , node -> opno );
907927 form = (Form_pg_operator ) GETSTRUCT (tuple );
908-
909- opnspname = quote_identifier (get_namespace_name (form -> oprnamespace ));
910- /* opname is not a SQL identifier, so we don't need to quote it. */
911- opname = NameStr (form -> oprname );
912928 oprkind = form -> oprkind ;
913929
914930 /* Sanity check. */
@@ -927,8 +943,8 @@ deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root)
927943 appendStringInfoChar (buf , ' ' );
928944 }
929945
930- /* Deparse fully qualified operator name. */
931- appendStringInfo (buf , "OPERATOR(%s.%s)" , opnspname , opname );
946+ /* Deparse operator name. */
947+ deparseOperatorName (buf , form );
932948
933949 /* Deparse right operand. */
934950 if (oprkind == 'l' || oprkind == 'b' )
@@ -943,6 +959,34 @@ deparseOpExpr(StringInfo buf, OpExpr *node, PlannerInfo *root)
943959 ReleaseSysCache (tuple );
944960}
945961
962+ /*
963+ * Print the name of an operator.
964+ */
965+ static void
966+ deparseOperatorName (StringInfo buf , Form_pg_operator opform )
967+ {
968+ char * opname ;
969+
970+ /* opname is not a SQL identifier, so we should not quote it. */
971+ opname = NameStr (opform -> oprname );
972+
973+ /* Print schema name only if it's not pg_catalog */
974+ if (opform -> oprnamespace != PG_CATALOG_NAMESPACE )
975+ {
976+ const char * opnspname ;
977+
978+ opnspname = get_namespace_name (opform -> oprnamespace );
979+ /* Print fully qualified operator name. */
980+ appendStringInfo (buf , "OPERATOR(%s.%s)" ,
981+ quote_identifier (opnspname ), opname );
982+ }
983+ else
984+ {
985+ /* Just print operator name. */
986+ appendStringInfo (buf , "%s" , opname );
987+ }
988+ }
989+
946990/*
947991 * Deparse IS DISTINCT FROM.
948992 */
@@ -960,9 +1004,7 @@ deparseDistinctExpr(StringInfo buf, DistinctExpr *node, PlannerInfo *root)
9601004
9611005/*
9621006 * Deparse given ScalarArrayOpExpr expression into buf. To avoid problems
963- * around priority of operations, we always parenthesize the arguments. Also
964- * we use OPERATOR(schema.operator) notation to determine remote operator
965- * exactly.
1007+ * around priority of operations, we always parenthesize the arguments.
9661008 */
9671009static void
9681010deparseScalarArrayOpExpr (StringInfo buf ,
@@ -971,8 +1013,6 @@ deparseScalarArrayOpExpr(StringInfo buf,
9711013{
9721014 HeapTuple tuple ;
9731015 Form_pg_operator form ;
974- const char * opnspname ;
975- char * opname ;
9761016 Expr * arg1 ;
9771017 Expr * arg2 ;
9781018
@@ -982,10 +1022,6 @@ deparseScalarArrayOpExpr(StringInfo buf,
9821022 elog (ERROR , "cache lookup failed for operator %u" , node -> opno );
9831023 form = (Form_pg_operator ) GETSTRUCT (tuple );
9841024
985- opnspname = quote_identifier (get_namespace_name (form -> oprnamespace ));
986- /* opname is not a SQL identifier, so we don't need to quote it. */
987- opname = NameStr (form -> oprname );
988-
9891025 /* Sanity check. */
9901026 Assert (list_length (node -> args ) == 2 );
9911027
@@ -995,10 +1031,11 @@ deparseScalarArrayOpExpr(StringInfo buf,
9951031 /* Deparse left operand. */
9961032 arg1 = linitial (node -> args );
9971033 deparseExpr (buf , arg1 , root );
1034+ appendStringInfoChar (buf , ' ' );
9981035
999- /* Deparse fully qualified operator name plus decoration. */
1000- appendStringInfo (buf , " OPERATOR(%s.%s) %s (" ,
1001- opnspname , opname , node -> useOr ? "ANY" : "ALL" );
1036+ /* Deparse operator name plus decoration. */
1037+ deparseOperatorName (buf , form );
1038+ appendStringInfo ( buf , " %s (" , node -> useOr ? "ANY" : "ALL" );
10021039
10031040 /* Deparse right operand. */
10041041 arg2 = lsecond (node -> args );
0 commit comments