Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7f8f766

Browse files
committed
Planner failed to be smart about binary-compatible expressions in pathkeys
and hash bucket-size estimation. Issue has been there awhile but is more critical in 7.4 because it affects varchar columns. Per report from Greg Stark.
1 parent 32580ef commit 7f8f766

File tree

4 files changed

+64
-13
lines changed

4 files changed

+64
-13
lines changed

src/backend/optimizer/path/costsize.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* Portions Copyright (c) 1994, Regents of the University of California
5050
*
5151
* IDENTIFICATION
52-
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.116 2003/11/29 19:51:50 pgsql Exp $
52+
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.117 2003/12/03 17:45:07 tgl Exp $
5353
*
5454
*-------------------------------------------------------------------------
5555
*/
@@ -1322,6 +1322,10 @@ estimate_hash_bucketsize(Query *root, Var *var, int nbuckets)
13221322
float4 *numbers;
13231323
int nnumbers;
13241324

1325+
/* Ignore any binary-compatible relabeling */
1326+
if (var && IsA(var, RelabelType))
1327+
var = (Var *) ((RelabelType *) var)->arg;
1328+
13251329
/*
13261330
* Lookup info about var's relation and attribute; if none available,
13271331
* return default estimate.

src/backend/optimizer/path/pathkeys.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.54 2003/11/29 19:51:50 pgsql Exp $
14+
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.55 2003/12/03 17:45:07 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -25,12 +25,13 @@
2525
#include "optimizer/tlist.h"
2626
#include "optimizer/var.h"
2727
#include "parser/parsetree.h"
28+
#include "parser/parse_expr.h"
2829
#include "parser/parse_func.h"
2930
#include "utils/lsyscache.h"
3031
#include "utils/memutils.h"
3132

3233

33-
static PathKeyItem *makePathKeyItem(Node *key, Oid sortop);
34+
static PathKeyItem *makePathKeyItem(Node *key, Oid sortop, bool checkType);
3435
static List *make_canonical_pathkey(Query *root, PathKeyItem *item);
3536
static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
3637
AttrNumber varattno);
@@ -41,10 +42,29 @@ static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
4142
* create a PathKeyItem node
4243
*/
4344
static PathKeyItem *
44-
makePathKeyItem(Node *key, Oid sortop)
45+
makePathKeyItem(Node *key, Oid sortop, bool checkType)
4546
{
4647
PathKeyItem *item = makeNode(PathKeyItem);
4748

49+
/*
50+
* Some callers pass expressions that are not necessarily of the same
51+
* type as the sort operator expects as input (for example when dealing
52+
* with an index that uses binary-compatible operators). We must relabel
53+
* these with the correct type so that the key expressions will be seen
54+
* as equal() to expressions that have been correctly labeled.
55+
*/
56+
if (checkType)
57+
{
58+
Oid lefttype,
59+
righttype;
60+
61+
op_input_types(sortop, &lefttype, &righttype);
62+
if (exprType(key) != lefttype)
63+
key = (Node *) makeRelabelType((Expr *) key,
64+
lefttype, -1,
65+
COERCE_DONTCARE);
66+
}
67+
4868
item->key = key;
4969
item->sortop = sortop;
5070
return item;
@@ -70,9 +90,11 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
7090
{
7191
Expr *clause = restrictinfo->clause;
7292
PathKeyItem *item1 = makePathKeyItem(get_leftop(clause),
73-
restrictinfo->left_sortop);
93+
restrictinfo->left_sortop,
94+
false);
7495
PathKeyItem *item2 = makePathKeyItem(get_rightop(clause),
75-
restrictinfo->right_sortop);
96+
restrictinfo->right_sortop,
97+
false);
7698
List *newset,
7799
*cursetlink;
78100

@@ -668,7 +690,7 @@ build_index_pathkeys(Query *root,
668690
}
669691

670692
/* OK, make a sublist for this sort key */
671-
item = makePathKeyItem(indexkey, sortop);
693+
item = makePathKeyItem(indexkey, sortop, true);
672694
cpathkey = make_canonical_pathkey(root, item);
673695

674696
/*
@@ -785,7 +807,8 @@ build_subquery_pathkeys(Query *root, RelOptInfo *rel, Query *subquery)
785807
tle->resdom->restypmod,
786808
0);
787809
outer_item = makePathKeyItem((Node *) outer_var,
788-
sub_item->sortop);
810+
sub_item->sortop,
811+
true);
789812
/* score = # of mergejoin peers */
790813
score = count_canonical_peers(root, outer_item);
791814
/* +1 if it matches the proper query_pathkeys item */
@@ -893,7 +916,7 @@ make_pathkeys_for_sortclauses(List *sortclauses,
893916
PathKeyItem *pathkey;
894917

895918
sortkey = get_sortgroupclause_expr(sortcl, tlist);
896-
pathkey = makePathKeyItem(sortkey, sortcl->sortop);
919+
pathkey = makePathKeyItem(sortkey, sortcl->sortop, true);
897920

898921
/*
899922
* The pathkey becomes a one-element sublist, for now;
@@ -937,15 +960,15 @@ cache_mergeclause_pathkeys(Query *root, RestrictInfo *restrictinfo)
937960
{
938961
oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(restrictinfo));
939962
key = get_leftop(restrictinfo->clause);
940-
item = makePathKeyItem(key, restrictinfo->left_sortop);
963+
item = makePathKeyItem(key, restrictinfo->left_sortop, false);
941964
restrictinfo->left_pathkey = make_canonical_pathkey(root, item);
942965
MemoryContextSwitchTo(oldcontext);
943966
}
944967
if (restrictinfo->right_pathkey == NIL)
945968
{
946969
oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(restrictinfo));
947970
key = get_rightop(restrictinfo->clause);
948-
item = makePathKeyItem(key, restrictinfo->right_sortop);
971+
item = makePathKeyItem(key, restrictinfo->right_sortop, false);
949972
restrictinfo->right_pathkey = make_canonical_pathkey(root, item);
950973
MemoryContextSwitchTo(oldcontext);
951974
}

src/backend/utils/cache/lsyscache.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.111 2003/11/29 19:52:00 pgsql Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.112 2003/12/03 17:45:09 tgl Exp $
1111
*
1212
* NOTES
1313
* Eventually, the index information should go through here, too.
@@ -465,6 +465,29 @@ get_opname(Oid opno)
465465
return NULL;
466466
}
467467

468+
/*
469+
* op_input_types
470+
*
471+
* Returns the left and right input datatypes for an operator
472+
* (InvalidOid if not relevant).
473+
*/
474+
void
475+
op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
476+
{
477+
HeapTuple tp;
478+
Form_pg_operator optup;
479+
480+
tp = SearchSysCache(OPEROID,
481+
ObjectIdGetDatum(opno),
482+
0, 0, 0);
483+
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
484+
elog(ERROR, "cache lookup failed for operator %u", opno);
485+
optup = (Form_pg_operator) GETSTRUCT(tp);
486+
*lefttype = optup->oprleft;
487+
*righttype = optup->oprright;
488+
ReleaseSysCache(tp);
489+
}
490+
468491
/*
469492
* op_mergejoinable
470493
*

src/include/utils/lsyscache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.85 2003/11/29 22:41:15 pgsql Exp $
9+
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.86 2003/12/03 17:45:10 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -42,6 +42,7 @@ extern bool opclass_is_btree(Oid opclass);
4242
extern bool opclass_is_hash(Oid opclass);
4343
extern RegProcedure get_opcode(Oid opno);
4444
extern char *get_opname(Oid opno);
45+
extern void op_input_types(Oid opno, Oid *lefttype, Oid *righttype);
4546
extern bool op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp);
4647
extern void op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
4748
RegProcedure *ltproc, RegProcedure *gtproc);

0 commit comments

Comments
 (0)