]> granicus.if.org Git - postgresql/blob - src/backend/utils/mmgr/portalmem.c
Fix macros that were not properly surrounded by parens or braces.
[postgresql] / src / backend / utils / mmgr / portalmem.c
1 /*-------------------------------------------------------------------------
2  *
3  * portalmem.c--
4  *        backend portal memory context management stuff
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.11 1998/06/15 18:39:44 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * NOTES
16  *              Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer").
17  *              When a PQexec() routine is run, the resulting tuples
18  *              find their way into a "PortalEntry".  The contents of the resulting
19  *              "PortalEntry" can then be inspected by other PQxxx functions.
20  *
21  *              A "Portal" is a structure used to keep track of queries of the
22  *              form:
23  *                              retrieve portal FOO ( blah... ) where blah...
24  *
25  *              When the backend sees a "retrieve portal" query, it allocates
26  *              a "PortalD" structure, plans the query and then stores the query
27  *              in the portal without executing it.  Later, when the backend
28  *              sees a
29  *                              fetch 1 into FOO
30  *
31  *              the system looks up the portal named "FOO" in the portal table,
32  *              gets the planned query and then calls the executor with a feature of
33  *              '(EXEC_FOR 1).  The executor then runs the query and returns a single
34  *              tuple.  The problem is that we have to hold onto the state of the
35  *              portal query until we see a "close p".  This means we have to be
36  *              careful about memory management.
37  *
38  *              Having said all that, here is what a PortalD currently looks like:
39  *
40  * struct PortalD {
41  *              char*                                                   name;
42  *              classObj(PortalVariableMemory)  variable;
43  *              classObj(PortalHeapMemory)              heap;
44  *              List                                                    queryDesc;
45  *              EState                                                  state;
46  *              void                                                    (*cleanup) ARGS((Portal portal));
47  * };
48  *
49  *              I hope this makes things clearer to whoever reads this -cim 2/22/91
50  *
51  *              Here is an old comment taken from nodes/memnodes.h
52  *
53  * MemoryContext --
54  *              A logical context in which memory allocations occur.
55  *
56  * The types of memory contexts can be thought of as members of the
57  * following inheritance hierarchy with properties summarized below.
58  *
59  *                                              Node
60  *                                              |
61  *                              MemoryContext___
62  *                              /                               \
63  *              GlobalMemory    PortalMemoryContext
64  *                                              /                               \
65  *              PortalVariableMemory    PortalHeapMemory
66  *
67  *                                              Flushed at              Flushed at              Checkpoints
68  *                                              Transaction             Portal
69  *                                              Commit                  Close
70  *
71  * GlobalMemory                                 n                               n                               n
72  * PortalVariableMemory                 n                               y                               n
73  * PortalHeapMemory                             y                               y                               y *
74  *
75  */
76 #include <stdio.h>                              /* for sprintf() */
77 #include <string.h>                             /* for strlen, strncpy */
78
79 #include "postgres.h"
80
81 #include "lib/hasht.h"
82 #include "utils/module.h"
83 #include "utils/excid.h"                /* for Unimplemented */
84 #include "utils/mcxt.h"
85 #include "utils/hsearch.h"
86
87 #include "nodes/memnodes.h"
88 #include "nodes/nodes.h"
89 #include "nodes/pg_list.h"
90 #include "nodes/execnodes.h"    /* for EState */
91
92 #include "utils/portal.h"
93
94 static void CollectNamedPortals(Portal *portalP, int destroy);
95 static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
96 static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
97 static void PortalResetHeapMemory(Portal portal);
98 static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
99
100 /* ----------------
101  *              ALLOCFREE_ERROR_ABORT
102  *              define this if you want a core dump when you try to
103  *              free memory already freed -cim 2/9/91
104  * ----------------
105  */
106 #undef ALLOCFREE_ERROR_ABORT
107
108 /* ----------------
109  *              Global state
110  * ----------------
111  */
112
113 static int      PortalManagerEnableCount = 0;
114
115 #define MAX_PORTALNAME_LEN              64              /* XXX LONGALIGNable value */
116
117 typedef struct portalhashent
118 {
119         char            portalname[MAX_PORTALNAME_LEN];
120         Portal          portal;
121 } PortalHashEnt;
122
123 #define PortalManagerEnabled    (PortalManagerEnableCount >= 1)
124
125 static HTAB *PortalHashTable = NULL;
126
127 #define PortalHashTableLookup(NAME, PORTAL) \
128 do { \
129         PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
130         \
131         MemSet(key, 0, MAX_PORTALNAME_LEN); \
132         sprintf(key, "%s", NAME); \
133         hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
134                                                                                  key, HASH_FIND, &found); \
135         if (hentry == NULL) \
136                 elog(FATAL, "error in PortalHashTable"); \
137         if (found) \
138                 PORTAL = hentry->portal; \
139         else \
140                 PORTAL = NULL; \
141 } while(0)
142
143 #define PortalHashTableInsert(PORTAL) \
144 do { \
145         PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
146         \
147         MemSet(key, 0, MAX_PORTALNAME_LEN); \
148         sprintf(key, "%s", PORTAL->name); \
149         hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
150                                                                                  key, HASH_ENTER, &found); \
151         if (hentry == NULL) \
152                 elog(FATAL, "error in PortalHashTable"); \
153         if (found) \
154                 elog(NOTICE, "trying to insert a portal name that exists."); \
155         hentry->portal = PORTAL; \
156 } while(0)
157
158 #define PortalHashTableDelete(PORTAL) \
159 { \
160         PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
161         \
162         MemSet(key, 0, MAX_PORTALNAME_LEN); \
163         sprintf(key, "%s", PORTAL->name); \
164         hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
165                                                                                  key, HASH_REMOVE, &found); \
166         if (hentry == NULL) \
167                 elog(FATAL, "error in PortalHashTable"); \
168         if (!found) \
169                 elog(NOTICE, "trying to delete portal name that does not exist."); \
170 } while(0)
171
172 static GlobalMemory PortalMemory = NULL;
173 static char PortalMemoryName[] = "Portal";
174
175 static Portal BlankPortal = NULL;
176
177 /* ----------------
178  *              Internal class definitions
179  * ----------------
180  */
181 typedef struct HeapMemoryBlockData
182 {
183         AllocSetData setData;
184         FixedItemData itemData;
185 } HeapMemoryBlockData;
186
187 typedef HeapMemoryBlockData *HeapMemoryBlock;
188
189 #define HEAPMEMBLOCK(context) \
190         ((HeapMemoryBlock)(context)->block)
191
192 /* ----------------------------------------------------------------
193  *                                Variable and heap memory methods
194  * ----------------------------------------------------------------
195  */
196 /* ----------------
197  *              PortalVariableMemoryAlloc
198  * ----------------
199  */
200 static Pointer
201 PortalVariableMemoryAlloc(PortalVariableMemory this,
202                                                   Size size)
203 {
204         return (AllocSetAlloc(&this->setData, size));
205 }
206
207 /* ----------------
208  *              PortalVariableMemoryFree
209  * ----------------
210  */
211 static void
212 PortalVariableMemoryFree(PortalVariableMemory this,
213                                                  Pointer pointer)
214 {
215         AllocSetFree(&this->setData, pointer);
216 }
217
218 /* ----------------
219  *              PortalVariableMemoryRealloc
220  * ----------------
221  */
222 static Pointer
223 PortalVariableMemoryRealloc(PortalVariableMemory this,
224                                                         Pointer pointer,
225                                                         Size size)
226 {
227         return (AllocSetRealloc(&this->setData, pointer, size));
228 }
229
230 /* ----------------
231  *              PortalVariableMemoryGetName
232  * ----------------
233  */
234 static char *
235 PortalVariableMemoryGetName(PortalVariableMemory this)
236 {
237         return (form("%s-var", PortalVariableMemoryGetPortal(this)->name));
238 }
239
240 /* ----------------
241  *              PortalVariableMemoryDump
242  * ----------------
243  */
244 static void
245 PortalVariableMemoryDump(PortalVariableMemory this)
246 {
247         printf("--\n%s:\n", PortalVariableMemoryGetName(this));
248
249         AllocSetDump(&this->setData);           /* XXX is this the right interface */
250 }
251
252 /* ----------------
253  *              PortalHeapMemoryAlloc
254  * ----------------
255  */
256 static Pointer
257 PortalHeapMemoryAlloc(PortalHeapMemory this,
258                                           Size size)
259 {
260         HeapMemoryBlock block = HEAPMEMBLOCK(this);
261
262         AssertState(PointerIsValid(block));
263
264         return (AllocSetAlloc(&block->setData, size));
265 }
266
267 /* ----------------
268  *              PortalHeapMemoryFree
269  * ----------------
270  */
271 static void
272 PortalHeapMemoryFree(PortalHeapMemory this,
273                                          Pointer pointer)
274 {
275         HeapMemoryBlock block = HEAPMEMBLOCK(this);
276
277         AssertState(PointerIsValid(block));
278
279         if (AllocSetContains(&block->setData, pointer))
280                 AllocSetFree(&block->setData, pointer);
281         else
282         {
283                 elog(NOTICE,
284                          "PortalHeapMemoryFree: 0x%x not in alloc set!",
285                          pointer);
286 #ifdef ALLOCFREE_ERROR_ABORT
287                 Assert(AllocSetContains(&block->setData, pointer));
288 #endif                                                  /* ALLOCFREE_ERROR_ABORT */
289         }
290 }
291
292 /* ----------------
293  *              PortalHeapMemoryRealloc
294  * ----------------
295  */
296 static Pointer
297 PortalHeapMemoryRealloc(PortalHeapMemory this,
298                                                 Pointer pointer,
299                                                 Size size)
300 {
301         HeapMemoryBlock block = HEAPMEMBLOCK(this);
302
303         AssertState(PointerIsValid(block));
304
305         return (AllocSetRealloc(&block->setData, pointer, size));
306 }
307
308 /* ----------------
309  *              PortalHeapMemoryGetName
310  * ----------------
311  */
312 static char *
313 PortalHeapMemoryGetName(PortalHeapMemory this)
314 {
315         return (form("%s-heap", PortalHeapMemoryGetPortal(this)->name));
316 }
317
318 /* ----------------
319  *              PortalHeapMemoryDump
320  * ----------------
321  */
322 static void
323 PortalHeapMemoryDump(PortalHeapMemory this)
324 {
325         HeapMemoryBlock block;
326
327         printf("--\n%s:\n", PortalHeapMemoryGetName(this));
328
329         /* XXX is this the right interface */
330         if (PointerIsValid(this->block))
331                 AllocSetDump(&HEAPMEMBLOCK(this)->setData);
332
333         /* dump the stack too */
334         for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
335                  PointerIsValid(block);
336                  block = (HeapMemoryBlock)
337                  FixedStackGetNext(&this->stackData, (Pointer) block))
338         {
339
340                 printf("--\n");
341                 AllocSetDump(&block->setData);
342         }
343 }
344
345 /* ----------------------------------------------------------------
346  *                              variable / heap context method tables
347  * ----------------------------------------------------------------
348  */
349 static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
350         PortalVariableMemoryAlloc,      /* Pointer (*)(this, uint32)    palloc */
351         PortalVariableMemoryFree,       /* void (*)(this, Pointer)              pfree */
352         PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer)       repalloc */
353         PortalVariableMemoryGetName,/* char* (*)(this)                          getName */
354         PortalVariableMemoryDump        /* void (*)(this)                               dump */
355 };
356
357 static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
358         PortalHeapMemoryAlloc,          /* Pointer (*)(this, uint32)    palloc */
359         PortalHeapMemoryFree,           /* void (*)(this, Pointer)              pfree */
360         PortalHeapMemoryRealloc,        /* Pointer (*)(this, Pointer)   repalloc */
361         PortalHeapMemoryGetName,        /* char* (*)(this)                              getName */
362         PortalHeapMemoryDump            /* void (*)(this)                               dump */
363 };
364
365
366 /* ----------------------------------------------------------------
367  *                                private internal support routines
368  * ----------------------------------------------------------------
369  */
370 /* ----------------
371  *              CreateNewBlankPortal
372  * ----------------
373  */
374 static void
375 CreateNewBlankPortal()
376 {
377         Portal          portal;
378
379         AssertState(!PortalIsValid(BlankPortal));
380
381         /*
382          * make new portal structure
383          */
384         portal = (Portal)
385                 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
386
387         /*
388          * initialize portal variable context
389          */
390         NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
391         AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
392         portal->variable.method = &PortalVariableContextMethodsData;
393
394         /*
395          * initialize portal heap context
396          */
397         NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
398         portal->heap.block = NULL;
399         FixedStackInit(&portal->heap.stackData,
400                                    offsetof(HeapMemoryBlockData, itemData));
401         portal->heap.method = &PortalHeapContextMethodsData;
402
403         /*
404          * set bogus portal name
405          */
406         portal->name = "** Blank Portal **";
407
408         /* initialize portal query */
409         portal->queryDesc = NULL;
410         portal->attinfo = NULL;
411         portal->state = NULL;
412         portal->cleanup = NULL;
413
414         /*
415          * install blank portal
416          */
417         BlankPortal = portal;
418 }
419
420 bool
421 PortalNameIsSpecial(char *pname)
422 {
423         if (strcmp(pname, VACPNAME) == 0)
424                 return true;
425         return false;
426 }
427
428 /*
429  * This routine is used to collect all portals created in this xaction
430  * and then destroy them.  There is a little trickiness required as a
431  * result of the dynamic hashing interface to getting every hash entry
432  * sequentially.  Its use of static variables requires that we get every
433  * entry *before* we destroy anything (destroying updates the hashtable
434  * and screws up the sequential walk of the table). -mer 17 Aug 1992
435  */
436 static void
437 CollectNamedPortals(Portal *portalP, int destroy)
438 {
439         static Portal *portalList = (Portal *) NULL;
440         static int      listIndex = 0;
441         static int      maxIndex = 9;
442
443         if (portalList == (Portal *) NULL)
444                 portalList = (Portal *) malloc(10 * sizeof(Portal));
445
446         if (destroy != 0)
447         {
448                 int                     i;
449
450                 for (i = 0; i < listIndex; i++)
451                         PortalDestroy(&portalList[i]);
452                 listIndex = 0;
453         }
454         else
455         {
456                 Assert(portalP);
457                 Assert(*portalP);
458
459                 /*
460                  * Don't delete special portals, up to portal creator to do this
461                  */
462                 if (PortalNameIsSpecial((*portalP)->name))
463                         return;
464
465                 portalList[listIndex] = *portalP;
466                 listIndex++;
467                 if (listIndex == maxIndex)
468                 {
469                         portalList = (Portal *)
470                                 realloc(portalList, (maxIndex + 11) * sizeof(Portal));
471                         maxIndex += 10;
472                 }
473         }
474         return;
475 }
476
477 void
478 AtEOXact_portals()
479 {
480         HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
481         CollectNamedPortals(NULL, 1);
482 }
483
484 /* ----------------
485  *              PortalDump
486  * ----------------
487  */
488 #ifdef NOT_USED
489 static void
490 PortalDump(Portal *thisP)
491 {
492         /* XXX state/argument checking here */
493
494         PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
495         PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
496 }
497
498 #endif
499
500 /* ----------------
501  *              DumpPortals
502  * ----------------
503  */
504 #ifdef NOT_USED
505 static void
506 DumpPortals()
507 {
508         /* XXX state checking here */
509
510         HashTableWalk(PortalHashTable, PortalDump, 0);
511 }
512
513 #endif
514
515 /* ----------------------------------------------------------------
516  *                                 public portal interface functions
517  * ----------------------------------------------------------------
518  */
519 /*
520  * EnablePortalManager --
521  *              Enables/disables the portal management module.
522  */
523 void
524 EnablePortalManager(bool on)
525 {
526         static bool processing = false;
527         HASHCTL         ctl;
528
529         AssertState(!processing);
530         AssertArg(BoolIsValid(on));
531
532         if (BypassEnable(&PortalManagerEnableCount, on))
533                 return;
534
535         processing = true;
536
537         if (on)
538         {                                                       /* initialize */
539                 EnableMemoryContext(true);
540
541                 PortalMemory = CreateGlobalMemory(PortalMemoryName);
542
543                 ctl.keysize = MAX_PORTALNAME_LEN;
544                 ctl.datasize = sizeof(Portal);
545
546                 /*
547                  * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
548                  * how many hash table entries to create, initially
549                  */
550                 PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
551
552                 CreateNewBlankPortal();
553
554         }
555         else
556         {                                                       /* cleanup */
557                 if (PortalIsValid(BlankPortal))
558                 {
559                         PortalDestroy(&BlankPortal);
560                         MemoryContextFree((MemoryContext) PortalMemory,
561                                                           (Pointer) BlankPortal);
562                         BlankPortal = NULL;
563                 }
564
565                 /*
566                  * Each portal must free its non-memory resources specially.
567                  */
568                 HashTableWalk(PortalHashTable, PortalDestroy, 0);
569                 hash_destroy(PortalHashTable);
570                 PortalHashTable = NULL;
571
572                 GlobalMemoryDestroy(PortalMemory);
573                 PortalMemory = NULL;
574
575                 EnableMemoryContext(true);
576         }
577
578         processing = false;
579 }
580
581 /*
582  * GetPortalByName --
583  *              Returns a portal given a portal name; returns blank portal given
584  * NULL; returns invalid portal if portal not found.
585  *
586  * Exceptions:
587  *              BadState if called when disabled.
588  */
589 Portal
590 GetPortalByName(char *name)
591 {
592         Portal          portal;
593
594         AssertState(PortalManagerEnabled);
595
596         if (PointerIsValid(name))
597         {
598                 PortalHashTableLookup(name, portal);
599         }
600         else
601         {
602                 if (!PortalIsValid(BlankPortal))
603                         CreateNewBlankPortal();
604                 portal = BlankPortal;
605         }
606
607         return (portal);
608 }
609
610 /*
611  * BlankPortalAssignName --
612  *              Returns former blank portal as portal with given name.
613  *
614  * Side effect:
615  *              All references to the former blank portal become incorrect.
616  *
617  * Exceptions:
618  *              BadState if called when disabled.
619  *              BadState if called without an intervening call to GetPortalByName(NULL).
620  *              BadArg if portal name is invalid.
621  *              "WARN" if portal name is in use.
622  */
623 Portal
624 BlankPortalAssignName(char *name)               /* XXX PortalName */
625 {
626         Portal          portal;
627         uint16          length;
628
629         AssertState(PortalManagerEnabled);
630         AssertState(PortalIsValid(BlankPortal));
631         AssertArg(PointerIsValid(name));        /* XXX PortalName */
632
633         portal = GetPortalByName(name);
634         if (PortalIsValid(portal))
635         {
636                 elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
637                 return (portal);
638         }
639
640         /*
641          * remove blank portal
642          */
643         portal = BlankPortal;
644         BlankPortal = NULL;
645
646         /*
647          * initialize portal name
648          */
649         length = 1 + strlen(name);
650         portal->name = (char *)
651                 MemoryContextAlloc((MemoryContext) &portal->variable, length);
652
653         strncpy(portal->name, name, length);
654
655         /*
656          * put portal in table
657          */
658         PortalHashTableInsert(portal);
659
660         return (portal);
661 }
662
663 /*
664  * PortalSetQuery --
665  *              Attaches a "query" to portal.
666  *
667  * Exceptions:
668  *              BadState if called when disabled.
669  *              BadArg if portal is invalid.
670  *              BadArg if queryDesc is "invalid."
671  *              BadArg if state is "invalid."
672  */
673 void
674 PortalSetQuery(Portal portal,
675                            QueryDesc *queryDesc,
676                            TupleDesc attinfo,
677                            EState *state,
678                            void (*cleanup) (Portal portal))
679 {
680         AssertState(PortalManagerEnabled);
681         AssertArg(PortalIsValid(portal));
682         AssertArg(IsA((Node *) state, EState));
683
684         portal->queryDesc = queryDesc;
685         portal->state = state;
686         portal->attinfo = attinfo;
687         portal->cleanup = cleanup;
688 }
689
690 /*
691  * PortalGetQueryDesc --
692  *              Returns query attached to portal.
693  *
694  * Exceptions:
695  *              BadState if called when disabled.
696  *              BadArg if portal is invalid.
697  */
698 QueryDesc  *
699 PortalGetQueryDesc(Portal portal)
700 {
701         AssertState(PortalManagerEnabled);
702         AssertArg(PortalIsValid(portal));
703
704         return (portal->queryDesc);
705 }
706
707 /*
708  * PortalGetState --
709  *              Returns state attached to portal.
710  *
711  * Exceptions:
712  *              BadState if called when disabled.
713  *              BadArg if portal is invalid.
714  */
715 EState *
716 PortalGetState(Portal portal)
717 {
718         AssertState(PortalManagerEnabled);
719         AssertArg(PortalIsValid(portal));
720
721         return (portal->state);
722 }
723
724 /*
725  * CreatePortal --
726  *              Returns a new portal given a name.
727  *
728  * Note:
729  *              This is expected to be of very limited usability.  See instead,
730  * BlankPortalAssignName.
731  *
732  * Exceptions:
733  *              BadState if called when disabled.
734  *              BadArg if portal name is invalid.
735  *              "WARN" if portal name is in use.
736  */
737 Portal
738 CreatePortal(char *name)                /* XXX PortalName */
739 {
740         Portal          portal;
741         uint16          length;
742
743         AssertState(PortalManagerEnabled);
744         AssertArg(PointerIsValid(name));        /* XXX PortalName */
745
746         portal = GetPortalByName(name);
747         if (PortalIsValid(portal))
748         {
749                 elog(NOTICE, "CreatePortal: portal %s already exists", name);
750                 return (portal);
751         }
752
753         /* make new portal structure */
754         portal = (Portal)
755                 MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
756
757         /* initialize portal variable context */
758         NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
759         AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
760         portal->variable.method = &PortalVariableContextMethodsData;
761
762         /* initialize portal heap context */
763         NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
764         portal->heap.block = NULL;
765         FixedStackInit(&portal->heap.stackData,
766                                    offsetof(HeapMemoryBlockData, itemData));
767         portal->heap.method = &PortalHeapContextMethodsData;
768
769         /* initialize portal name */
770         length = 1 + strlen(name);
771         portal->name = (char *)
772                 MemoryContextAlloc((MemoryContext) &portal->variable, length);
773         strncpy(portal->name, name, length);
774
775         /* initialize portal query */
776         portal->queryDesc = NULL;
777         portal->attinfo = NULL;
778         portal->state = NULL;
779         portal->cleanup = NULL;
780
781         /* put portal in table */
782         PortalHashTableInsert(portal);
783
784         /* Trap(PointerIsValid(name), Unimplemented); */
785         return (portal);
786 }
787
788 /*
789  * PortalDestroy --
790  *              Destroys portal.
791  *
792  * Exceptions:
793  *              BadState if called when disabled.
794  *              BadArg if portal is invalid.
795  */
796 void
797 PortalDestroy(Portal *portalP)
798 {
799         Portal          portal = *portalP;
800
801         AssertState(PortalManagerEnabled);
802         AssertArg(PortalIsValid(portal));
803
804         /* remove portal from table if not blank portal */
805         if (portal != BlankPortal)
806                 PortalHashTableDelete(portal);
807
808         /* reset portal */
809         if (PointerIsValid(portal->cleanup))
810                 (*portal->cleanup) (portal);
811
812         PortalResetHeapMemory(portal);
813         MemoryContextFree((MemoryContext) &portal->variable,
814                                           (Pointer) portal->name);
815         AllocSetReset(&portal->variable.setData);       /* XXX log */
816
817         if (portal != BlankPortal)
818                 MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
819 }
820
821 /* ----------------
822  *              PortalResetHeapMemory --
823  *                              Resets portal's heap memory context.
824  *
825  * Someday, Reset, Start, and End can be optimized by keeping a global
826  * portal module stack of free HeapMemoryBlock's.  This will make Start
827  * and End be fast.
828  *
829  * Exceptions:
830  *              BadState if called when disabled.
831  *              BadState if called when not in PortalHeapMemory context.
832  *              BadArg if mode is invalid.
833  * ----------------
834  */
835 static void
836 PortalResetHeapMemory(Portal portal)
837 {
838         PortalHeapMemory context;
839         MemoryContext currentContext;
840
841         context = PortalGetHeapMemory(portal);
842
843         if (PointerIsValid(context->block))
844         {
845                 /* save present context */
846                 currentContext = MemoryContextSwitchTo((MemoryContext) context);
847
848                 do
849                 {
850                         EndPortalAllocMode();
851                 } while (PointerIsValid(context->block));
852
853                 /* restore context */
854                 MemoryContextSwitchTo(currentContext);
855         }
856 }
857
858 /*
859  * StartPortalAllocMode --
860  *              Starts a new block of portal heap allocation using mode and limit;
861  *              the current block is disabled until EndPortalAllocMode is called.
862  *
863  * Note:
864  *              Note blocks may be stacked and restored arbitarily.
865  *              The semantics of mode and limit are described in aset.h.
866  *
867  * Exceptions:
868  *              BadState if called when disabled.
869  *              BadState if called when not in PortalHeapMemory context.
870  *              BadArg if mode is invalid.
871  */
872 void
873 StartPortalAllocMode(AllocMode mode, Size limit)
874 {
875         PortalHeapMemory context;
876
877         AssertState(PortalManagerEnabled);
878         AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
879         /* AssertArg(AllocModeIsValid); */
880
881         context = (PortalHeapMemory) CurrentMemoryContext;
882
883         /* stack current mode */
884         if (PointerIsValid(context->block))
885                 FixedStackPush(&context->stackData, context->block);
886
887         /* allocate and initialize new block */
888         context->block =
889                 MemoryContextAlloc(
890                           (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
891                                                    sizeof(HeapMemoryBlockData));
892
893         /* XXX careful, context->block has never been stacked => bad state */
894
895         AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
896 }
897
898 /*
899  * EndPortalAllocMode --
900  *              Ends current block of portal heap allocation; previous block is
901  *              reenabled.
902  *
903  * Note:
904  *              Note blocks may be stacked and restored arbitarily.
905  *
906  * Exceptions:
907  *              BadState if called when disabled.
908  *              BadState if called when not in PortalHeapMemory context.
909  */
910 void
911 EndPortalAllocMode()
912 {
913         PortalHeapMemory context;
914
915         AssertState(PortalManagerEnabled);
916         AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
917
918         context = (PortalHeapMemory) CurrentMemoryContext;
919         AssertState(PointerIsValid(context->block));            /* XXX Trap(...) */
920
921         /* free current mode */
922         AllocSetReset(&HEAPMEMBLOCK(context)->setData);
923         MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
924                                           context->block);
925
926         /* restore previous mode */
927         context->block = FixedStackPop(&context->stackData);
928 }
929
930 /*
931  * PortalGetVariableMemory --
932  *              Returns variable memory context for a given portal.
933  *
934  * Exceptions:
935  *              BadState if called when disabled.
936  *              BadArg if portal is invalid.
937  */
938 PortalVariableMemory
939 PortalGetVariableMemory(Portal portal)
940 {
941         return (&portal->variable);
942 }
943
944 /*
945  * PortalGetHeapMemory --
946  *              Returns heap memory context for a given portal.
947  *
948  * Exceptions:
949  *              BadState if called when disabled.
950  *              BadArg if portal is invalid.
951  */
952 PortalHeapMemory
953 PortalGetHeapMemory(Portal portal)
954 {
955         return (&portal->heap);
956 }
957
958 /*
959  * PortalVariableMemoryGetPortal --
960  *              Returns portal containing given variable memory context.
961  *
962  * Exceptions:
963  *              BadState if called when disabled.
964  *              BadArg if context is invalid.
965  */
966 static Portal
967 PortalVariableMemoryGetPortal(PortalVariableMemory context)
968 {
969         return ((Portal) ((char *) context - offsetof(PortalD, variable)));
970 }
971
972 /*
973  * PortalHeapMemoryGetPortal --
974  *              Returns portal containing given heap memory context.
975  *
976  * Exceptions:
977  *              BadState if called when disabled.
978  *              BadArg if context is invalid.
979  */
980 static Portal
981 PortalHeapMemoryGetPortal(PortalHeapMemory context)
982 {
983         return ((Portal) ((char *) context - offsetof(PortalD, heap)));
984 }
985
986 /*
987  * PortalVariableMemoryGetHeapMemory --
988  *              Returns heap memory context associated with given variable memory.
989  *
990  * Exceptions:
991  *              BadState if called when disabled.
992  *              BadArg if context is invalid.
993  */
994 #ifdef NOT_USED
995 PortalHeapMemory
996 PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
997 {
998         return ((PortalHeapMemory) ((char *) context
999                                                                 - offsetof(PortalD, variable)
1000                                                                 +offsetof(PortalD, heap)));
1001 }
1002
1003 #endif
1004
1005 /*
1006  * PortalHeapMemoryGetVariableMemory --
1007  *              Returns variable memory context associated with given heap memory.
1008  *
1009  * Exceptions:
1010  *              BadState if called when disabled.
1011  *              BadArg if context is invalid.
1012  */
1013 static PortalVariableMemory
1014 PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
1015 {
1016         return ((PortalVariableMemory) ((char *) context
1017                                                                         - offsetof(PortalD, heap)
1018                                                                         +offsetof(PortalD, variable)));
1019 }