You are right, I came to this erroneous conclusion based on the following mishandled experiment: My test program is shown below.
typedef struct ColumnIdentifier { Oid relid; AttrNumber resno; } ColumnIdentifier; typedef struct ColumnType { ColumnIdentifier colId; Oid vartype; } ColumnType; int ColumnIdentifier_compare(const void *key1, const void *key2, Size keysize) { const ColumnIdentifier *colId_key1 = (const ColumnIdentifier *) key1; const ColumnIdentifier *colId_key2 = (const ColumnIdentifier *) key2; return colId_key1->relid == colId_key2->relid && colId_key1->resno == colId_key2->resno ? 0 : 1; } void * ColumnIdentifier_copy(void *dest, const void *src, Size keysize) { ColumnIdentifier *colId_dest = (ColumnIdentifier *) dest; ColumnIdentifier *colId_src = (ColumnIdentifier *) src; colId_dest->relid = colId_src->relid; colId_dest->resno = colId_src->resno; return NULL; /* not used */ } HASHCTL hashctl; hashctl.hash = tag_hash; hashctl.match = ColumnIdentifier_compare; hashctl.keycopy = ColumnIdentifier_copy; hashctl.keysize = sizeof(ColumnIdentifier); hashctl.entrysize = sizeof(ColumnType); HTAB *htab = hash_create("type of column", 512 /* nelem */, &hashctl, HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_KEYCOPY); ColumnType *entry = NULL; ColumnIdentifier *colId = (ColumnIdentifier *) MemoryContextAllocZero(CurrentMemoryContext, sizeof(ColumnIdentifier)); ColumnType *coltype = (ColumnType *) MemoryContextAllocZero(CurrentMemoryContext, sizeof(ColumnType)); coltype->colId.relid = colId->relid = 16384; coltype->colId.resno = colId->resno = 1; coltype->vartype = INT4OID; hash_search(htab, coltype, HASH_ENTER, NULL); entry = hash_search(htab, colId, HASH_FIND, NULL); Assert(entry->colId.relid == colId->relid); Assert(entry->colId.resno == colId->resno); Assert(entry->vartype == INT4OID); // entry->vartype == 0 As shown above, entry->vartype is not assigned when keycopy copies only the key. I modified ColumnIdentifier_copy as shown below, the keycopy copies the entire entry. void * ColumnIdentifier_copy(void *dest, const void *src, Size keysize) { const ColumnType *coltype_src = (const ColumnType *) src; const ColumnType *coltype_dest = (const ColumnType *) dest; coltype_dest->colId->relid = coltype_src->colId->relid; coltype_dest->colId->resno = coltype_src->colId->resno; coltype_dest->vartype = coltype_src->vartype; return NULL; /* not used */ } The result is that entry->vartype is now the same as var->vartype, which leads me to believe that keycopy "should" copy the entire entry. Before sending the initial email, I looked at the implementation of "hash_search_with_hash_value" and found the line "hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize)", which made me wonder how data field is copied into the HTAB? But at the time I ignored a note above: "Caller is expected to fill the data field on return". Now I know that the data field needs to be filled manually, so it was my misuse. Thanks for the correction! Thanks Tom Lane <t...@sss.pgh.pa.us> 于2023年9月13日周三 09:36写道: > ywgrit <yw987194...@gmail.com> writes: > > According to the description, the keycopy function only copies the key, > but > > in reality it copies the entire entry, i.e., the key and the value, > > On what grounds do you claim that? dynahash.c only ever passes "keysize" > as the size parameter. > > regards, tom lane >