3838#include "access/heapam.h"
3939#include "access/htup_details.h"
4040#include "access/sysattr.h"
41- #include "access/transam.h"
4241#include "catalog/pg_collation.h"
4342#include "catalog/pg_namespace.h"
4443#include "catalog/pg_operator.h"
@@ -102,7 +101,7 @@ typedef struct deparse_expr_cxt
102101static bool foreign_expr_walker (Node * node ,
103102 foreign_glob_cxt * glob_cxt ,
104103 foreign_loc_cxt * outer_cxt );
105- static bool is_builtin (Oid procid );
104+ static char * deparse_type_name (Oid type_oid , int32 typemod );
106105
107106/*
108107 * Functions to construct string representation of a node tree.
@@ -220,18 +219,20 @@ is_foreign_expr(PlannerInfo *root,
220219 * In addition, *outer_cxt is updated with collation information.
221220 *
222221 * We must check that the expression contains only node types we can deparse,
223- * that all types/functions/operators are safe to send (which we approximate
224- * as being built-in), and that all collations used in the expression derive
225- * from Vars of the foreign table. Because of the latter, the logic is
226- * pretty close to assign_collations_walker() in parse_collate.c, though we
227- * can assume here that the given expression is valid.
222+ * that all types/functions/operators are safe to send (they are "shippable"),
223+ * and that all collations used in the expression derive from Vars of the
224+ * foreign table. Because of the latter, the logic is pretty close to
225+ * assign_collations_walker() in parse_collate.c, though we can assume here
226+ * that the given expression is valid. Note function mutability is not
227+ * currently considered here.
228228 */
229229static bool
230230foreign_expr_walker (Node * node ,
231231 foreign_glob_cxt * glob_cxt ,
232232 foreign_loc_cxt * outer_cxt )
233233{
234234 bool check_type = true;
235+ PgFdwRelationInfo * fpinfo ;
235236 foreign_loc_cxt inner_cxt ;
236237 Oid collation ;
237238 FDWCollateState state ;
@@ -240,6 +241,9 @@ foreign_expr_walker(Node *node,
240241 if (node == NULL )
241242 return true;
242243
244+ /* May need server info from baserel's fdw_private struct */
245+ fpinfo = (PgFdwRelationInfo * ) (glob_cxt -> foreignrel -> fdw_private );
246+
243247 /* Set up inner_cxt for possible recursion to child nodes */
244248 inner_cxt .collation = InvalidOid ;
245249 inner_cxt .state = FDW_COLLATE_NONE ;
@@ -377,11 +381,11 @@ foreign_expr_walker(Node *node,
377381 FuncExpr * fe = (FuncExpr * ) node ;
378382
379383 /*
380- * If function used by the expression is not built-in , it
384+ * If function used by the expression is not shippable , it
381385 * can't be sent to remote because it might have incompatible
382386 * semantics on remote side.
383387 */
384- if (!is_builtin (fe -> funcid ))
388+ if (!is_shippable (fe -> funcid , ProcedureRelationId , fpinfo ))
385389 return false;
386390
387391 /*
@@ -425,11 +429,11 @@ foreign_expr_walker(Node *node,
425429 OpExpr * oe = (OpExpr * ) node ;
426430
427431 /*
428- * Similarly, only built-in operators can be sent to remote.
429- * (If the operator is, surely its underlying function is
430- * too.)
432+ * Similarly, only shippable operators can be sent to remote.
433+ * (If the operator is shippable, we assume its underlying
434+ * function is too.)
431435 */
432- if (!is_builtin (oe -> opno ))
436+ if (!is_shippable (oe -> opno , OperatorRelationId , fpinfo ))
433437 return false;
434438
435439 /*
@@ -467,9 +471,9 @@ foreign_expr_walker(Node *node,
467471 ScalarArrayOpExpr * oe = (ScalarArrayOpExpr * ) node ;
468472
469473 /*
470- * Again, only built-in operators can be sent to remote.
474+ * Again, only shippable operators can be sent to remote.
471475 */
472- if (!is_builtin (oe -> opno ))
476+ if (!is_shippable (oe -> opno , OperatorRelationId , fpinfo ))
473477 return false;
474478
475479 /*
@@ -616,10 +620,10 @@ foreign_expr_walker(Node *node,
616620 }
617621
618622 /*
619- * If result type of given expression is not built-in , it can't be sent to
620- * remote because it might have incompatible semantics on remote side.
623+ * If result type of given expression is not shippable , it can't be sent
624+ * to remote because it might have incompatible semantics on remote side.
621625 */
622- if (check_type && !is_builtin (exprType (node )))
626+ if (check_type && !is_shippable (exprType (node ), TypeRelationId , fpinfo ))
623627 return false;
624628
625629 /*
@@ -672,27 +676,23 @@ foreign_expr_walker(Node *node,
672676}
673677
674678/*
675- * Return true if given object is one of PostgreSQL's built-in objects.
676- *
677- * We use FirstBootstrapObjectId as the cutoff, so that we only consider
678- * objects with hand-assigned OIDs to be "built in", not for instance any
679- * function or type defined in the information_schema.
679+ * Convert type OID + typmod info into a type name we can ship to the remote
680+ * server. Someplace else had better have verified that this type name is
681+ * expected to be known on the remote end.
680682 *
681- * Our constraints for dealing with types are tighter than they are for
682- * functions or operators: we want to accept only types that are in pg_catalog,
683- * else format_type might incorrectly fail to schema-qualify their names.
684- * (This could be fixed with some changes to format_type, but for now there's
685- * no need.) Thus we must exclude information_schema types.
686- *
687- * XXX there is a problem with this, which is that the set of built-in
688- * objects expands over time. Something that is built-in to us might not
689- * be known to the remote server, if it's of an older version. But keeping
690- * track of that would be a huge exercise.
683+ * This is almost just format_type_with_typemod(), except that if left to its
684+ * own devices, that function will make schema-qualification decisions based
685+ * on the local search_path, which is wrong. We must schema-qualify all
686+ * type names that are not in pg_catalog. We assume here that built-in types
687+ * are all in pg_catalog and need not be qualified; otherwise, qualify.
691688 */
692- static bool
693- is_builtin (Oid oid )
689+ static char *
690+ deparse_type_name (Oid type_oid , int32 typemod )
694691{
695- return (oid < FirstBootstrapObjectId );
692+ if (is_builtin (type_oid ))
693+ return format_type_with_typemod (type_oid , typemod );
694+ else
695+ return format_type_with_typemod_qualified (type_oid , typemod );
696696}
697697
698698
@@ -1358,8 +1358,8 @@ deparseConst(Const *node, deparse_expr_cxt *context)
13581358 {
13591359 appendStringInfoString (buf , "NULL" );
13601360 appendStringInfo (buf , "::%s" ,
1361- format_type_with_typemod (node -> consttype ,
1362- node -> consttypmod ));
1361+ deparse_type_name (node -> consttype ,
1362+ node -> consttypmod ));
13631363 return ;
13641364 }
13651365
@@ -1432,8 +1432,8 @@ deparseConst(Const *node, deparse_expr_cxt *context)
14321432 }
14331433 if (needlabel )
14341434 appendStringInfo (buf , "::%s" ,
1435- format_type_with_typemod (node -> consttype ,
1436- node -> consttypmod ));
1435+ deparse_type_name (node -> consttype ,
1436+ node -> consttypmod ));
14371437}
14381438
14391439/*
@@ -1558,7 +1558,7 @@ deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
15581558
15591559 deparseExpr ((Expr * ) linitial (node -> args ), context );
15601560 appendStringInfo (buf , "::%s" ,
1561- format_type_with_typemod (rettype , coercedTypmod ));
1561+ deparse_type_name (rettype , coercedTypmod ));
15621562 return ;
15631563 }
15641564
@@ -1753,8 +1753,8 @@ deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
17531753 deparseExpr (node -> arg , context );
17541754 if (node -> relabelformat != COERCE_IMPLICIT_CAST )
17551755 appendStringInfo (context -> buf , "::%s" ,
1756- format_type_with_typemod (node -> resulttype ,
1757- node -> resulttypmod ));
1756+ deparse_type_name (node -> resulttype ,
1757+ node -> resulttypmod ));
17581758}
17591759
17601760/*
@@ -1834,7 +1834,7 @@ deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
18341834 /* If the array is empty, we need an explicit cast to the array type. */
18351835 if (node -> elements == NIL )
18361836 appendStringInfo (buf , "::%s" ,
1837- format_type_with_typemod (node -> array_typeid , -1 ));
1837+ deparse_type_name (node -> array_typeid , -1 ));
18381838}
18391839
18401840/*
@@ -1850,7 +1850,7 @@ printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
18501850 deparse_expr_cxt * context )
18511851{
18521852 StringInfo buf = context -> buf ;
1853- char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1853+ char * ptypename = deparse_type_name (paramtype , paramtypmod );
18541854
18551855 appendStringInfo (buf , "$%d::%s" , paramindex , ptypename );
18561856}
@@ -1876,7 +1876,7 @@ printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
18761876 deparse_expr_cxt * context )
18771877{
18781878 StringInfo buf = context -> buf ;
1879- char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1879+ char * ptypename = deparse_type_name (paramtype , paramtypmod );
18801880
18811881 appendStringInfo (buf , "((SELECT null::%s)::%s)" , ptypename , ptypename );
18821882}
@@ -1890,10 +1890,10 @@ void
18901890appendOrderByClause (StringInfo buf , PlannerInfo * root , RelOptInfo * baserel ,
18911891 List * pathkeys )
18921892{
1893- ListCell * lcell ;
1894- deparse_expr_cxt context ;
1895- int nestlevel ;
1896- char * delim = " " ;
1893+ ListCell * lcell ;
1894+ deparse_expr_cxt context ;
1895+ int nestlevel ;
1896+ char * delim = " " ;
18971897
18981898 /* Set up context struct for recursion */
18991899 context .root = root ;
@@ -1907,8 +1907,8 @@ appendOrderByClause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel,
19071907 appendStringInfo (buf , " ORDER BY" );
19081908 foreach (lcell , pathkeys )
19091909 {
1910- PathKey * pathkey = lfirst (lcell );
1911- Expr * em_expr ;
1910+ PathKey * pathkey = lfirst (lcell );
1911+ Expr * em_expr ;
19121912
19131913 em_expr = find_em_expr_for_rel (pathkey -> pk_eclass , baserel );
19141914 Assert (em_expr != NULL );
0 commit comments