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"
@@ -183,6 +184,8 @@ static void deparseRangeTblRef(StringInfo buf, PlannerInfo *root,
183
184
Index ignore_rel , List * * ignore_conds , List * * params_list );
184
185
static void deparseAggref (Aggref * node , deparse_expr_cxt * context );
185
186
static void appendGroupByClause (List * tlist , deparse_expr_cxt * context );
187
+ static void appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
188
+ deparse_expr_cxt * context );
186
189
static void appendAggOrderBy (List * orderList , List * targetList ,
187
190
deparse_expr_cxt * context );
188
191
static void appendFunctionName (Oid funcid , deparse_expr_cxt * context );
@@ -1038,6 +1041,33 @@ is_foreign_param(PlannerInfo *root,
1038
1041
return false;
1039
1042
}
1040
1043
1044
+ /*
1045
+ * Returns true if it's safe to push down the sort expression described by
1046
+ * 'pathkey' to the foreign server.
1047
+ */
1048
+ bool
1049
+ is_foreign_pathkey (PlannerInfo * root ,
1050
+ RelOptInfo * baserel ,
1051
+ PathKey * pathkey )
1052
+ {
1053
+ EquivalenceClass * pathkey_ec = pathkey -> pk_eclass ;
1054
+ PgFdwRelationInfo * fpinfo = (PgFdwRelationInfo * ) baserel -> fdw_private ;
1055
+
1056
+ /*
1057
+ * is_foreign_expr would detect volatile expressions as well, but checking
1058
+ * ec_has_volatile here saves some cycles.
1059
+ */
1060
+ if (pathkey_ec -> ec_has_volatile )
1061
+ return false;
1062
+
1063
+ /* can't push down the sort if the pathkey's opfamily is not shippable */
1064
+ if (!is_shippable (pathkey -> pk_opfamily , OperatorFamilyRelationId , fpinfo ))
1065
+ return false;
1066
+
1067
+ /* can push if a suitable EC member exists */
1068
+ return (find_em_for_rel (root , pathkey_ec , baserel ) != NULL );
1069
+ }
1070
+
1041
1071
/*
1042
1072
* Convert type OID + typmod info into a type name we can ship to the remote
1043
1073
* server. Someplace else had better have verified that this type name is
@@ -3445,44 +3475,59 @@ appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context)
3445
3475
{
3446
3476
SortGroupClause * srt = (SortGroupClause * ) lfirst (lc );
3447
3477
Node * sortexpr ;
3448
- Oid sortcoltype ;
3449
- TypeCacheEntry * typentry ;
3450
3478
3451
3479
if (!first )
3452
3480
appendStringInfoString (buf , ", " );
3453
3481
first = false;
3454
3482
3483
+ /* Deparse the sort expression proper. */
3455
3484
sortexpr = deparseSortGroupClause (srt -> tleSortGroupRef , targetList ,
3456
3485
false, context );
3457
- sortcoltype = exprType (sortexpr );
3458
- /* See whether operator is default < or > for datatype */
3459
- typentry = lookup_type_cache (sortcoltype ,
3460
- TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
3461
- if (srt -> sortop == typentry -> lt_opr )
3462
- appendStringInfoString (buf , " ASC" );
3463
- else if (srt -> sortop == typentry -> gt_opr )
3464
- appendStringInfoString (buf , " DESC" );
3465
- else
3466
- {
3467
- HeapTuple opertup ;
3468
- Form_pg_operator operform ;
3469
-
3470
- appendStringInfoString (buf , " USING " );
3471
-
3472
- /* Append operator name. */
3473
- opertup = SearchSysCache1 (OPEROID , ObjectIdGetDatum (srt -> sortop ));
3474
- if (!HeapTupleIsValid (opertup ))
3475
- elog (ERROR , "cache lookup failed for operator %u" , srt -> sortop );
3476
- operform = (Form_pg_operator ) GETSTRUCT (opertup );
3477
- deparseOperatorName (buf , operform );
3478
- ReleaseSysCache (opertup );
3479
- }
3486
+ /* Add decoration as needed. */
3487
+ appendOrderBySuffix (srt -> sortop , exprType (sortexpr ), srt -> nulls_first ,
3488
+ context );
3489
+ }
3490
+ }
3480
3491
3481
- if (srt -> nulls_first )
3482
- appendStringInfoString (buf , " NULLS FIRST" );
3483
- else
3484
- appendStringInfoString (buf , " NULLS LAST" );
3492
+ /*
3493
+ * Append the ASC, DESC, USING <OPERATOR> and NULLS FIRST / NULLS LAST parts
3494
+ * of an ORDER BY clause.
3495
+ */
3496
+ static void
3497
+ appendOrderBySuffix (Oid sortop , Oid sortcoltype , bool nulls_first ,
3498
+ deparse_expr_cxt * context )
3499
+ {
3500
+ StringInfo buf = context -> buf ;
3501
+ TypeCacheEntry * typentry ;
3502
+
3503
+ /* See whether operator is default < or > for sort expr's datatype. */
3504
+ typentry = lookup_type_cache (sortcoltype ,
3505
+ TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
3506
+
3507
+ if (sortop == typentry -> lt_opr )
3508
+ appendStringInfoString (buf , " ASC" );
3509
+ else if (sortop == typentry -> gt_opr )
3510
+ appendStringInfoString (buf , " DESC" );
3511
+ else
3512
+ {
3513
+ HeapTuple opertup ;
3514
+ Form_pg_operator operform ;
3515
+
3516
+ appendStringInfoString (buf , " USING " );
3517
+
3518
+ /* Append operator name. */
3519
+ opertup = SearchSysCache1 (OPEROID , ObjectIdGetDatum (sortop ));
3520
+ if (!HeapTupleIsValid (opertup ))
3521
+ elog (ERROR , "cache lookup failed for operator %u" , sortop );
3522
+ operform = (Form_pg_operator ) GETSTRUCT (opertup );
3523
+ deparseOperatorName (buf , operform );
3524
+ ReleaseSysCache (opertup );
3485
3525
}
3526
+
3527
+ if (nulls_first )
3528
+ appendStringInfoString (buf , " NULLS FIRST" );
3529
+ else
3530
+ appendStringInfoString (buf , " NULLS LAST" );
3486
3531
}
3487
3532
3488
3533
/*
@@ -3565,18 +3610,21 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context)
3565
3610
}
3566
3611
3567
3612
/*
3568
- * Deparse ORDER BY clause according to the given pathkeys for given base
3569
- * relation. From given pathkeys expressions belonging entirely to the given
3570
- * base relation are obtained and deparsed.
3613
+ * Deparse ORDER BY clause defined by the given pathkeys.
3614
+ *
3615
+ * The clause should use Vars from context->scanrel if !has_final_sort,
3616
+ * or from context->foreignrel's targetlist if has_final_sort.
3617
+ *
3618
+ * We find a suitable pathkey expression (some earlier step
3619
+ * should have verified that there is one) and deparse it.
3571
3620
*/
3572
3621
static void
3573
3622
appendOrderByClause (List * pathkeys , bool has_final_sort ,
3574
3623
deparse_expr_cxt * context )
3575
3624
{
3576
3625
ListCell * lcell ;
3577
3626
int nestlevel ;
3578
- char * delim = " " ;
3579
- RelOptInfo * baserel = context -> scanrel ;
3627
+ const char * delim = " " ;
3580
3628
StringInfo buf = context -> buf ;
3581
3629
3582
3630
/* Make sure any constants in the exprs are printed portably */
@@ -3586,34 +3634,58 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
3586
3634
foreach (lcell , pathkeys )
3587
3635
{
3588
3636
PathKey * pathkey = lfirst (lcell );
3637
+ EquivalenceMember * em ;
3589
3638
Expr * em_expr ;
3639
+ Oid oprid ;
3590
3640
3591
3641
if (has_final_sort )
3592
3642
{
3593
3643
/*
3594
3644
* By construction, context->foreignrel is the input relation to
3595
3645
* the final sort.
3596
3646
*/
3597
- em_expr = find_em_expr_for_input_target (context -> root ,
3598
- pathkey -> pk_eclass ,
3599
- context -> foreignrel -> reltarget );
3647
+ em = find_em_for_rel_target (context -> root ,
3648
+ pathkey -> pk_eclass ,
3649
+ context -> foreignrel );
3600
3650
}
3601
3651
else
3602
- em_expr = find_em_expr_for_rel (pathkey -> pk_eclass , baserel );
3652
+ em = find_em_for_rel (context -> root ,
3653
+ pathkey -> pk_eclass ,
3654
+ context -> scanrel );
3655
+
3656
+ /*
3657
+ * We don't expect any error here; it would mean that shippability
3658
+ * wasn't verified earlier. For the same reason, we don't recheck
3659
+ * shippability of the sort operator.
3660
+ */
3661
+ if (em == NULL )
3662
+ elog (ERROR , "could not find pathkey item to sort" );
3663
+
3664
+ em_expr = em -> em_expr ;
3603
3665
3604
- Assert (em_expr != NULL );
3666
+ /*
3667
+ * Lookup the operator corresponding to the strategy in the opclass.
3668
+ * The datatype used by the opfamily is not necessarily the same as
3669
+ * the expression type (for array types for example).
3670
+ */
3671
+ oprid = get_opfamily_member (pathkey -> pk_opfamily ,
3672
+ em -> em_datatype ,
3673
+ em -> em_datatype ,
3674
+ pathkey -> pk_strategy );
3675
+ if (!OidIsValid (oprid ))
3676
+ elog (ERROR , "missing operator %d(%u,%u) in opfamily %u" ,
3677
+ pathkey -> pk_strategy , em -> em_datatype , em -> em_datatype ,
3678
+ pathkey -> pk_opfamily );
3605
3679
3606
3680
appendStringInfoString (buf , delim );
3607
3681
deparseExpr (em_expr , context );
3608
- if (pathkey -> pk_strategy == BTLessStrategyNumber )
3609
- appendStringInfoString (buf , " ASC" );
3610
- else
3611
- appendStringInfoString (buf , " DESC" );
3612
3682
3613
- if (pathkey -> pk_nulls_first )
3614
- appendStringInfoString (buf , " NULLS FIRST" );
3615
- else
3616
- appendStringInfoString (buf , " NULLS LAST" );
3683
+ /*
3684
+ * Here we need to use the expression's actual type to discover
3685
+ * whether the desired operator will be the default or not.
3686
+ */
3687
+ appendOrderBySuffix (oprid , exprType ((Node * ) em_expr ),
3688
+ pathkey -> pk_nulls_first , context );
3617
3689
3618
3690
delim = ", " ;
3619
3691
}
0 commit comments