42
42
#include "catalog/pg_collation.h"
43
43
#include "catalog/pg_namespace.h"
44
44
#include "catalog/pg_operator.h"
45
+ #include "catalog/pg_opfamily.h"
45
46
#include "catalog/pg_proc.h"
46
47
#include "catalog/pg_type.h"
47
48
#include "commands/defrem.h"
@@ -175,6 +176,8 @@ static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root,
175
176
List * * params_list );
176
177
static void deparseAggref (Aggref * node , deparse_expr_cxt * context );
177
178
static void appendGroupByClause (List * tlist , deparse_expr_cxt * context );
179
+ static void appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
180
+ deparse_expr_cxt * context );
178
181
static void appendAggOrderBy (List * orderList , List * targetList ,
179
182
deparse_expr_cxt * context );
180
183
static void appendFunctionName (Oid funcid , deparse_expr_cxt * context );
@@ -901,6 +904,33 @@ is_foreign_param(PlannerInfo *root,
901
904
return false;
902
905
}
903
906
907
+ /*
908
+ * Returns true if it's safe to push down the sort expression described by
909
+ * 'pathkey' to the foreign server.
910
+ */
911
+ bool
912
+ is_foreign_pathkey (PlannerInfo * root ,
913
+ RelOptInfo * baserel ,
914
+ PathKey * pathkey )
915
+ {
916
+ EquivalenceClass * pathkey_ec = pathkey -> pk_eclass ;
917
+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) baserel -> fdw_private ;
918
+
919
+ /*
920
+ * is_foreign_expr would detect volatile expressions as well, but checking
921
+ * ec_has_volatile here saves some cycles.
922
+ */
923
+ if (pathkey_ec -> ec_has_volatile )
924
+ return false;
925
+
926
+ /* can't push down the sort if the pathkey's opfamily is not shippable */
927
+ if (!is_shippable (pathkey -> pk_opfamily , OperatorFamilyRelationId , fpinfo ))
928
+ return false;
929
+
930
+ /* can push if a suitable EC member exists */
931
+ return (find_em_for_rel (root , pathkey_ec , baserel ) != NULL );
932
+ }
933
+
904
934
/*
905
935
* Convert type OID + typmod info into a type name we can ship to the remote
906
936
* server. Someplace else had better have verified that this type name is
@@ -2910,44 +2940,59 @@ appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
2910
2940
{
2911
2941
SortGroupClause * srt = (SortGroupClause * ) lfirst (lc );
2912
2942
Node * sortexpr ;
2913
- Oid sortcoltype ;
2914
- TypeCacheEntry * typentry ;
2915
2943
2916
2944
if (!first )
2917
2945
appendStringInfoString (buf , ", " );
2918
2946
first = false;
2919
2947
2948
+ /* Deparse the sort expression proper. */
2920
2949
sortexpr = deparseSortGroupClause (srt -> tleSortGroupRef , targetList ,
2921
2950
false, context );
2922
- sortcoltype = exprType (sortexpr );
2923
- /* See whether operator is default < or > for datatype */
2924
- typentry = lookup_type_cache (sortcoltype ,
2925
- TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
2926
- if (srt -> sortop == typentry -> lt_opr )
2927
- appendStringInfoString (buf , " ASC" );
2928
- else if (srt -> sortop == typentry -> gt_opr )
2929
- appendStringInfoString (buf , " DESC" );
2930
- else
2931
- {
2932
- HeapTuple opertup ;
2933
- Form_pg_operator operform ;
2934
-
2935
- appendStringInfoString (buf , " USING " );
2936
-
2937
- /* Append operator name. */
2938
- opertup = SearchSysCache1 (OPEROID , ObjectIdGetDatum (srt -> sortop ));
2939
- if (!HeapTupleIsValid (opertup ))
2940
- elog (ERROR , "cache lookup failed for operator %u" , srt -> sortop );
2941
- operform = (Form_pg_operator ) GETSTRUCT (opertup );
2942
- deparseOperatorName (buf , operform );
2943
- ReleaseSysCache (opertup );
2944
- }
2951
+ /* Add decoration as needed. */
2952
+ appendOrderBySuffix (srt -> sortop , exprType (sortexpr ), srt -> nulls_first ,
2953
+ context );
2954
+ }
2955
+ }
2945
2956
2946
- if (srt -> nulls_first )
2947
- appendStringInfoString (buf , " NULLS FIRST" );
2948
- else
2949
- appendStringInfoString (buf , " NULLS LAST" );
2957
+ /*
2958
+ * Append the ASC, DESC, USING <OPERATOR> and NULLS FIRST / NULLS LAST parts
2959
+ * of an ORDER BY clause.
2960
+ */
2961
+ static void
2962
+ appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
2963
+ deparse_expr_cxt * context )
2964
+ {
2965
+ StringInfo buf = context -> buf ;
2966
+ TypeCacheEntry * typentry ;
2967
+
2968
+ /* See whether operator is default < or > for sort expr's datatype. */
2969
+ typentry = lookup_type_cache (sortcoltype ,
2970
+ TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
2971
+
2972
+ if (sortop == typentry -> lt_opr )
2973
+ appendStringInfoString (buf , " ASC" );
2974
+ else if (sortop == typentry -> gt_opr )
2975
+ appendStringInfoString (buf , " DESC" );
2976
+ else
2977
+ {
2978
+ HeapTuple opertup ;
2979
+ Form_pg_operator operform ;
2980
+
2981
+ appendStringInfoString (buf , " USING " );
2982
+
2983
+ /* Append operator name. */
2984
+ opertup = SearchSysCache1 (OPEROID , ObjectIdGetDatum (sortop ));
2985
+ if (!HeapTupleIsValid (opertup ))
2986
+ elog (ERROR , "cache lookup failed for operator %u" , sortop );
2987
+ operform = (Form_pg_operator ) GETSTRUCT (opertup );
2988
+ deparseOperatorName (buf , operform );
2989
+ ReleaseSysCache (opertup );
2950
2990
}
2991
+
2992
+ if (nulls_first )
2993
+ appendStringInfoString (buf , " NULLS FIRST" );
2994
+ else
2995
+ appendStringInfoString (buf , " NULLS LAST" );
2951
2996
}
2952
2997
2953
2998
/*
@@ -3030,17 +3075,17 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context)
3030
3075
}
3031
3076
3032
3077
/*
3033
- * Deparse ORDER BY clause according to the given pathkeys for given base
3034
- * relation. From given pathkeys expressions belonging entirely to the given
3035
- * base relation are obtained and deparsed.
3078
+ * Deparse ORDER BY clause defined by the given pathkeys.
3079
+ *
3080
+ * We find a suitable pathkey expression (some earlier step
3081
+ * should have verified that there is one) and deparse it.
3036
3082
*/
3037
3083
static void
3038
3084
appendOrderByClause (List * pathkeys , deparse_expr_cxt * context )
3039
3085
{
3040
3086
ListCell * lcell ;
3041
3087
int nestlevel ;
3042
- char * delim = " " ;
3043
- RelOptInfo * baserel = context -> scanrel ;
3088
+ const char * delim = " " ;
3044
3089
StringInfo buf = context -> buf ;
3045
3090
3046
3091
/* Make sure any constants in the exprs are printed portably */
@@ -3050,22 +3095,47 @@ appendOrderByClause(List *pathkeys, deparse_expr_cxt *context)
3050
3095
foreach (lcell , pathkeys )
3051
3096
{
3052
3097
PathKey * pathkey = lfirst (lcell );
3098
+ EquivalenceMember * em ;
3053
3099
Expr * em_expr ;
3100
+ Oid oprid ;
3054
3101
3055
- em_expr = find_em_expr_for_rel (pathkey -> pk_eclass , baserel );
3056
- Assert (em_expr != NULL );
3102
+ em = find_em_for_rel (context -> root ,
3103
+ pathkey -> pk_eclass ,
3104
+ context -> scanrel );
3105
+
3106
+ /*
3107
+ * We don't expect any error here; it would mean that shippability
3108
+ * wasn't verified earlier. For the same reason, we don't recheck
3109
+ * shippability of the sort operator.
3110
+ */
3111
+ if (em == NULL )
3112
+ elog (ERROR , "could not find pathkey item to sort" );
3113
+
3114
+ em_expr = em -> em_expr ;
3115
+
3116
+ /*
3117
+ * Lookup the operator corresponding to the strategy in the opclass.
3118
+ * The datatype used by the opfamily is not necessarily the same as
3119
+ * the expression type (for array types for example).
3120
+ */
3121
+ oprid = get_opfamily_member (pathkey -> pk_opfamily ,
3122
+ em -> em_datatype ,
3123
+ em -> em_datatype ,
3124
+ pathkey -> pk_strategy );
3125
+ if (!OidIsValid (oprid ))
3126
+ elog (ERROR , "missing operator %d(%u,%u) in opfamily %u" ,
3127
+ pathkey -> pk_strategy , em -> em_datatype , em -> em_datatype ,
3128
+ pathkey -> pk_opfamily );
3057
3129
3058
3130
appendStringInfoString (buf , delim );
3059
3131
deparseExpr (em_expr , context );
3060
- if (pathkey -> pk_strategy == BTLessStrategyNumber )
3061
- appendStringInfoString (buf , " ASC" );
3062
- else
3063
- appendStringInfoString (buf , " DESC" );
3064
3132
3065
- if (pathkey -> pk_nulls_first )
3066
- appendStringInfoString (buf , " NULLS FIRST" );
3067
- else
3068
- appendStringInfoString (buf , " NULLS LAST" );
3133
+ /*
3134
+ * Here we need to use the expression's actual type to discover
3135
+ * whether the desired operator will be the default or not.
3136
+ */
3137
+ appendOrderBySuffix (oprid , exprType ((Node * ) em_expr ),
3138
+ pathkey -> pk_nulls_first , context );
3069
3139
3070
3140
delim = ", " ;
3071
3141
}
0 commit comments