Skip to content

Commit aaff0a5

Browse files
committed
Clean up a couple of problems in crosstab_hash's use of a hash table.
The original coding leaked memory (at least 8K per crosstab_hash call) because it allowed the hash table to be allocated as a child of TopMemoryContext and then never freed it. Fix that by putting the hash table under per_query_ctx, instead. Also get rid of use of a static variable to point to the hash table. Aside from being ugly, that would actively do the wrong thing in the case of re-entrant calls to crosstab_hash, which are at least theoretically possible since it was expecting the static variable to stay valid across a SPI_execute call.
1 parent cac82bb commit aaff0a5

File tree

1 file changed

+25
-22
lines changed

1 file changed

+25
-22
lines changed

contrib/tablefunc/tablefunc.c

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444

4545
PG_MODULE_MAGIC;
4646

47-
static int load_categories_hash(char *cats_sql, MemoryContext per_query_ctx);
47+
static HTAB *load_categories_hash(char *cats_sql, MemoryContext per_query_ctx);
4848
static Tuplestorestate *get_crosstab_tuplestore(char *sql,
49-
int num_categories,
49+
HTAB *crosstab_hash,
5050
TupleDesc tupdesc,
5151
MemoryContext per_query_ctx);
5252
static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial);
@@ -121,40 +121,37 @@ typedef struct
121121
/* sign, 10 digits, '\0' */
122122
#define INT32_STRLEN 12
123123

124-
/* hash table support */
125-
static HTAB *crosstab_HashTable;
126-
127-
/* The information we cache about loaded procedures */
124+
/* stored info for a crosstab category */
128125
typedef struct crosstab_cat_desc
129126
{
130-
char *catname;
127+
char *catname; /* full category name */
131128
int attidx; /* zero based */
132129
} crosstab_cat_desc;
133130

134131
#define MAX_CATNAME_LEN NAMEDATALEN
135132
#define INIT_CATS 64
136133

137-
#define crosstab_HashTableLookup(CATNAME, CATDESC) \
134+
#define crosstab_HashTableLookup(HASHTAB, CATNAME, CATDESC) \
138135
do { \
139136
crosstab_HashEnt *hentry; char key[MAX_CATNAME_LEN]; \
140137
\
141138
MemSet(key, 0, MAX_CATNAME_LEN); \
142139
snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATNAME); \
143-
hentry = (crosstab_HashEnt*) hash_search(crosstab_HashTable, \
140+
hentry = (crosstab_HashEnt*) hash_search(HASHTAB, \
144141
key, HASH_FIND, NULL); \
145142
if (hentry) \
146143
CATDESC = hentry->catdesc; \
147144
else \
148145
CATDESC = NULL; \
149146
} while(0)
150147

151-
#define crosstab_HashTableInsert(CATDESC) \
148+
#define crosstab_HashTableInsert(HASHTAB, CATDESC) \
152149
do { \
153150
crosstab_HashEnt *hentry; bool found; char key[MAX_CATNAME_LEN]; \
154151
\
155152
MemSet(key, 0, MAX_CATNAME_LEN); \
156153
snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATDESC->catname); \
157-
hentry = (crosstab_HashEnt*) hash_search(crosstab_HashTable, \
154+
hentry = (crosstab_HashEnt*) hash_search(HASHTAB, \
158155
key, HASH_ENTER, &found); \
159156
if (found) \
160157
ereport(ERROR, \
@@ -704,7 +701,7 @@ crosstab_hash(PG_FUNCTION_ARGS)
704701
TupleDesc tupdesc;
705702
MemoryContext per_query_ctx;
706703
MemoryContext oldcontext;
707-
int num_categories;
704+
HTAB *crosstab_hash;
708705

709706
/* check to see if caller supports us returning a tuplestore */
710707
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
@@ -737,14 +734,14 @@ crosstab_hash(PG_FUNCTION_ARGS)
737734
"crosstab function are not compatible")));
738735

739736
/* load up the categories hash table */
740-
num_categories = load_categories_hash(cats_sql, per_query_ctx);
737+
crosstab_hash = load_categories_hash(cats_sql, per_query_ctx);
741738

742739
/* let the caller know we're sending back a tuplestore */
743740
rsinfo->returnMode = SFRM_Materialize;
744741

745742
/* now go build it */
746743
rsinfo->setResult = get_crosstab_tuplestore(sql,
747-
num_categories,
744+
crosstab_hash,
748745
tupdesc,
749746
per_query_ctx);
750747

@@ -764,24 +761,29 @@ crosstab_hash(PG_FUNCTION_ARGS)
764761
/*
765762
* load up the categories hash table
766763
*/
767-
static int
764+
static HTAB *
768765
load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
769766
{
767+
HTAB *crosstab_hash;
770768
HASHCTL ctl;
771769
int ret;
772770
int proc;
773771
MemoryContext SPIcontext;
774-
int num_categories = 0;
775772

776773
/* initialize the category hash table */
774+
MemSet(&ctl, 0, sizeof(ctl));
777775
ctl.keysize = MAX_CATNAME_LEN;
778776
ctl.entrysize = sizeof(crosstab_HashEnt);
777+
ctl.hcxt = per_query_ctx;
779778

780779
/*
781780
* use INIT_CATS, defined above as a guess of how many hash table entries
782781
* to create, initially
783782
*/
784-
crosstab_HashTable = hash_create("crosstab hash", INIT_CATS, &ctl, HASH_ELEM);
783+
crosstab_hash = hash_create("crosstab hash",
784+
INIT_CATS,
785+
&ctl,
786+
HASH_ELEM | HASH_CONTEXT);
785787

786788
/* Connect to SPI manager */
787789
if ((ret = SPI_connect()) < 0)
@@ -790,7 +792,7 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
790792

791793
/* Retrieve the category name rows */
792794
ret = SPI_execute(cats_sql, true, 0);
793-
num_categories = proc = SPI_processed;
795+
proc = SPI_processed;
794796

795797
/* Check for qualifying tuples */
796798
if ((ret == SPI_OK_SELECT) && (proc > 0))
@@ -828,7 +830,7 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
828830
catdesc->attidx = i;
829831

830832
/* Add the proc description block to the hashtable */
831-
crosstab_HashTableInsert(catdesc);
833+
crosstab_HashTableInsert(crosstab_hash, catdesc);
832834

833835
MemoryContextSwitchTo(SPIcontext);
834836
}
@@ -838,19 +840,20 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
838840
/* internal error */
839841
elog(ERROR, "load_categories_hash: SPI_finish() failed");
840842

841-
return num_categories;
843+
return crosstab_hash;
842844
}
843845

844846
/*
845847
* create and populate the crosstab tuplestore using the provided source query
846848
*/
847849
static Tuplestorestate *
848850
get_crosstab_tuplestore(char *sql,
849-
int num_categories,
851+
HTAB *crosstab_hash,
850852
TupleDesc tupdesc,
851853
MemoryContext per_query_ctx)
852854
{
853855
Tuplestorestate *tupstore;
856+
int num_categories = hash_get_num_entries(crosstab_hash);
854857
AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc);
855858
char **values;
856859
HeapTuple tuple;
@@ -978,7 +981,7 @@ get_crosstab_tuplestore(char *sql,
978981

979982
if (catname != NULL)
980983
{
981-
crosstab_HashTableLookup(catname, catdesc);
984+
crosstab_HashTableLookup(crosstab_hash, catname, catdesc);
982985

983986
if (catdesc)
984987
values[catdesc->attidx + ncols - 2] =

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy