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