8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.2 2003/01/12 04:03:34 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.3 2003/06/22 22: 04:54 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
19
19
#include "executor/executor.h"
20
20
#include "parser/parse_oper.h"
21
21
#include "utils/memutils.h"
22
+ #include "utils/lsyscache.h"
23
+ #include "utils/syscache.h"
22
24
23
25
24
26
/*****************************************************************************
@@ -213,76 +215,46 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
213
215
return eqfunctions ;
214
216
}
215
217
216
-
217
- /*****************************************************************************
218
- * Utility routines for hashing
219
- *****************************************************************************/
220
-
221
218
/*
222
- * ComputeHashFunc
219
+ * execTuplesHashPrepare
220
+ * Look up the equality and hashing functions needed for a TupleHashTable.
223
221
*
224
- * the hash function for hash joins (also used for hash aggregation)
225
- *
226
- * XXX this probably ought to be replaced with datatype-specific
227
- * hash functions, such as those already implemented for hash indexes.
222
+ * This is similar to execTuplesMatchPrepare, but we also need to find the
223
+ * hash functions associated with the equality operators. *eqfunctions and
224
+ * *hashfunctions receive the palloc'd result arrays.
228
225
*/
229
- uint32
230
- ComputeHashFunc (Datum key , int typLen , bool byVal )
226
+ void
227
+ execTuplesHashPrepare (TupleDesc tupdesc ,
228
+ int numCols ,
229
+ AttrNumber * matchColIdx ,
230
+ FmgrInfo * * eqfunctions ,
231
+ FmgrInfo * * hashfunctions )
231
232
{
232
- unsigned char * k ;
233
+ int i ;
233
234
234
- if (byVal )
235
- {
236
- /*
237
- * If it's a by-value data type, just hash the whole Datum value.
238
- * This assumes that datatypes narrower than Datum are
239
- * consistently padded (either zero-extended or sign-extended, but
240
- * not random bits) to fill Datum; see the XXXGetDatum macros in
241
- * postgres.h. NOTE: it would not work to do hash_any(&key, len)
242
- * since this would get the wrong bytes on a big-endian machine.
243
- */
244
- k = (unsigned char * ) & key ;
245
- typLen = sizeof (Datum );
246
- }
247
- else
235
+ * eqfunctions = (FmgrInfo * ) palloc (numCols * sizeof (FmgrInfo ));
236
+ * hashfunctions = (FmgrInfo * ) palloc (numCols * sizeof (FmgrInfo ));
237
+
238
+ for (i = 0 ; i < numCols ; i ++ )
248
239
{
249
- if (typLen > 0 )
250
- {
251
- /* fixed-width pass-by-reference type */
252
- k = (unsigned char * ) DatumGetPointer (key );
253
- }
254
- else if (typLen == -1 )
255
- {
256
- /*
257
- * It's a varlena type, so 'key' points to a "struct varlena".
258
- * NOTE: VARSIZE returns the "real" data length plus the
259
- * sizeof the "vl_len" attribute of varlena (the length
260
- * information). 'key' points to the beginning of the varlena
261
- * struct, so we have to use "VARDATA" to find the beginning
262
- * of the "real" data. Also, we have to be careful to detoast
263
- * the datum if it's toasted. (We don't worry about freeing
264
- * the detoasted copy; that happens for free when the
265
- * per-tuple memory context is reset in ExecHashGetBucket.)
266
- */
267
- struct varlena * vkey = PG_DETOAST_DATUM (key );
268
-
269
- typLen = VARSIZE (vkey ) - VARHDRSZ ;
270
- k = (unsigned char * ) VARDATA (vkey );
271
- }
272
- else if (typLen == -2 )
273
- {
274
- /* It's a null-terminated C string */
275
- typLen = strlen (DatumGetCString (key )) + 1 ;
276
- k = (unsigned char * ) DatumGetPointer (key );
277
- }
278
- else
279
- {
280
- elog (ERROR , "ComputeHashFunc: Invalid typLen %d" , typLen );
281
- k = NULL ; /* keep compiler quiet */
282
- }
240
+ AttrNumber att = matchColIdx [i ];
241
+ Oid typid = tupdesc -> attrs [att - 1 ]-> atttypid ;
242
+ Operator optup ;
243
+ Oid eq_opr ;
244
+ Oid eq_function ;
245
+ Oid hash_function ;
246
+
247
+ optup = equality_oper (typid , false);
248
+ eq_opr = oprid (optup );
249
+ eq_function = oprfuncid (optup );
250
+ ReleaseSysCache (optup );
251
+ hash_function = get_op_hash_function (eq_opr );
252
+ if (!OidIsValid (hash_function ))
253
+ elog (ERROR , "Could not find hash function for hash operator %u" ,
254
+ eq_opr );
255
+ fmgr_info (eq_function , & (* eqfunctions )[i ]);
256
+ fmgr_info (hash_function , & (* hashfunctions )[i ]);
283
257
}
284
-
285
- return DatumGetUInt32 (hash_any (k , typLen ));
286
258
}
287
259
288
260
@@ -299,19 +271,21 @@ ComputeHashFunc(Datum key, int typLen, bool byVal)
299
271
*
300
272
* numCols, keyColIdx: identify the tuple fields to use as lookup key
301
273
* eqfunctions: equality comparison functions to use
274
+ * hashfunctions: datatype-specific hashing functions to use
302
275
* nbuckets: number of buckets to make
303
276
* entrysize: size of each entry (at least sizeof(TupleHashEntryData))
304
277
* tablecxt: memory context in which to store table and table entries
305
278
* tempcxt: short-lived context for evaluation hash and comparison functions
306
279
*
307
- * The eqfunctions array may be made with execTuplesMatchPrepare ().
280
+ * The function arrays may be made with execTuplesHashPrepare ().
308
281
*
309
- * Note that keyColIdx and eqfunctions must be allocated in storage that
310
- * will live as long as the hashtable does.
282
+ * Note that keyColIdx, eqfunctions, and hashfunctions must be allocated in
283
+ * storage that will live as long as the hashtable does.
311
284
*/
312
285
TupleHashTable
313
286
BuildTupleHashTable (int numCols , AttrNumber * keyColIdx ,
314
287
FmgrInfo * eqfunctions ,
288
+ FmgrInfo * hashfunctions ,
315
289
int nbuckets , Size entrysize ,
316
290
MemoryContext tablecxt , MemoryContext tempcxt )
317
291
{
@@ -328,6 +302,7 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
328
302
hashtable -> numCols = numCols ;
329
303
hashtable -> keyColIdx = keyColIdx ;
330
304
hashtable -> eqfunctions = eqfunctions ;
305
+ hashtable -> hashfunctions = hashfunctions ;
331
306
hashtable -> tablecxt = tablecxt ;
332
307
hashtable -> tempcxt = tempcxt ;
333
308
hashtable -> entrysize = entrysize ;
@@ -375,11 +350,15 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
375
350
hashkey = (hashkey << 1 ) | ((hashkey & 0x80000000 ) ? 1 : 0 );
376
351
377
352
attr = heap_getattr (tuple , att , tupdesc , & isNull );
378
- if (isNull )
379
- continue ; /* treat nulls as having hash key 0 */
380
- hashkey ^= ComputeHashFunc (attr ,
381
- (int ) tupdesc -> attrs [att - 1 ]-> attlen ,
382
- tupdesc -> attrs [att - 1 ]-> attbyval );
353
+
354
+ if (!isNull ) /* treat nulls as having hash key 0 */
355
+ {
356
+ uint32 hkey ;
357
+
358
+ hkey = DatumGetUInt32 (FunctionCall1 (& hashtable -> hashfunctions [i ],
359
+ attr ));
360
+ hashkey ^= hkey ;
361
+ }
383
362
}
384
363
bucketno = hashkey % (uint32 ) hashtable -> nbuckets ;
385
364
0 commit comments