88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.108 2007/01/05 22:19:28 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.109 2007/01/28 23:21:26 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -92,11 +92,14 @@ MultiExecHash(HashState *node)
9292slot = ExecProcNode (outerNode );
9393if (TupIsNull (slot ))
9494break ;
95- hashtable -> totalTuples += 1 ;
9695/* We have to compute the hash value */
9796econtext -> ecxt_innertuple = slot ;
98- hashvalue = ExecHashGetHashValue (hashtable ,econtext ,hashkeys );
99- ExecHashTableInsert (hashtable ,slot ,hashvalue );
97+ if (ExecHashGetHashValue (hashtable ,econtext ,hashkeys , false,
98+ & hashvalue ))
99+ {
100+ ExecHashTableInsert (hashtable ,slot ,hashvalue );
101+ hashtable -> totalTuples += 1 ;
102+ }
100103}
101104
102105/* must provide our own instrumentation support */
@@ -261,19 +264,23 @@ ExecHashTableCreate(Hash *node, List *hashOperators)
261264
262265/*
263266 * Get info about the hash functions to be used for each hash key.
267+ * Also remember whether the join operators are strict.
264268 */
265269nkeys = list_length (hashOperators );
266270hashtable -> hashfunctions = (FmgrInfo * )palloc (nkeys * sizeof (FmgrInfo ));
271+ hashtable -> hashStrict = (bool * )palloc (nkeys * sizeof (bool ));
267272i = 0 ;
268273foreach (ho ,hashOperators )
269274{
275+ Oid hashop = lfirst_oid (ho );
270276Oid hashfn ;
271277
272- hashfn = get_op_hash_function (lfirst_oid ( ho ) );
278+ hashfn = get_op_hash_function (hashop );
273279if (!OidIsValid (hashfn ))
274280elog (ERROR ,"could not find hash function for hash operator %u" ,
275- lfirst_oid ( ho ) );
281+ hashop );
276282fmgr_info (hashfn ,& hashtable -> hashfunctions [i ]);
283+ hashtable -> hashStrict [i ]= op_strict (hashop );
277284i ++ ;
278285}
279286
@@ -657,11 +664,18 @@ ExecHashTableInsert(HashJoinTable hashtable,
657664 * The tuple to be tested must be in either econtext->ecxt_outertuple or
658665 * econtext->ecxt_innertuple. Vars in the hashkeys expressions reference
659666 * either OUTER or INNER.
667+ *
668+ * A TRUE result means the tuple's hash value has been successfully computed
669+ * and stored at *hashvalue. A FALSE result means the tuple cannot match
670+ * because it contains a null attribute, and hence it should be discarded
671+ * immediately. (If keep_nulls is true then FALSE is never returned.)
660672 */
661- uint32
673+ bool
662674ExecHashGetHashValue (HashJoinTable hashtable ,
663675ExprContext * econtext ,
664- List * hashkeys )
676+ List * hashkeys ,
677+ bool keep_nulls ,
678+ uint32 * hashvalue )
665679{
666680uint32 hashkey = 0 ;
667681ListCell * hk ;
@@ -691,10 +705,27 @@ ExecHashGetHashValue(HashJoinTable hashtable,
691705keyval = ExecEvalExpr (keyexpr ,econtext ,& isNull ,NULL );
692706
693707/*
694- * Compute the hash function
708+ * If the attribute is NULL, and the join operator is strict, then
709+ * this tuple cannot pass the join qual so we can reject it
710+ * immediately (unless we're scanning the outside of an outer join,
711+ * in which case we must not reject it). Otherwise we act like the
712+ * hashcode of NULL is zero (this will support operators that act like
713+ * IS NOT DISTINCT, though not any more-random behavior). We treat
714+ * the hash support function as strict even if the operator is not.
715+ *
716+ * Note: currently, all hashjoinable operators must be strict since
717+ * the hash index AM assumes that. However, it takes so little
718+ * extra code here to allow non-strict that we may as well do it.
695719 */
696- if (!isNull )/* treat nulls as having hash key 0 */
720+ if (isNull )
721+ {
722+ if (hashtable -> hashStrict [i ]&& !keep_nulls )
723+ return false;/* cannot match */
724+ /* else, leave hashkey unmodified, equivalent to hashcode 0 */
725+ }
726+ else
697727{
728+ /* Compute the hash function */
698729uint32 hkey ;
699730
700731hkey = DatumGetUInt32 (FunctionCall1 (& hashtable -> hashfunctions [i ],
@@ -707,7 +738,8 @@ ExecHashGetHashValue(HashJoinTable hashtable,
707738
708739MemoryContextSwitchTo (oldContext );
709740
710- return hashkey ;
741+ * hashvalue = hashkey ;
742+ return true;
711743}
712744
713745/*