38
38
#include "access/heapam.h"
39
39
#include "access/htup_details.h"
40
40
#include "access/sysattr.h"
41
- #include "access/transam.h"
42
41
#include "catalog/pg_collation.h"
43
42
#include "catalog/pg_namespace.h"
44
43
#include "catalog/pg_operator.h"
@@ -102,7 +101,7 @@ typedef struct deparse_expr_cxt
102
101
static bool foreign_expr_walker (Node * node ,
103
102
foreign_glob_cxt * glob_cxt ,
104
103
foreign_loc_cxt * outer_cxt );
105
- static bool is_builtin (Oid procid );
104
+ static char * deparse_type_name (Oid type_oid , int32 typemod );
106
105
107
106
/*
108
107
* Functions to construct string representation of a node tree.
@@ -220,18 +219,20 @@ is_foreign_expr(PlannerInfo *root,
220
219
* In addition, *outer_cxt is updated with collation information.
221
220
*
222
221
* 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.
228
228
*/
229
229
static bool
230
230
foreign_expr_walker (Node * node ,
231
231
foreign_glob_cxt * glob_cxt ,
232
232
foreign_loc_cxt * outer_cxt )
233
233
{
234
234
bool check_type = true;
235
+ PgFdwRelationInfo * fpinfo ;
235
236
foreign_loc_cxt inner_cxt ;
236
237
Oid collation ;
237
238
FDWCollateState state ;
@@ -240,6 +241,9 @@ foreign_expr_walker(Node *node,
240
241
if (node == NULL )
241
242
return true;
242
243
244
+ /* May need server info from baserel's fdw_private struct */
245
+ fpinfo = (PgFdwRelationInfo * ) (glob_cxt -> foreignrel -> fdw_private );
246
+
243
247
/* Set up inner_cxt for possible recursion to child nodes */
244
248
inner_cxt .collation = InvalidOid ;
245
249
inner_cxt .state = FDW_COLLATE_NONE ;
@@ -377,11 +381,11 @@ foreign_expr_walker(Node *node,
377
381
FuncExpr * fe = (FuncExpr * ) node ;
378
382
379
383
/*
380
- * If function used by the expression is not built-in , it
384
+ * If function used by the expression is not shippable , it
381
385
* can't be sent to remote because it might have incompatible
382
386
* semantics on remote side.
383
387
*/
384
- if (!is_builtin (fe -> funcid ))
388
+ if (!is_shippable (fe -> funcid , ProcedureRelationId , fpinfo ))
385
389
return false;
386
390
387
391
/*
@@ -425,11 +429,11 @@ foreign_expr_walker(Node *node,
425
429
OpExpr * oe = (OpExpr * ) node ;
426
430
427
431
/*
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.)
431
435
*/
432
- if (!is_builtin (oe -> opno ))
436
+ if (!is_shippable (oe -> opno , OperatorRelationId , fpinfo ))
433
437
return false;
434
438
435
439
/*
@@ -467,9 +471,9 @@ foreign_expr_walker(Node *node,
467
471
ScalarArrayOpExpr * oe = (ScalarArrayOpExpr * ) node ;
468
472
469
473
/*
470
- * Again, only built-in operators can be sent to remote.
474
+ * Again, only shippable operators can be sent to remote.
471
475
*/
472
- if (!is_builtin (oe -> opno ))
476
+ if (!is_shippable (oe -> opno , OperatorRelationId , fpinfo ))
473
477
return false;
474
478
475
479
/*
@@ -616,10 +620,10 @@ foreign_expr_walker(Node *node,
616
620
}
617
621
618
622
/*
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.
621
625
*/
622
- if (check_type && !is_builtin (exprType (node )))
626
+ if (check_type && !is_shippable (exprType (node ), TypeRelationId , fpinfo ))
623
627
return false;
624
628
625
629
/*
@@ -672,27 +676,23 @@ foreign_expr_walker(Node *node,
672
676
}
673
677
674
678
/*
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.
680
682
*
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.
691
688
*/
692
- static bool
693
- is_builtin (Oid oid )
689
+ static char *
690
+ deparse_type_name (Oid type_oid , int32 typemod )
694
691
{
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 );
696
696
}
697
697
698
698
@@ -1358,8 +1358,8 @@ deparseConst(Const *node, deparse_expr_cxt *context)
1358
1358
{
1359
1359
appendStringInfoString (buf , "NULL" );
1360
1360
appendStringInfo (buf , "::%s" ,
1361
- format_type_with_typemod (node -> consttype ,
1362
- node -> consttypmod ));
1361
+ deparse_type_name (node -> consttype ,
1362
+ node -> consttypmod ));
1363
1363
return ;
1364
1364
}
1365
1365
@@ -1432,8 +1432,8 @@ deparseConst(Const *node, deparse_expr_cxt *context)
1432
1432
}
1433
1433
if (needlabel )
1434
1434
appendStringInfo (buf , "::%s" ,
1435
- format_type_with_typemod (node -> consttype ,
1436
- node -> consttypmod ));
1435
+ deparse_type_name (node -> consttype ,
1436
+ node -> consttypmod ));
1437
1437
}
1438
1438
1439
1439
/*
@@ -1558,7 +1558,7 @@ deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
1558
1558
1559
1559
deparseExpr ((Expr * ) linitial (node -> args ), context );
1560
1560
appendStringInfo (buf , "::%s" ,
1561
- format_type_with_typemod (rettype , coercedTypmod ));
1561
+ deparse_type_name (rettype , coercedTypmod ));
1562
1562
return ;
1563
1563
}
1564
1564
@@ -1753,8 +1753,8 @@ deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
1753
1753
deparseExpr (node -> arg , context );
1754
1754
if (node -> relabelformat != COERCE_IMPLICIT_CAST )
1755
1755
appendStringInfo (context -> buf , "::%s" ,
1756
- format_type_with_typemod (node -> resulttype ,
1757
- node -> resulttypmod ));
1756
+ deparse_type_name (node -> resulttype ,
1757
+ node -> resulttypmod ));
1758
1758
}
1759
1759
1760
1760
/*
@@ -1834,7 +1834,7 @@ deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
1834
1834
/* If the array is empty, we need an explicit cast to the array type. */
1835
1835
if (node -> elements == NIL )
1836
1836
appendStringInfo (buf , "::%s" ,
1837
- format_type_with_typemod (node -> array_typeid , -1 ));
1837
+ deparse_type_name (node -> array_typeid , -1 ));
1838
1838
}
1839
1839
1840
1840
/*
@@ -1850,7 +1850,7 @@ printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
1850
1850
deparse_expr_cxt * context )
1851
1851
{
1852
1852
StringInfo buf = context -> buf ;
1853
- char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1853
+ char * ptypename = deparse_type_name (paramtype , paramtypmod );
1854
1854
1855
1855
appendStringInfo (buf , "$%d::%s" , paramindex , ptypename );
1856
1856
}
@@ -1876,7 +1876,7 @@ printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
1876
1876
deparse_expr_cxt * context )
1877
1877
{
1878
1878
StringInfo buf = context -> buf ;
1879
- char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1879
+ char * ptypename = deparse_type_name (paramtype , paramtypmod );
1880
1880
1881
1881
appendStringInfo (buf , "((SELECT null::%s)::%s)" , ptypename , ptypename );
1882
1882
}
@@ -1890,10 +1890,10 @@ void
1890
1890
appendOrderByClause (StringInfo buf , PlannerInfo * root , RelOptInfo * baserel ,
1891
1891
List * pathkeys )
1892
1892
{
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 = " " ;
1897
1897
1898
1898
/* Set up context struct for recursion */
1899
1899
context .root = root ;
@@ -1907,8 +1907,8 @@ appendOrderByClause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel,
1907
1907
appendStringInfo (buf , " ORDER BY" );
1908
1908
foreach (lcell , pathkeys )
1909
1909
{
1910
- PathKey * pathkey = lfirst (lcell );
1911
- Expr * em_expr ;
1910
+ PathKey * pathkey = lfirst (lcell );
1911
+ Expr * em_expr ;
1912
1912
1913
1913
em_expr = find_em_expr_for_rel (pathkey -> pk_eclass , baserel );
1914
1914
Assert (em_expr != NULL );
0 commit comments