Commit 144b0ae8 authored by Tom Lane's avatar Tom Lane

Teach convert_subquery_pathkeys() to handle the case where the

subquery's pathkey is a RelabelType applied to something that appears
in the subquery's output; for example where the subquery returns a
varchar Var and the sort order is shown as that Var coerced to text.
This comes up because varchar doesn't have its own sort operator.
Per example from Peter Hardman.
parent 4e1bdcaa
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.77 2006/07/14 14:52:20 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.78 2006/08/17 17:02:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1059,39 +1059,73 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, ...@@ -1059,39 +1059,73 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
{ {
PathKeyItem *sub_item = (PathKeyItem *) lfirst(j); PathKeyItem *sub_item = (PathKeyItem *) lfirst(j);
Node *sub_key = sub_item->key; Node *sub_key = sub_item->key;
Expr *rtarg;
ListCell *k; ListCell *k;
/*
* We handle two cases: the sub_pathkey key can be either an exact
* match for a targetlist entry, or a RelabelType of a targetlist
* entry. (The latter case is worth extra code because it arises
* frequently in connection with varchar fields.)
*/
if (IsA(sub_key, RelabelType))
rtarg = ((RelabelType *) sub_key)->arg;
else
rtarg = NULL;
foreach(k, sub_tlist) foreach(k, sub_tlist)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(k); TargetEntry *tle = (TargetEntry *) lfirst(k);
Node *outer_expr;
PathKeyItem *outer_item;
int score;
if (!tle->resjunk && /* resjunk items aren't visible to outer query */
equal(tle->expr, sub_key)) if (tle->resjunk)
continue;
if (equal(tle->expr, sub_key))
{ {
/* Found a representation for this sub_key */ /* Exact match */
Var *outer_var; outer_expr = (Node *)
PathKeyItem *outer_item; makeVar(rel->relid,
int score; tle->resno,
exprType((Node *) tle->expr),
outer_var = makeVar(rel->relid, exprTypmod((Node *) tle->expr),
tle->resno, 0);
exprType((Node *) tle->expr), }
exprTypmod((Node *) tle->expr), else if (rtarg && equal(tle->expr, rtarg))
0); {
outer_item = makePathKeyItem((Node *) outer_var, /* Match after discarding RelabelType */
sub_item->sortop, outer_expr = (Node *)
true); makeVar(rel->relid,
/* score = # of mergejoin peers */ tle->resno,
score = count_canonical_peers(root, outer_item); exprType((Node *) tle->expr),
/* +1 if it matches the proper query_pathkeys item */ exprTypmod((Node *) tle->expr),
if (retvallen < outer_query_keys && 0);
list_member(list_nth(root->query_pathkeys, retvallen), outer_item)) outer_expr = (Node *)
score++; makeRelabelType((Expr *) outer_expr,
if (score > best_score) ((RelabelType *) sub_key)->resulttype,
{ ((RelabelType *) sub_key)->resulttypmod,
best_item = outer_item; ((RelabelType *) sub_key)->relabelformat);
best_score = score; }
} else
continue;
/* Found a representation for this sub_key */
outer_item = makePathKeyItem(outer_expr,
sub_item->sortop,
true);
/* score = # of mergejoin peers */
score = count_canonical_peers(root, outer_item);
/* +1 if it matches the proper query_pathkeys item */
if (retvallen < outer_query_keys &&
list_member(list_nth(root->query_pathkeys, retvallen), outer_item))
score++;
if (score > best_score)
{
best_item = outer_item;
best_score = score;
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment