Skip to content

Commit f68f119

Browse files
committed
Tighten selection of equality and ordering operators for grouping
operations: make sure we use operators that are compatible, as determined by a mergejoin link in pg_operator. Also, add code to planner to ensure we don't try to use hashed grouping when the grouping operators aren't marked hashable.
1 parent 851a4c4 commit f68f119

File tree

8 files changed

+165
-79
lines changed

8 files changed

+165
-79
lines changed

src/backend/commands/analyze.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.50 2002/11/13 00:39:46 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.51 2002/11/29 21:39:10 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -402,10 +402,7 @@ examine_attribute(Relation onerel, int attnum)
402402
return NULL;
403403

404404
/* If column has no "=" operator, we can't do much of anything */
405-
func_operator = compatible_oper(makeList1(makeString("=")),
406-
attr->atttypid,
407-
attr->atttypid,
408-
true);
405+
func_operator = equality_oper(attr->atttypid, true);
409406
if (func_operator != NULL)
410407
{
411408
oprrest = ((Form_pg_operator) GETSTRUCT(func_operator))->oprrest;
@@ -443,10 +440,7 @@ examine_attribute(Relation onerel, int attnum)
443440
stats->attr->attstattarget = default_statistics_target;
444441

445442
/* Is there a "<" operator with suitable semantics? */
446-
func_operator = compatible_oper(makeList1(makeString("<")),
447-
attr->atttypid,
448-
attr->atttypid,
449-
true);
443+
func_operator = ordering_oper(attr->atttypid, true);
450444
if (func_operator != NULL)
451445
{
452446
oprrest = ((Form_pg_operator) GETSTRUCT(func_operator))->oprrest;

src/backend/executor/nodeAgg.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* Portions Copyright (c) 1994, Regents of the University of California
4646
*
4747
* IDENTIFICATION
48-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.96 2002/11/19 23:21:57 tgl Exp $
48+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.97 2002/11/29 21:39:11 tgl Exp $
4949
*
5050
*-------------------------------------------------------------------------
5151
*/
@@ -1321,14 +1321,9 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
13211321
&peraggstate->inputtypeLen,
13221322
&peraggstate->inputtypeByVal);
13231323

1324-
eq_function = compatible_oper_funcid(makeList1(makeString("=")),
1325-
inputType, inputType,
1326-
true);
1327-
if (!OidIsValid(eq_function))
1328-
elog(ERROR, "Unable to identify an equality operator for type %s",
1329-
format_type_be(inputType));
1324+
eq_function = equality_oper_funcid(inputType);
13301325
fmgr_info(eq_function, &(peraggstate->equalfn));
1331-
peraggstate->sortOperator = any_ordering_op(inputType);
1326+
peraggstate->sortOperator = ordering_oper_opid(inputType);
13321327
peraggstate->sortstate = NULL;
13331328
}
13341329

src/backend/executor/nodeGroup.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* locate group boundaries.
1616
*
1717
* IDENTIFICATION
18-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.49 2002/11/06 22:31:23 tgl Exp $
18+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.50 2002/11/29 21:39:11 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -353,11 +353,7 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
353353
Oid typid = tupdesc->attrs[att - 1]->atttypid;
354354
Oid eq_function;
355355

356-
eq_function = compatible_oper_funcid(makeList1(makeString("=")),
357-
typid, typid, true);
358-
if (!OidIsValid(eq_function))
359-
elog(ERROR, "Unable to identify an equality operator for type %s",
360-
format_type_be(typid));
356+
eq_function = equality_oper_funcid(typid);
361357
fmgr_info(eq_function, &eqfunctions[i]);
362358
}
363359

src/backend/optimizer/plan/planner.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.131 2002/11/26 03:01:58 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.132 2002/11/29 21:39:11 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -17,6 +17,7 @@
1717

1818
#include <limits.h>
1919

20+
#include "catalog/pg_operator.h"
2021
#include "catalog/pg_type.h"
2122
#include "miscadmin.h"
2223
#include "nodes/makefuncs.h"
@@ -36,9 +37,11 @@
3637
#include "parser/analyze.h"
3738
#include "parser/parsetree.h"
3839
#include "parser/parse_expr.h"
40+
#include "parser/parse_oper.h"
3941
#include "rewrite/rewriteManip.h"
4042
#include "utils/lsyscache.h"
4143
#include "utils/selfuncs.h"
44+
#include "utils/syscache.h"
4245

4346

4447
/* Expression kind codes for preprocess_expression */
@@ -57,6 +60,7 @@ static Node *preprocess_expression(Query *parse, Node *expr, int kind);
5760
static void preprocess_qual_conditions(Query *parse, Node *jtnode);
5861
static Plan *inheritance_planner(Query *parse, List *inheritlist);
5962
static Plan *grouping_planner(Query *parse, double tuple_fraction);
63+
static bool hash_safe_grouping(Query *parse);
6064
static List *make_subplanTargetList(Query *parse, List *tlist,
6165
AttrNumber **groupColIdx);
6266
static Plan *make_groupsortplan(Query *parse,
@@ -1252,11 +1256,14 @@ grouping_planner(Query *parse, double tuple_fraction)
12521256
numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
12531257

12541258
/*
1259+
* Check can't-do-it conditions, including whether the grouping
1260+
* operators are hashjoinable.
1261+
*
12551262
* Executor doesn't support hashed aggregation with DISTINCT
12561263
* aggregates. (Doing so would imply storing *all* the input
12571264
* values in the hash table, which seems like a certain loser.)
12581265
*/
1259-
if (!enable_hashagg)
1266+
if (!enable_hashagg || !hash_safe_grouping(parse))
12601267
use_hashed_grouping = false;
12611268
else if (parse->hasAggs &&
12621269
(contain_distinct_agg_clause((Node *) tlist) ||
@@ -1554,6 +1561,33 @@ grouping_planner(Query *parse, double tuple_fraction)
15541561
return result_plan;
15551562
}
15561563

1564+
/*
1565+
* hash_safe_grouping - are grouping operators hashable?
1566+
*
1567+
* We assume hashed aggregation will work if the datatype's equality operator
1568+
* is marked hashjoinable.
1569+
*/
1570+
static bool
1571+
hash_safe_grouping(Query *parse)
1572+
{
1573+
List *gl;
1574+
1575+
foreach(gl, parse->groupClause)
1576+
{
1577+
GroupClause *grpcl = (GroupClause *) lfirst(gl);
1578+
TargetEntry *tle = get_sortgroupclause_tle(grpcl, parse->targetList);
1579+
Operator optup;
1580+
bool oprcanhash;
1581+
1582+
optup = equality_oper(tle->resdom->restype, false);
1583+
oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash;
1584+
ReleaseSysCache(optup);
1585+
if (!oprcanhash)
1586+
return false;
1587+
}
1588+
return true;
1589+
}
1590+
15571591
/*---------------
15581592
* make_subplanTargetList
15591593
* Generate appropriate target list when grouping is required.

src/backend/parser/parse_clause.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.99 2002/11/15 02:50:08 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.100 2002/11/29 21:39:11 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1128,8 +1128,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
11281128

11291129
/*
11301130
* transformGroupClause -
1131-
* transform a Group By clause
1132-
*
1131+
* transform a GROUP BY clause
11331132
*/
11341133
List *
11351134
transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
@@ -1151,7 +1150,7 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
11511150

11521151
grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
11531152

1154-
grpcl->sortop = any_ordering_op(tle->resdom->restype);
1153+
grpcl->sortop = ordering_oper_opid(tle->resdom->restype);
11551154

11561155
glist = lappend(glist, grpcl);
11571156
}
@@ -1331,7 +1330,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
13311330
* addTargetToSortList
13321331
* If the given targetlist entry isn't already in the ORDER BY list,
13331332
* add it to the end of the list, using the sortop with given name
1334-
* or any available sort operator if opname == NIL.
1333+
* or the default sort operator if opname == NIL.
13351334
*
13361335
* Returns the updated ORDER BY list.
13371336
*/
@@ -1352,7 +1351,7 @@ addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
13521351
tle->resdom->restype,
13531352
false);
13541353
else
1355-
sortcl->sortop = any_ordering_op(tle->resdom->restype);
1354+
sortcl->sortop = ordering_oper_opid(tle->resdom->restype);
13561355

13571356
sortlist = lappend(sortlist, sortcl);
13581357
}

src/backend/parser/parse_oper.c

Lines changed: 105 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.60 2002/09/18 21:35:22 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.61 2002/11/29 21:39:11 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -130,22 +130,116 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft,
130130
return operoid;
131131
}
132132

133+
/*
134+
* equality_oper - identify a suitable equality operator for a datatype
135+
*
136+
* On failure, return NULL if noError, else report a standard error
137+
*/
138+
Operator
139+
equality_oper(Oid argtype, bool noError)
140+
{
141+
Operator optup;
133142

134-
/* Select an ordering operator for the given datatype */
135-
Oid
136-
any_ordering_op(Oid argtype)
143+
/*
144+
* Look for an "=" operator for the datatype. We require it to be
145+
* an exact or binary-compatible match, since most callers are not
146+
* prepared to cope with adding any run-time type coercion steps.
147+
*/
148+
optup = compatible_oper(makeList1(makeString("=")),
149+
argtype, argtype, true);
150+
if (optup != NULL)
151+
{
152+
/*
153+
* Only believe that it's equality if it's mergejoinable,
154+
* hashjoinable, or uses eqsel() as oprrest.
155+
*/
156+
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(optup);
157+
158+
if (OidIsValid(pgopform->oprlsortop) ||
159+
pgopform->oprcanhash ||
160+
pgopform->oprrest == F_EQSEL)
161+
return optup;
162+
163+
ReleaseSysCache(optup);
164+
}
165+
if (!noError)
166+
elog(ERROR, "Unable to identify an equality operator for type %s",
167+
format_type_be(argtype));
168+
return NULL;
169+
}
170+
171+
/*
172+
* ordering_oper - identify a suitable sorting operator ("<") for a datatype
173+
*
174+
* On failure, return NULL if noError, else report a standard error
175+
*/
176+
Operator
177+
ordering_oper(Oid argtype, bool noError)
137178
{
138-
Oid order_opid;
179+
Operator optup;
139180

140-
order_opid = compatible_oper_opid(makeList1(makeString("<")),
141-
argtype, argtype, true);
142-
if (!OidIsValid(order_opid))
143-
elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'"
181+
/*
182+
* Find the type's equality operator, and use its lsortop (it *must*
183+
* be mergejoinable). We use this definition because for sorting and
184+
* grouping purposes, it's important that the equality and ordering
185+
* operators are consistent.
186+
*/
187+
optup = equality_oper(argtype, noError);
188+
if (optup != NULL)
189+
{
190+
Oid lsortop = ((Form_pg_operator) GETSTRUCT(optup))->oprlsortop;
191+
192+
ReleaseSysCache(optup);
193+
194+
if (OidIsValid(lsortop))
195+
{
196+
optup = SearchSysCache(OPEROID,
197+
ObjectIdGetDatum(lsortop),
198+
0, 0, 0);
199+
if (optup != NULL)
200+
return optup;
201+
}
202+
}
203+
if (!noError)
204+
elog(ERROR, "Unable to identify an ordering operator for type %s"
144205
"\n\tUse an explicit ordering operator or modify the query",
145-
"<", format_type_be(argtype));
146-
return order_opid;
206+
format_type_be(argtype));
207+
return NULL;
208+
}
209+
210+
/*
211+
* equality_oper_funcid - convenience routine for oprfuncid(equality_oper())
212+
*/
213+
Oid
214+
equality_oper_funcid(Oid argtype)
215+
{
216+
Operator optup;
217+
Oid result;
218+
219+
optup = equality_oper(argtype, false);
220+
result = oprfuncid(optup);
221+
ReleaseSysCache(optup);
222+
return result;
223+
}
224+
225+
/*
226+
* ordering_oper_opid - convenience routine for oprid(ordering_oper())
227+
*
228+
* This was formerly called any_ordering_op()
229+
*/
230+
Oid
231+
ordering_oper_opid(Oid argtype)
232+
{
233+
Operator optup;
234+
Oid result;
235+
236+
optup = ordering_oper(argtype, false);
237+
result = oprid(optup);
238+
ReleaseSysCache(optup);
239+
return result;
147240
}
148241

242+
149243
/* given operator tuple, return the operator OID */
150244
Oid
151245
oprid(Operator op)
@@ -731,28 +825,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
731825
return InvalidOid;
732826
}
733827

734-
/* compatible_oper_funcid() -- get OID of a binary operator's function
735-
*
736-
* This is a convenience routine that extracts only the function OID
737-
* from the result of compatible_oper(). InvalidOid is returned if the
738-
* lookup fails and noError is true.
739-
*/
740-
Oid
741-
compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError)
742-
{
743-
Operator optup;
744-
Oid result;
745-
746-
optup = compatible_oper(op, arg1, arg2, noError);
747-
if (optup != NULL)
748-
{
749-
result = oprfuncid(optup);
750-
ReleaseSysCache(optup);
751-
return result;
752-
}
753-
return InvalidOid;
754-
}
755-
756828

757829
/* right_oper() -- search for a unary right operator (operator on right)
758830
* Given operator name and type of arg, return oper struct.

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