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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy