Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit01e658f

Browse files
committed
Hash support for row types
Add hash functions for the record type as well as a hash operatorfamily and operator class for the record type. This enables all thehash functionality for the record type such as hash-based plans forUNION/INTERSECT/EXCEPT DISTINCT, recursive queries using UNIONDISTINCT, hash joins, and hash partitioning.Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>Discussion:https://www.postgresql.org/message-id/flat/38eccd35-4e2d-6767-1b3c-dada1eac3124%402ndquadrant.com
1 parent7888b09 commit01e658f

File tree

19 files changed

+462
-75
lines changed

19 files changed

+462
-75
lines changed

‎doc/src/sgml/queries.sgml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,15 +2182,6 @@ SELECT * FROM search_tree <emphasis>ORDER BY path</emphasis>;
21822182
</programlisting>
21832183
</para>
21842184

2185-
<note>
2186-
<para>
2187-
The queries shown in this and the following section involving
2188-
<literal>ROW</literal> constructors in the target list only support
2189-
<literal>UNION ALL</literal> (not plain <literal>UNION</literal>) in the
2190-
current implementation.
2191-
</para>
2192-
</note>
2193-
21942185
<tip>
21952186
<para>
21962187
Omit the <literal>ROW()</literal> syntax in the common case where only one

‎src/backend/utils/adt/rowtypes.c

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include"access/detoast.h"
2020
#include"access/htup_details.h"
2121
#include"catalog/pg_type.h"
22+
#include"common/hashfn.h"
2223
#include"funcapi.h"
2324
#include"libpq/pqformat.h"
2425
#include"miscadmin.h"
@@ -1766,3 +1767,251 @@ btrecordimagecmp(PG_FUNCTION_ARGS)
17661767
{
17671768
PG_RETURN_INT32(record_image_cmp(fcinfo));
17681769
}
1770+
1771+
1772+
/*
1773+
* Row type hash functions
1774+
*/
1775+
1776+
Datum
1777+
hash_record(PG_FUNCTION_ARGS)
1778+
{
1779+
HeapTupleHeaderrecord=PG_GETARG_HEAPTUPLEHEADER(0);
1780+
uint32result=0;
1781+
OidtupType;
1782+
int32tupTypmod;
1783+
TupleDesctupdesc;
1784+
HeapTupleDatatuple;
1785+
intncolumns;
1786+
RecordCompareData*my_extra;
1787+
Datum*values;
1788+
bool*nulls;
1789+
1790+
check_stack_depth();/* recurses for record-type columns */
1791+
1792+
/* Extract type info from tuple */
1793+
tupType=HeapTupleHeaderGetTypeId(record);
1794+
tupTypmod=HeapTupleHeaderGetTypMod(record);
1795+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
1796+
ncolumns=tupdesc->natts;
1797+
1798+
/* Build temporary HeapTuple control structure */
1799+
tuple.t_len=HeapTupleHeaderGetDatumLength(record);
1800+
ItemPointerSetInvalid(&(tuple.t_self));
1801+
tuple.t_tableOid=InvalidOid;
1802+
tuple.t_data=record;
1803+
1804+
/*
1805+
* We arrange to look up the needed hashing info just once per series
1806+
* of calls, assuming the record type doesn't change underneath us.
1807+
*/
1808+
my_extra= (RecordCompareData*)fcinfo->flinfo->fn_extra;
1809+
if (my_extra==NULL||
1810+
my_extra->ncolumns<ncolumns)
1811+
{
1812+
fcinfo->flinfo->fn_extra=
1813+
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1814+
offsetof(RecordCompareData,columns)+
1815+
ncolumns*sizeof(ColumnCompareData));
1816+
my_extra= (RecordCompareData*)fcinfo->flinfo->fn_extra;
1817+
my_extra->ncolumns=ncolumns;
1818+
my_extra->record1_type=InvalidOid;
1819+
my_extra->record1_typmod=0;
1820+
}
1821+
1822+
if (my_extra->record1_type!=tupType||
1823+
my_extra->record1_typmod!=tupTypmod)
1824+
{
1825+
MemSet(my_extra->columns,0,ncolumns*sizeof(ColumnCompareData));
1826+
my_extra->record1_type=tupType;
1827+
my_extra->record1_typmod=tupTypmod;
1828+
}
1829+
1830+
/* Break down the tuple into fields */
1831+
values= (Datum*)palloc(ncolumns*sizeof(Datum));
1832+
nulls= (bool*)palloc(ncolumns*sizeof(bool));
1833+
heap_deform_tuple(&tuple,tupdesc,values,nulls);
1834+
1835+
for (inti=0;i<ncolumns;i++)
1836+
{
1837+
Form_pg_attributeatt;
1838+
TypeCacheEntry*typentry;
1839+
uint32element_hash;
1840+
1841+
att=TupleDescAttr(tupdesc,i);
1842+
1843+
if (att->attisdropped)
1844+
continue;
1845+
1846+
/*
1847+
* Lookup the hash function if not done already
1848+
*/
1849+
typentry=my_extra->columns[i].typentry;
1850+
if (typentry==NULL||
1851+
typentry->type_id!=att->atttypid)
1852+
{
1853+
typentry=lookup_type_cache(att->atttypid,
1854+
TYPECACHE_HASH_PROC_FINFO);
1855+
if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
1856+
ereport(ERROR,
1857+
(errcode(ERRCODE_UNDEFINED_FUNCTION),
1858+
errmsg("could not identify a hash function for type %s",
1859+
format_type_be(typentry->type_id))));
1860+
my_extra->columns[i].typentry=typentry;
1861+
}
1862+
1863+
/* Compute hash of element */
1864+
if (nulls[i])
1865+
{
1866+
element_hash=0;
1867+
}
1868+
else
1869+
{
1870+
LOCAL_FCINFO(locfcinfo,1);
1871+
1872+
InitFunctionCallInfoData(*locfcinfo,&typentry->hash_proc_finfo,1,
1873+
att->attcollation,NULL,NULL);
1874+
locfcinfo->args[0].value=values[i];
1875+
locfcinfo->args[0].isnull= false;
1876+
element_hash=DatumGetUInt32(FunctionCallInvoke(locfcinfo));
1877+
1878+
/* We don't expect hash support functions to return null */
1879+
Assert(!locfcinfo->isnull);
1880+
}
1881+
1882+
/* see hash_array() */
1883+
result= (result <<5)-result+element_hash;
1884+
}
1885+
1886+
pfree(values);
1887+
pfree(nulls);
1888+
ReleaseTupleDesc(tupdesc);
1889+
1890+
/* Avoid leaking memory when handed toasted input. */
1891+
PG_FREE_IF_COPY(record,0);
1892+
1893+
PG_RETURN_UINT32(result);
1894+
}
1895+
1896+
Datum
1897+
hash_record_extended(PG_FUNCTION_ARGS)
1898+
{
1899+
HeapTupleHeaderrecord=PG_GETARG_HEAPTUPLEHEADER(0);
1900+
uint64seed=PG_GETARG_INT64(1);
1901+
uint64result=0;
1902+
OidtupType;
1903+
int32tupTypmod;
1904+
TupleDesctupdesc;
1905+
HeapTupleDatatuple;
1906+
intncolumns;
1907+
RecordCompareData*my_extra;
1908+
Datum*values;
1909+
bool*nulls;
1910+
1911+
check_stack_depth();/* recurses for record-type columns */
1912+
1913+
/* Extract type info from tuple */
1914+
tupType=HeapTupleHeaderGetTypeId(record);
1915+
tupTypmod=HeapTupleHeaderGetTypMod(record);
1916+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
1917+
ncolumns=tupdesc->natts;
1918+
1919+
/* Build temporary HeapTuple control structure */
1920+
tuple.t_len=HeapTupleHeaderGetDatumLength(record);
1921+
ItemPointerSetInvalid(&(tuple.t_self));
1922+
tuple.t_tableOid=InvalidOid;
1923+
tuple.t_data=record;
1924+
1925+
/*
1926+
* We arrange to look up the needed hashing info just once per series
1927+
* of calls, assuming the record type doesn't change underneath us.
1928+
*/
1929+
my_extra= (RecordCompareData*)fcinfo->flinfo->fn_extra;
1930+
if (my_extra==NULL||
1931+
my_extra->ncolumns<ncolumns)
1932+
{
1933+
fcinfo->flinfo->fn_extra=
1934+
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1935+
offsetof(RecordCompareData,columns)+
1936+
ncolumns*sizeof(ColumnCompareData));
1937+
my_extra= (RecordCompareData*)fcinfo->flinfo->fn_extra;
1938+
my_extra->ncolumns=ncolumns;
1939+
my_extra->record1_type=InvalidOid;
1940+
my_extra->record1_typmod=0;
1941+
}
1942+
1943+
if (my_extra->record1_type!=tupType||
1944+
my_extra->record1_typmod!=tupTypmod)
1945+
{
1946+
MemSet(my_extra->columns,0,ncolumns*sizeof(ColumnCompareData));
1947+
my_extra->record1_type=tupType;
1948+
my_extra->record1_typmod=tupTypmod;
1949+
}
1950+
1951+
/* Break down the tuple into fields */
1952+
values= (Datum*)palloc(ncolumns*sizeof(Datum));
1953+
nulls= (bool*)palloc(ncolumns*sizeof(bool));
1954+
heap_deform_tuple(&tuple,tupdesc,values,nulls);
1955+
1956+
for (inti=0;i<ncolumns;i++)
1957+
{
1958+
Form_pg_attributeatt;
1959+
TypeCacheEntry*typentry;
1960+
uint64element_hash;
1961+
1962+
att=TupleDescAttr(tupdesc,i);
1963+
1964+
if (att->attisdropped)
1965+
continue;
1966+
1967+
/*
1968+
* Lookup the hash function if not done already
1969+
*/
1970+
typentry=my_extra->columns[i].typentry;
1971+
if (typentry==NULL||
1972+
typentry->type_id!=att->atttypid)
1973+
{
1974+
typentry=lookup_type_cache(att->atttypid,
1975+
TYPECACHE_HASH_EXTENDED_PROC_FINFO);
1976+
if (!OidIsValid(typentry->hash_extended_proc_finfo.fn_oid))
1977+
ereport(ERROR,
1978+
(errcode(ERRCODE_UNDEFINED_FUNCTION),
1979+
errmsg("could not identify an extended hash function for type %s",
1980+
format_type_be(typentry->type_id))));
1981+
my_extra->columns[i].typentry=typentry;
1982+
}
1983+
1984+
/* Compute hash of element */
1985+
if (nulls[i])
1986+
{
1987+
element_hash=0;
1988+
}
1989+
else
1990+
{
1991+
LOCAL_FCINFO(locfcinfo,2);
1992+
1993+
InitFunctionCallInfoData(*locfcinfo,&typentry->hash_extended_proc_finfo,2,
1994+
att->attcollation,NULL,NULL);
1995+
locfcinfo->args[0].value=values[i];
1996+
locfcinfo->args[0].isnull= false;
1997+
locfcinfo->args[1].value=Int64GetDatum(seed);
1998+
locfcinfo->args[0].isnull= false;
1999+
element_hash=DatumGetUInt64(FunctionCallInvoke(locfcinfo));
2000+
2001+
/* We don't expect hash support functions to return null */
2002+
Assert(!locfcinfo->isnull);
2003+
}
2004+
2005+
/* see hash_array_extended() */
2006+
result= (result <<5)-result+element_hash;
2007+
}
2008+
2009+
pfree(values);
2010+
pfree(nulls);
2011+
ReleaseTupleDesc(tupdesc);
2012+
2013+
/* Avoid leaking memory when handed toasted input. */
2014+
PG_FREE_IF_COPY(record,0);
2015+
2016+
PG_RETURN_UINT64(result);
2017+
}

‎src/backend/utils/cache/lsyscache.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,13 +1358,18 @@ op_hashjoinable(Oid opno, Oid inputtype)
13581358
TypeCacheEntry*typentry;
13591359

13601360
/* As in op_mergejoinable, let the typcache handle the hard cases */
1361-
/* Eventually we'll need a similar case for record_eq ... */
13621361
if (opno==ARRAY_EQ_OP)
13631362
{
13641363
typentry=lookup_type_cache(inputtype,TYPECACHE_HASH_PROC);
13651364
if (typentry->hash_proc==F_HASH_ARRAY)
13661365
result= true;
13671366
}
1367+
elseif (opno==RECORD_EQ_OP)
1368+
{
1369+
typentry=lookup_type_cache(inputtype,TYPECACHE_HASH_PROC);
1370+
if (typentry->hash_proc==F_HASH_RECORD)
1371+
result= true;
1372+
}
13681373
else
13691374
{
13701375
/* For all other operators, rely on pg_operator.oprcanhash */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp