4444
4545PG_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 );
4848static Tuplestorestate * get_crosstab_tuplestore (char * sql ,
49- int num_categories ,
49+ HTAB * crosstab_hash ,
5050TupleDesc tupdesc ,
5151MemoryContext per_query_ctx );
5252static 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 */
128125typedef struct crosstab_cat_desc
129126{
130- char * catname ;
127+ char * catname ;/* full category name */
131128int 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 ) \
138135do { \
139136crosstab_HashEnt *hentry; char key[MAX_CATNAME_LEN]; \
140137\
141138MemSet(key, 0, MAX_CATNAME_LEN); \
142139snprintf(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); \
145142if (hentry) \
146143CATDESC = hentry->catdesc; \
147144else \
148145CATDESC = NULL; \
149146} while(0)
150147
151- #define crosstab_HashTableInsert (CATDESC ) \
148+ #define crosstab_HashTableInsert (HASHTAB , CATDESC ) \
152149do { \
153150crosstab_HashEnt *hentry; bool found; char key[MAX_CATNAME_LEN]; \
154151\
155152MemSet(key, 0, MAX_CATNAME_LEN); \
156153snprintf(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); \
159156if (found) \
160157ereport(ERROR, \
@@ -704,7 +701,7 @@ crosstab_hash(PG_FUNCTION_ARGS)
704701TupleDesc tupdesc ;
705702MemoryContext per_query_ctx ;
706703MemoryContext oldcontext ;
707- int num_categories ;
704+ HTAB * crosstab_hash ;
708705
709706/* check to see if caller supports us returning a tuplestore */
710707if (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 */
743740rsinfo -> returnMode = SFRM_Materialize ;
744741
745742/* now go build it */
746743rsinfo -> setResult = get_crosstab_tuplestore (sql ,
747- num_categories ,
744+ crosstab_hash ,
748745tupdesc ,
749746per_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 *
768765load_categories_hash (char * cats_sql ,MemoryContext per_query_ctx )
769766{
767+ HTAB * crosstab_hash ;
770768HASHCTL ctl ;
771769int ret ;
772770int proc ;
773771MemoryContext SPIcontext ;
774- int num_categories = 0 ;
775772
776773/* initialize the category hash table */
774+ MemSet (& ctl ,0 ,sizeof (ctl ));
777775ctl .keysize = MAX_CATNAME_LEN ;
778776ctl .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 */
787789if ((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 */
792794ret = SPI_execute (cats_sql , true,0 );
793- num_categories = proc = SPI_processed ;
795+ proc = SPI_processed ;
794796
795797/* Check for qualifying tuples */
796798if ((ret == SPI_OK_SELECT )&& (proc > 0 ))
@@ -828,7 +830,7 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
828830catdesc -> attidx = i ;
829831
830832/* Add the proc description block to the hashtable */
831- crosstab_HashTableInsert (catdesc );
833+ crosstab_HashTableInsert (crosstab_hash , catdesc );
832834
833835MemoryContextSwitchTo (SPIcontext );
834836}
@@ -838,19 +840,20 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
838840/* internal error */
839841elog (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 */
847849static Tuplestorestate *
848850get_crosstab_tuplestore (char * sql ,
849- int num_categories ,
851+ HTAB * crosstab_hash ,
850852TupleDesc tupdesc ,
851853MemoryContext per_query_ctx )
852854{
853855Tuplestorestate * tupstore ;
856+ int num_categories = hash_get_num_entries (crosstab_hash );
854857AttInMetadata * attinmeta = TupleDescGetAttInMetadata (tupdesc );
855858char * * values ;
856859HeapTuple tuple ;
@@ -978,7 +981,7 @@ get_crosstab_tuplestore(char *sql,
978981
979982if (catname != NULL )
980983{
981- crosstab_HashTableLookup (catname ,catdesc );
984+ crosstab_HashTableLookup (crosstab_hash , catname ,catdesc );
982985
983986if (catdesc )
984987values [catdesc -> attidx + ncols - 2 ]=