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"
@@ -180,6 +181,8 @@ static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root,
180
181
Index ignore_rel ,List * * ignore_conds ,List * * params_list );
181
182
static void deparseAggref (Aggref * node ,deparse_expr_cxt * context );
182
183
static void appendGroupByClause (List * tlist ,deparse_expr_cxt * context );
184
+ static void appendOrderBySuffix (Oid sortop ,Oid sortcoltype ,bool nulls_first ,
185
+ deparse_expr_cxt * context );
183
186
static void appendAggOrderBy (List * orderList ,List * targetList ,
184
187
deparse_expr_cxt * context );
185
188
static void appendFunctionName (Oid funcid ,deparse_expr_cxt * context );
@@ -910,6 +913,33 @@ is_foreign_param(PlannerInfo *root,
910
913
return false;
911
914
}
912
915
916
+ /*
917
+ * Returns true if it's safe to push down the sort expression described by
918
+ * 'pathkey' to the foreign server.
919
+ */
920
+ bool
921
+ is_foreign_pathkey (PlannerInfo * root ,
922
+ RelOptInfo * baserel ,
923
+ PathKey * pathkey )
924
+ {
925
+ EquivalenceClass * pathkey_ec = pathkey -> pk_eclass ;
926
+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * )baserel -> fdw_private ;
927
+
928
+ /*
929
+ * is_foreign_expr would detect volatile expressions as well, but checking
930
+ * ec_has_volatile here saves some cycles.
931
+ */
932
+ if (pathkey_ec -> ec_has_volatile )
933
+ return false;
934
+
935
+ /* can't push down the sort if the pathkey's opfamily is not shippable */
936
+ if (!is_shippable (pathkey -> pk_opfamily ,OperatorFamilyRelationId ,fpinfo ))
937
+ return false;
938
+
939
+ /* can push if a suitable EC member exists */
940
+ return (find_em_for_rel (root ,pathkey_ec ,baserel )!= NULL );
941
+ }
942
+
913
943
/*
914
944
* Convert type OID + typmod info into a type name we can ship to the remote
915
945
* server. Someplace else had better have verified that this type name is
@@ -3165,44 +3195,59 @@ appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
3165
3195
{
3166
3196
SortGroupClause * srt = (SortGroupClause * )lfirst (lc );
3167
3197
Node * sortexpr ;
3168
- Oid sortcoltype ;
3169
- TypeCacheEntry * typentry ;
3170
3198
3171
3199
if (!first )
3172
3200
appendStringInfoString (buf ,", " );
3173
3201
first = false;
3174
3202
3203
+ /* Deparse the sort expression proper. */
3175
3204
sortexpr = deparseSortGroupClause (srt -> tleSortGroupRef ,targetList ,
3176
3205
false,context );
3177
- sortcoltype = exprType (sortexpr );
3178
- /* See whether operator is default < or > for datatype */
3179
- typentry = lookup_type_cache (sortcoltype ,
3180
- TYPECACHE_LT_OPR |TYPECACHE_GT_OPR );
3181
- if (srt -> sortop == typentry -> lt_opr )
3182
- appendStringInfoString (buf ," ASC" );
3183
- else if (srt -> sortop == typentry -> gt_opr )
3184
- appendStringInfoString (buf ," DESC" );
3185
- else
3186
- {
3187
- HeapTuple opertup ;
3188
- Form_pg_operator operform ;
3189
-
3190
- appendStringInfoString (buf ," USING " );
3191
-
3192
- /* Append operator name. */
3193
- opertup = SearchSysCache1 (OPEROID ,ObjectIdGetDatum (srt -> sortop ));
3194
- if (!HeapTupleIsValid (opertup ))
3195
- elog (ERROR ,"cache lookup failed for operator %u" ,srt -> sortop );
3196
- operform = (Form_pg_operator )GETSTRUCT (opertup );
3197
- deparseOperatorName (buf ,operform );
3198
- ReleaseSysCache (opertup );
3199
- }
3206
+ /* Add decoration as needed. */
3207
+ appendOrderBySuffix (srt -> sortop ,exprType (sortexpr ),srt -> nulls_first ,
3208
+ context );
3209
+ }
3210
+ }
3200
3211
3201
- if (srt -> nulls_first )
3202
- appendStringInfoString (buf ," NULLS FIRST" );
3203
- else
3204
- appendStringInfoString (buf ," NULLS LAST" );
3212
+ /*
3213
+ * Append the ASC, DESC, USING <OPERATOR> and NULLS FIRST / NULLS LAST parts
3214
+ * of an ORDER BY clause.
3215
+ */
3216
+ static void
3217
+ appendOrderBySuffix (Oid sortop ,Oid sortcoltype ,bool nulls_first ,
3218
+ deparse_expr_cxt * context )
3219
+ {
3220
+ StringInfo buf = context -> buf ;
3221
+ TypeCacheEntry * typentry ;
3222
+
3223
+ /* See whether operator is default < or > for sort expr's datatype. */
3224
+ typentry = lookup_type_cache (sortcoltype ,
3225
+ TYPECACHE_LT_OPR |TYPECACHE_GT_OPR );
3226
+
3227
+ if (sortop == typentry -> lt_opr )
3228
+ appendStringInfoString (buf ," ASC" );
3229
+ else if (sortop == typentry -> gt_opr )
3230
+ appendStringInfoString (buf ," DESC" );
3231
+ else
3232
+ {
3233
+ HeapTuple opertup ;
3234
+ Form_pg_operator operform ;
3235
+
3236
+ appendStringInfoString (buf ," USING " );
3237
+
3238
+ /* Append operator name. */
3239
+ opertup = SearchSysCache1 (OPEROID ,ObjectIdGetDatum (sortop ));
3240
+ if (!HeapTupleIsValid (opertup ))
3241
+ elog (ERROR ,"cache lookup failed for operator %u" ,sortop );
3242
+ operform = (Form_pg_operator )GETSTRUCT (opertup );
3243
+ deparseOperatorName (buf ,operform );
3244
+ ReleaseSysCache (opertup );
3205
3245
}
3246
+
3247
+ if (nulls_first )
3248
+ appendStringInfoString (buf ," NULLS FIRST" );
3249
+ else
3250
+ appendStringInfoString (buf ," NULLS LAST" );
3206
3251
}
3207
3252
3208
3253
/*
@@ -3285,18 +3330,21 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context)
3285
3330
}
3286
3331
3287
3332
/*
3288
- * Deparse ORDER BY clause according to the given pathkeys for given base
3289
- * relation. From given pathkeys expressions belonging entirely to the given
3290
- * base relation are obtained and deparsed.
3333
+ * Deparse ORDER BY clause defined by the given pathkeys.
3334
+ *
3335
+ * The clause should use Vars from context->scanrel if !has_final_sort,
3336
+ * or from context->foreignrel's targetlist if has_final_sort.
3337
+ *
3338
+ * We find a suitable pathkey expression (some earlier step
3339
+ * should have verified that there is one) and deparse it.
3291
3340
*/
3292
3341
static void
3293
3342
appendOrderByClause (List * pathkeys ,bool has_final_sort ,
3294
3343
deparse_expr_cxt * context )
3295
3344
{
3296
3345
ListCell * lcell ;
3297
3346
int nestlevel ;
3298
- char * delim = " " ;
3299
- RelOptInfo * baserel = context -> scanrel ;
3347
+ const char * delim = " " ;
3300
3348
StringInfo buf = context -> buf ;
3301
3349
3302
3350
/* Make sure any constants in the exprs are printed portably */
@@ -3306,34 +3354,58 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
3306
3354
foreach (lcell ,pathkeys )
3307
3355
{
3308
3356
PathKey * pathkey = lfirst (lcell );
3357
+ EquivalenceMember * em ;
3309
3358
Expr * em_expr ;
3359
+ Oid oprid ;
3310
3360
3311
3361
if (has_final_sort )
3312
3362
{
3313
3363
/*
3314
3364
* By construction, context->foreignrel is the input relation to
3315
3365
* the final sort.
3316
3366
*/
3317
- em_expr = find_em_expr_for_input_target (context -> root ,
3318
- pathkey -> pk_eclass ,
3319
- context -> foreignrel -> reltarget );
3367
+ em = find_em_for_rel_target (context -> root ,
3368
+ pathkey -> pk_eclass ,
3369
+ context -> foreignrel );
3320
3370
}
3321
3371
else
3322
- em_expr = find_em_expr_for_rel (pathkey -> pk_eclass ,baserel );
3372
+ em = find_em_for_rel (context -> root ,
3373
+ pathkey -> pk_eclass ,
3374
+ context -> scanrel );
3375
+
3376
+ /*
3377
+ * We don't expect any error here; it would mean that shippability
3378
+ * wasn't verified earlier. For the same reason, we don't recheck
3379
+ * shippability of the sort operator.
3380
+ */
3381
+ if (em == NULL )
3382
+ elog (ERROR ,"could not find pathkey item to sort" );
3383
+
3384
+ em_expr = em -> em_expr ;
3323
3385
3324
- Assert (em_expr != NULL );
3386
+ /*
3387
+ * Lookup the operator corresponding to the strategy in the opclass.
3388
+ * The datatype used by the opfamily is not necessarily the same as
3389
+ * the expression type (for array types for example).
3390
+ */
3391
+ oprid = get_opfamily_member (pathkey -> pk_opfamily ,
3392
+ em -> em_datatype ,
3393
+ em -> em_datatype ,
3394
+ pathkey -> pk_strategy );
3395
+ if (!OidIsValid (oprid ))
3396
+ elog (ERROR ,"missing operator %d(%u,%u) in opfamily %u" ,
3397
+ pathkey -> pk_strategy ,em -> em_datatype ,em -> em_datatype ,
3398
+ pathkey -> pk_opfamily );
3325
3399
3326
3400
appendStringInfoString (buf ,delim );
3327
3401
deparseExpr (em_expr ,context );
3328
- if (pathkey -> pk_strategy == BTLessStrategyNumber )
3329
- appendStringInfoString (buf ," ASC" );
3330
- else
3331
- appendStringInfoString (buf ," DESC" );
3332
3402
3333
- if (pathkey -> pk_nulls_first )
3334
- appendStringInfoString (buf ," NULLS FIRST" );
3335
- else
3336
- appendStringInfoString (buf ," NULLS LAST" );
3403
+ /*
3404
+ * Here we need to use the expression's actual type to discover
3405
+ * whether the desired operator will be the default or not.
3406
+ */
3407
+ appendOrderBySuffix (oprid ,exprType ((Node * )em_expr ),
3408
+ pathkey -> pk_nulls_first ,context );
3337
3409
3338
3410
delim = ", " ;
3339
3411
}