aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/hash/hash.c34
-rw-r--r--src/backend/access/hash/hashutil.c44
-rw-r--r--src/include/access/hash.h5
3 files changed, 48 insertions, 35 deletions
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 49a6c816aab..19695ee1022 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -176,19 +176,25 @@ hashbuildCallback(Relation index,
void *state)
{
HashBuildState *buildstate = (HashBuildState *) state;
+ Datum index_values[1];
+ bool index_isnull[1];
IndexTuple itup;
- /* Hash indexes don't index nulls, see notes in hashinsert */
- if (isnull[0])
+ /* convert data to a hash key; on failure, do not insert anything */
+ if (!_hash_convert_tuple(index,
+ values, isnull,
+ index_values, index_isnull))
return;
/* Either spool the tuple for sorting, or just put it into the index */
if (buildstate->spool)
- _h_spool(buildstate->spool, &htup->t_self, values, isnull);
+ _h_spool(buildstate->spool, &htup->t_self,
+ index_values, index_isnull);
else
{
/* form an index tuple and point it at the heap tuple */
- itup = _hash_form_tuple(index, values, isnull);
+ itup = index_form_tuple(RelationGetDescr(index),
+ index_values, index_isnull);
itup->t_tid = htup->t_self;
_hash_doinsert(index, itup);
pfree(itup);
@@ -208,22 +214,18 @@ hashinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique)
{
+ Datum index_values[1];
+ bool index_isnull[1];
IndexTuple itup;
- /*
- * If the single index key is null, we don't insert it into the index.
- * Hash tables support scans on '='. Relational algebra says that A = B
- * returns null if either A or B is null. This means that no
- * qualification used in an index scan could ever return true on a null
- * attribute. It also means that indices can't be used by ISNULL or
- * NOTNULL scans, but that's an artifact of the strategy map architecture
- * chosen in 1986, not of the way nulls are handled here.
- */
- if (isnull[0])
+ /* convert data to a hash key; on failure, do not insert anything */
+ if (!_hash_convert_tuple(rel,
+ values, isnull,
+ index_values, index_isnull))
return false;
- /* generate an index tuple */
- itup = _hash_form_tuple(rel, values, isnull);
+ /* form an index tuple and point it at the heap tuple */
+ itup = index_form_tuple(RelationGetDescr(rel), index_values, index_isnull);
itup->t_tid = *ht_ctid;
_hash_doinsert(rel, itup);
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index 456954b0631..822862db7a7 100644
--- a/src/backend/access/hash/hashutil.c
+++ b/src/backend/access/hash/hashutil.c
@@ -240,27 +240,37 @@ _hash_get_indextuple_hashkey(IndexTuple itup)
}
/*
- * _hash_form_tuple - form an index tuple containing hash code only
+ * _hash_convert_tuple - convert raw index data to hash key
+ *
+ * Inputs: values and isnull arrays for the user data column(s)
+ * Outputs: values and isnull arrays for the index tuple, suitable for
+ * passing to index_form_tuple().
+ *
+ * Returns true if successful, false if not (because there are null values).
+ * On a false result, the given data need not be indexed.
+ *
+ * Note: callers know that the index-column arrays are always of length 1.
+ * In principle, there could be more than one input column, though we do not
+ * currently support that.
*/
-IndexTuple
-_hash_form_tuple(Relation index, Datum *values, bool *isnull)
+bool
+_hash_convert_tuple(Relation index,
+ Datum *user_values, bool *user_isnull,
+ Datum *index_values, bool *index_isnull)
{
- IndexTuple itup;
uint32 hashkey;
- Datum hashkeydatum;
- TupleDesc hashdesc;
- if (isnull[0])
- hashkeydatum = (Datum) 0;
- else
- {
- hashkey = _hash_datum2hashkey(index, values[0]);
- hashkeydatum = UInt32GetDatum(hashkey);
- }
- hashdesc = RelationGetDescr(index);
- Assert(hashdesc->natts == 1);
- itup = index_form_tuple(hashdesc, &hashkeydatum, isnull);
- return itup;
+ /*
+ * We do not insert null values into hash indexes. This is okay because
+ * the only supported search operator is '=', and we assume it is strict.
+ */
+ if (user_isnull[0])
+ return false;
+
+ hashkey = _hash_datum2hashkey(index, user_values[0]);
+ index_values[0] = UInt32GetDatum(hashkey);
+ index_isnull[0] = false;
+ return true;
}
/*
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index fa3f9b61caa..ce314180e6b 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -359,8 +359,9 @@ extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
extern uint32 _hash_log2(uint32 num);
extern void _hash_checkpage(Relation rel, Buffer buf, int flags);
extern uint32 _hash_get_indextuple_hashkey(IndexTuple itup);
-extern IndexTuple _hash_form_tuple(Relation index,
- Datum *values, bool *isnull);
+extern bool _hash_convert_tuple(Relation index,
+ Datum *user_values, bool *user_isnull,
+ Datum *index_values, bool *index_isnull);
extern OffsetNumber _hash_binsearch(Page page, uint32 hash_value);
extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);