40
40
#include "catalog/pg_collation.h"
41
41
#include "catalog/pg_namespace.h"
42
42
#include "catalog/pg_operator.h"
43
+ #include "catalog/pg_opfamily.h"
43
44
#include "catalog/pg_proc.h"
44
45
#include "catalog/pg_type.h"
45
46
#include "commands/defrem.h"
@@ -179,6 +180,8 @@ static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root,
179
180
Index ignore_rel , List * * ignore_conds , List * * params_list );
180
181
static void deparseAggref (Aggref * node , deparse_expr_cxt * context );
181
182
static void appendGroupByClause (List * tlist , deparse_expr_cxt * context );
183
+ static void appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
184
+ deparse_expr_cxt * context );
182
185
static void appendAggOrderBy (List * orderList , List * targetList ,
183
186
deparse_expr_cxt * context );
184
187
static void appendFunctionName (Oid funcid , deparse_expr_cxt * context );
@@ -904,6 +907,33 @@ is_foreign_param(PlannerInfo *root,
904
907
return false;
905
908
}
906
909
910
+ /*
911
+ * Returns true if it's safe to push down the sort expression described by
912
+ * 'pathkey' to the foreign server.
913
+ */
914
+ bool
915
+ is_foreign_pathkey (PlannerInfo * root ,
916
+ RelOptInfo * baserel ,
917
+ PathKey * pathkey )
918
+ {
919
+ EquivalenceClass * pathkey_ec = pathkey -> pk_eclass ;
920
+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) baserel -> fdw_private ;
921
+
922
+ /*
923
+ * is_foreign_expr would detect volatile expressions as well, but checking
924
+ * ec_has_volatile here saves some cycles.
925
+ */
926
+ if (pathkey_ec -> ec_has_volatile )
927
+ return false;
928
+
929
+ /* can't push down the sort if the pathkey's opfamily is not shippable */
930
+ if (!is_shippable (pathkey -> pk_opfamily , OperatorFamilyRelationId , fpinfo ))
931
+ return false;
932
+
933
+ /* can push if a suitable EC member exists */
934
+ return (find_em_for_rel (root , pathkey_ec , baserel ) != NULL );
935
+ }
936
+
907
937
/*
908
938
* Convert type OID + typmod info into a type name we can ship to the remote
909
939
* server. Someplace else had better have verified that this type name is
@@ -3070,44 +3100,59 @@ appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
3070
3100
{
3071
3101
SortGroupClause * srt = (SortGroupClause * ) lfirst (lc );
3072
3102
Node * sortexpr ;
3073
- Oid sortcoltype ;
3074
- TypeCacheEntry * typentry ;
3075
3103
3076
3104
if (!first )
3077
3105
appendStringInfoString (buf , ", " );
3078
3106
first = false;
3079
3107
3108
+ /* Deparse the sort expression proper. */
3080
3109
sortexpr = deparseSortGroupClause (srt -> tleSortGroupRef , targetList ,
3081
3110
false, context );
3082
- sortcoltype = exprType (sortexpr );
3083
- /* See whether operator is default < or > for datatype */
3084
- typentry = lookup_type_cache (sortcoltype ,
3085
- TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
3086
- if (srt -> sortop == typentry -> lt_opr )
3087
- appendStringInfoString (buf , " ASC" );
3088
- else if (srt -> sortop == typentry -> gt_opr )
3089
- appendStringInfoString (buf , " DESC" );
3090
- else
3091
- {
3092
- HeapTuple opertup ;
3093
- Form_pg_operator operform ;
3094
-
3095
- appendStringInfoString (buf , " USING " );
3096
-
3097
- /* Append operator name. */
3098
- opertup = SearchSysCache1 (OPEROID , ObjectIdGetDatum (srt -> sortop ));
3099
- if (!HeapTupleIsValid (opertup ))
3100
- elog (ERROR , "cache lookup failed for operator %u" , srt -> sortop );
3101
- operform = (Form_pg_operator ) GETSTRUCT (opertup );
3102
- deparseOperatorName (buf , operform );
3103
- ReleaseSysCache (opertup );
3104
- }
3111
+ /* Add decoration as needed. */
3112
+ appendOrderBySuffix (srt -> sortop , exprType (sortexpr ), srt -> nulls_first ,
3113
+ context );
3114
+ }
3115
+ }
3105
3116
3106
- if (srt -> nulls_first )
3107
- appendStringInfoString (buf , " NULLS FIRST" );
3108
- else
3109
- appendStringInfoString (buf , " NULLS LAST" );
3117
+ /*
3118
+ * Append the ASC, DESC, USING <OPERATOR> and NULLS FIRST / NULLS LAST parts
3119
+ * of an ORDER BY clause.
3120
+ */
3121
+ static void
3122
+ appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
3123
+ deparse_expr_cxt * context )
3124
+ {
3125
+ StringInfo buf = context -> buf ;
3126
+ TypeCacheEntry * typentry ;
3127
+
3128
+ /* See whether operator is default < or > for sort expr's datatype. */
3129
+ typentry = lookup_type_cache (sortcoltype ,
3130
+ TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
3131
+
3132
+ if (sortop == typentry -> lt_opr )
3133
+ appendStringInfoString (buf , " ASC" );
3134
+ else if (sortop == typentry -> gt_opr )
3135
+ appendStringInfoString (buf , " DESC" );
3136
+ else
3137
+ {
3138
+ HeapTuple opertup ;
3139
+ Form_pg_operator operform ;
3140
+
3141
+ appendStringInfoString (buf , " USING " );
3142
+
3143
+ /* Append operator name. */
3144
+ opertup = SearchSysCache1 (OPEROID , ObjectIdGetDatum (sortop ));
3145
+ if (!HeapTupleIsValid (opertup ))
3146
+ elog (ERROR , "cache lookup failed for operator %u" , sortop );
3147
+ operform = (Form_pg_operator ) GETSTRUCT (opertup );
3148
+ deparseOperatorName (buf , operform );
3149
+ ReleaseSysCache (opertup );
3110
3150
}
3151
+
3152
+ if (nulls_first )
3153
+ appendStringInfoString (buf , " NULLS FIRST" );
3154
+ else
3155
+ appendStringInfoString (buf , " NULLS LAST" );
3111
3156
}
3112
3157
3113
3158
/*
@@ -3190,18 +3235,21 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context)
3190
3235
}
3191
3236
3192
3237
/*
3193
- * Deparse ORDER BY clause according to the given pathkeys for given base
3194
- * relation. From given pathkeys expressions belonging entirely to the given
3195
- * base relation are obtained and deparsed.
3238
+ * Deparse ORDER BY clause defined by the given pathkeys.
3239
+ *
3240
+ * The clause should use Vars from context->scanrel if !has_final_sort,
3241
+ * or from context->foreignrel's targetlist if has_final_sort.
3242
+ *
3243
+ * We find a suitable pathkey expression (some earlier step
3244
+ * should have verified that there is one) and deparse it.
3196
3245
*/
3197
3246
static void
3198
3247
appendOrderByClause (List * pathkeys , bool has_final_sort ,
3199
3248
deparse_expr_cxt * context )
3200
3249
{
3201
3250
ListCell * lcell ;
3202
3251
int nestlevel ;
3203
- char * delim = " " ;
3204
- RelOptInfo * baserel = context -> scanrel ;
3252
+ const char * delim = " " ;
3205
3253
StringInfo buf = context -> buf ;
3206
3254
3207
3255
/* Make sure any constants in the exprs are printed portably */
@@ -3211,34 +3259,58 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
3211
3259
foreach (lcell , pathkeys )
3212
3260
{
3213
3261
PathKey * pathkey = lfirst (lcell );
3262
+ EquivalenceMember * em ;
3214
3263
Expr * em_expr ;
3264
+ Oid oprid ;
3215
3265
3216
3266
if (has_final_sort )
3217
3267
{
3218
3268
/*
3219
3269
* By construction, context->foreignrel is the input relation to
3220
3270
* the final sort.
3221
3271
*/
3222
- em_expr = find_em_expr_for_input_target (context -> root ,
3223
- pathkey -> pk_eclass ,
3224
- context -> foreignrel -> reltarget );
3272
+ em = find_em_for_rel_target (context -> root ,
3273
+ pathkey -> pk_eclass ,
3274
+ context -> foreignrel );
3225
3275
}
3226
3276
else
3227
- em_expr = find_em_expr_for_rel (pathkey -> pk_eclass , baserel );
3277
+ em = find_em_for_rel (context -> root ,
3278
+ pathkey -> pk_eclass ,
3279
+ context -> scanrel );
3280
+
3281
+ /*
3282
+ * We don't expect any error here; it would mean that shippability
3283
+ * wasn't verified earlier. For the same reason, we don't recheck
3284
+ * shippability of the sort operator.
3285
+ */
3286
+ if (em == NULL )
3287
+ elog (ERROR , "could not find pathkey item to sort" );
3288
+
3289
+ em_expr = em -> em_expr ;
3228
3290
3229
- Assert (em_expr != NULL );
3291
+ /*
3292
+ * Lookup the operator corresponding to the strategy in the opclass.
3293
+ * The datatype used by the opfamily is not necessarily the same as
3294
+ * the expression type (for array types for example).
3295
+ */
3296
+ oprid = get_opfamily_member (pathkey -> pk_opfamily ,
3297
+ em -> em_datatype ,
3298
+ em -> em_datatype ,
3299
+ pathkey -> pk_strategy );
3300
+ if (!OidIsValid (oprid ))
3301
+ elog (ERROR , "missing operator %d(%u,%u) in opfamily %u" ,
3302
+ pathkey -> pk_strategy , em -> em_datatype , em -> em_datatype ,
3303
+ pathkey -> pk_opfamily );
3230
3304
3231
3305
appendStringInfoString (buf , delim );
3232
3306
deparseExpr (em_expr , context );
3233
- if (pathkey -> pk_strategy == BTLessStrategyNumber )
3234
- appendStringInfoString (buf , " ASC" );
3235
- else
3236
- appendStringInfoString (buf , " DESC" );
3237
3307
3238
- if (pathkey -> pk_nulls_first )
3239
- appendStringInfoString (buf , " NULLS FIRST" );
3240
- else
3241
- appendStringInfoString (buf , " NULLS LAST" );
3308
+ /*
3309
+ * Here we need to use the expression's actual type to discover
3310
+ * whether the desired operator will be the default or not.
3311
+ */
3312
+ appendOrderBySuffix (oprid , exprType ((Node * ) em_expr ),
3313
+ pathkey -> pk_nulls_first , context );
3242
3314
3243
3315
delim = ", " ;
3244
3316
}
0 commit comments