|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.1 2003/01/10 23:54:24 tgl Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.2 2003/01/12 04:03:34 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
|
23 | 23 |
|
24 | 24 | /*****************************************************************************
|
25 | 25 | * Utility routines for grouping tuples together
|
26 |
| - * |
27 |
| - * These routines actually implement SQL's notion of "distinct/not distinct". |
28 |
| - * Two tuples match if they are not distinct in all the compared columns, |
29 |
| - * i.e., the column values are either both null, or both non-null and equal. |
30 | 26 | *****************************************************************************/
|
31 | 27 |
|
32 | 28 | /*
|
33 | 29 | * execTuplesMatch
|
34 | 30 | * Return true if two tuples match in all the indicated fields.
|
35 |
| - * This is used to detect group boundaries in nodeGroup and nodeAgg, |
36 |
| - * and to decide whether two tuples are distinct or not in nodeUnique. |
| 31 | + * |
| 32 | + * This actually implements SQL's notion of "not distinct". Two nulls |
| 33 | + * match, a null and a not-null don't match. |
37 | 34 | *
|
38 | 35 | * tuple1, tuple2: the tuples to compare
|
39 | 36 | * tupdesc: tuple descriptor applying to both tuples
|
@@ -112,11 +109,88 @@ execTuplesMatch(HeapTuple tuple1,
|
112 | 109 | return result;
|
113 | 110 | }
|
114 | 111 |
|
| 112 | +/* |
| 113 | + * execTuplesUnequal |
| 114 | + * Return true if two tuples are definitely unequal in the indicated |
| 115 | + * fields. |
| 116 | + * |
| 117 | + * Nulls are neither equal nor unequal to anything else. A true result |
| 118 | + * is obtained only if there are non-null fields that compare not-equal. |
| 119 | + * |
| 120 | + * Parameters are identical to execTuplesMatch. |
| 121 | + */ |
| 122 | +bool |
| 123 | +execTuplesUnequal(HeapTuple tuple1, |
| 124 | + HeapTuple tuple2, |
| 125 | + TupleDesc tupdesc, |
| 126 | + int numCols, |
| 127 | + AttrNumber *matchColIdx, |
| 128 | + FmgrInfo *eqfunctions, |
| 129 | + MemoryContext evalContext) |
| 130 | +{ |
| 131 | + MemoryContext oldContext; |
| 132 | + bool result; |
| 133 | + int i; |
| 134 | + |
| 135 | + /* Reset and switch into the temp context. */ |
| 136 | + MemoryContextReset(evalContext); |
| 137 | + oldContext = MemoryContextSwitchTo(evalContext); |
| 138 | + |
| 139 | + /* |
| 140 | + * We cannot report a match without checking all the fields, but we |
| 141 | + * can report a non-match as soon as we find unequal fields. So, |
| 142 | + * start comparing at the last field (least significant sort key). |
| 143 | + * That's the most likely to be different if we are dealing with |
| 144 | + * sorted input. |
| 145 | + */ |
| 146 | + result = false; |
| 147 | + |
| 148 | + for (i = numCols; --i >= 0;) |
| 149 | + { |
| 150 | + AttrNumber att = matchColIdx[i]; |
| 151 | + Datum attr1, |
| 152 | + attr2; |
| 153 | + bool isNull1, |
| 154 | + isNull2; |
| 155 | + |
| 156 | + attr1 = heap_getattr(tuple1, |
| 157 | + att, |
| 158 | + tupdesc, |
| 159 | + &isNull1); |
| 160 | + |
| 161 | + if (isNull1) |
| 162 | + continue; /* can't prove anything here */ |
| 163 | + |
| 164 | + attr2 = heap_getattr(tuple2, |
| 165 | + att, |
| 166 | + tupdesc, |
| 167 | + &isNull2); |
| 168 | + |
| 169 | + if (isNull2) |
| 170 | + continue; /* can't prove anything here */ |
| 171 | + |
| 172 | + /* Apply the type-specific equality function */ |
| 173 | + |
| 174 | + if (!DatumGetBool(FunctionCall2(&eqfunctions[i], |
| 175 | + attr1, attr2))) |
| 176 | + { |
| 177 | + result = true; /* they are unequal */ |
| 178 | + break; |
| 179 | + } |
| 180 | + } |
| 181 | + |
| 182 | + MemoryContextSwitchTo(oldContext); |
| 183 | + |
| 184 | + return result; |
| 185 | +} |
| 186 | + |
115 | 187 |
|
116 | 188 | /*
|
117 | 189 | * execTuplesMatchPrepare
|
118 |
| - * Look up the equality functions needed for execTuplesMatch. |
119 |
| - * The result is a palloc'd array. |
| 190 | + * Look up the equality functions needed for execTuplesMatch or |
| 191 | + * execTuplesUnequal. |
| 192 | + * |
| 193 | + * The result is a palloc'd array. |
120 | 194 | */
|
121 | 195 | FmgrInfo *
|
122 | 196 | execTuplesMatchPrepare(TupleDesc tupdesc,
|
@@ -266,8 +340,13 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
266 | 340 | * Find or create a hashtable entry for the tuple group containing the
|
267 | 341 | * given tuple.
|
268 | 342 | *
|
269 |
| - * On return, *isnew is true if the entry is newly created, false if it |
270 |
| - * existed already. Any extra space in a new entry has been zeroed. |
| 343 | + * If isnew is NULL, we do not create new entries; we return NULL if no |
| 344 | + * match is found. |
| 345 | + * |
| 346 | + * If isnew isn't NULL, then a new entry is created if no existing entry |
| 347 | + * matches. On return, *isnew is true if the entry is newly created, |
| 348 | + * false if it existed already. Any extra space in a new entry has been |
| 349 | + * zeroed. |
271 | 350 | */
|
272 | 351 | TupleHashEntry
|
273 | 352 | LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
|
@@ -318,26 +397,30 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
|
318 | 397 | hashtable->eqfunctions,
|
319 | 398 | hashtable->tempcxt))
|
320 | 399 | {
|
| 400 | + if (isnew) |
| 401 | + *isnew = false; |
321 | 402 | MemoryContextSwitchTo(oldContext);
|
322 |
| - *isnew = false; |
323 | 403 | return entry;
|
324 | 404 | }
|
325 | 405 | }
|
326 | 406 |
|
327 |
| - /* Not there, so build a new one */ |
328 |
| - MemoryContextSwitchTo(hashtable->tablecxt); |
| 407 | + /* Not there, so build a new one if requested */ |
| 408 | + if (isnew) |
| 409 | + { |
| 410 | + MemoryContextSwitchTo(hashtable->tablecxt); |
329 | 411 |
|
330 |
| - entry = (TupleHashEntry) palloc0(hashtable->entrysize); |
| 412 | + entry = (TupleHashEntry) palloc0(hashtable->entrysize); |
331 | 413 |
|
332 |
| - entry->hashkey = hashkey; |
333 |
| - entry->firstTuple = heap_copytuple(tuple); |
| 414 | + entry->hashkey = hashkey; |
| 415 | + entry->firstTuple = heap_copytuple(tuple); |
334 | 416 |
|
335 |
| - entry->next = hashtable->buckets[bucketno]; |
336 |
| - hashtable->buckets[bucketno] = entry; |
| 417 | + entry->next = hashtable->buckets[bucketno]; |
| 418 | + hashtable->buckets[bucketno] = entry; |
337 | 419 |
|
338 |
| - MemoryContextSwitchTo(oldContext); |
| 420 | + *isnew = true; |
| 421 | + } |
339 | 422 |
|
340 |
| - *isnew = true; |
| 423 | + MemoryContextSwitchTo(oldContext); |
341 | 424 |
|
342 | 425 | return entry;
|
343 | 426 | }
|
|
0 commit comments