LCOV - code coverage report
Current view: top level - src/test/modules/test_resowner - test_resowner_basic.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.0 % 84 79
Test Date: 2026-02-28 20:14:43 Functions: 100.0 % 11 11
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*--------------------------------------------------------------------------
       2              :  *
       3              :  * test_resowner_basic.c
       4              :  *      Test basic ResourceOwner functionality
       5              :  *
       6              :  * Copyright (c) 2022-2026, PostgreSQL Global Development Group
       7              :  *
       8              :  * IDENTIFICATION
       9              :  *      src/test/modules/test_resowner/test_resowner_basic.c
      10              :  *
      11              :  * -------------------------------------------------------------------------
      12              :  */
      13              : #include "postgres.h"
      14              : 
      15              : #include "fmgr.h"
      16              : #include "utils/resowner.h"
      17              : 
      18            1 : PG_MODULE_MAGIC;
      19              : 
      20              : static void ReleaseString(Datum res);
      21              : static char *PrintString(Datum res);
      22              : 
      23              : /*
      24              :  * A resource that tracks strings and prints the string when it's released.
      25              :  * This makes the order that the resources are released visible.
      26              :  */
      27              : static const ResourceOwnerDesc string_desc = {
      28              :     .name = "test resource",
      29              :     .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
      30              :     .release_priority = RELEASE_PRIO_FIRST,
      31              :     .ReleaseResource = ReleaseString,
      32              :     .DebugPrint = PrintString
      33              : };
      34              : 
      35              : static void
      36          142 : ReleaseString(Datum res)
      37              : {
      38          142 :     elog(NOTICE, "releasing string: %s", DatumGetCString(res));
      39          142 : }
      40              : 
      41              : static char *
      42            1 : PrintString(Datum res)
      43              : {
      44            1 :     return psprintf("test string \"%s\"", DatumGetCString(res));
      45              : }
      46              : 
      47              : /* demonstrates phases and priorities between a parent and child context */
      48            2 : PG_FUNCTION_INFO_V1(test_resowner_priorities);
      49              : Datum
      50            2 : test_resowner_priorities(PG_FUNCTION_ARGS)
      51              : {
      52            2 :     int32       nkinds = PG_GETARG_INT32(0);
      53            2 :     int32       nresources = PG_GETARG_INT32(1);
      54              :     ResourceOwner parent,
      55              :                 child;
      56              :     ResourceOwnerDesc *before_desc;
      57              :     ResourceOwnerDesc *after_desc;
      58              : 
      59            2 :     if (nkinds <= 0)
      60            0 :         elog(ERROR, "nkinds must be greater than zero");
      61            2 :     if (nresources <= 0)
      62            0 :         elog(ERROR, "nresources must be greater than zero");
      63              : 
      64            2 :     parent = ResourceOwnerCreate(CurrentResourceOwner, "test parent");
      65            2 :     child = ResourceOwnerCreate(parent, "test child");
      66              : 
      67            2 :     before_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
      68            6 :     for (int i = 0; i < nkinds; i++)
      69              :     {
      70            4 :         before_desc[i].name = psprintf("test resource before locks %d", i);
      71            4 :         before_desc[i].release_phase = RESOURCE_RELEASE_BEFORE_LOCKS;
      72            4 :         before_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
      73            4 :         before_desc[i].ReleaseResource = ReleaseString;
      74            4 :         before_desc[i].DebugPrint = PrintString;
      75              :     }
      76            2 :     after_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
      77            6 :     for (int i = 0; i < nkinds; i++)
      78              :     {
      79            4 :         after_desc[i].name = psprintf("test resource after locks %d", i);
      80            4 :         after_desc[i].release_phase = RESOURCE_RELEASE_AFTER_LOCKS;
      81            4 :         after_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
      82            4 :         after_desc[i].ReleaseResource = ReleaseString;
      83            4 :         after_desc[i].DebugPrint = PrintString;
      84              :     }
      85              : 
      86              :     /* Add a bunch of resources to child, with different priorities */
      87           37 :     for (int i = 0; i < nresources; i++)
      88              :     {
      89           35 :         ResourceOwnerDesc *kind = &before_desc[i % nkinds];
      90              : 
      91           35 :         ResourceOwnerEnlarge(child);
      92           35 :         ResourceOwnerRemember(child,
      93           35 :                               CStringGetDatum(psprintf("child before locks priority %d", kind->release_priority)),
      94              :                               kind);
      95              :     }
      96           37 :     for (int i = 0; i < nresources; i++)
      97              :     {
      98           35 :         ResourceOwnerDesc *kind = &after_desc[i % nkinds];
      99              : 
     100           35 :         ResourceOwnerEnlarge(child);
     101           35 :         ResourceOwnerRemember(child,
     102           35 :                               CStringGetDatum(psprintf("child after locks priority %d", kind->release_priority)),
     103              :                               kind);
     104              :     }
     105              : 
     106              :     /* And also to the parent */
     107           37 :     for (int i = 0; i < nresources; i++)
     108              :     {
     109           35 :         ResourceOwnerDesc *kind = &after_desc[i % nkinds];
     110              : 
     111           35 :         ResourceOwnerEnlarge(parent);
     112           35 :         ResourceOwnerRemember(parent,
     113           35 :                               CStringGetDatum(psprintf("parent after locks priority %d", kind->release_priority)),
     114              :                               kind);
     115              :     }
     116           37 :     for (int i = 0; i < nresources; i++)
     117              :     {
     118           35 :         ResourceOwnerDesc *kind = &before_desc[i % nkinds];
     119              : 
     120           35 :         ResourceOwnerEnlarge(parent);
     121           35 :         ResourceOwnerRemember(parent,
     122           35 :                               CStringGetDatum(psprintf("parent before locks priority %d", kind->release_priority)),
     123              :                               kind);
     124              :     }
     125              : 
     126            2 :     elog(NOTICE, "releasing resources before locks");
     127            2 :     ResourceOwnerRelease(parent, RESOURCE_RELEASE_BEFORE_LOCKS, false, false);
     128            2 :     elog(NOTICE, "releasing locks");
     129            2 :     ResourceOwnerRelease(parent, RESOURCE_RELEASE_LOCKS, false, false);
     130            2 :     elog(NOTICE, "releasing resources after locks");
     131            2 :     ResourceOwnerRelease(parent, RESOURCE_RELEASE_AFTER_LOCKS, false, false);
     132              : 
     133            2 :     ResourceOwnerDelete(parent);
     134              : 
     135            2 :     PG_RETURN_VOID();
     136              : }
     137              : 
     138            2 : PG_FUNCTION_INFO_V1(test_resowner_leak);
     139              : Datum
     140            1 : test_resowner_leak(PG_FUNCTION_ARGS)
     141              : {
     142              :     ResourceOwner resowner;
     143              : 
     144            1 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
     145              : 
     146            1 :     ResourceOwnerEnlarge(resowner);
     147              : 
     148            1 :     ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
     149              : 
     150              :     /* don't call ResourceOwnerForget, so that it is leaked */
     151              : 
     152            1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
     153            1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, true, false);
     154            1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_AFTER_LOCKS, true, false);
     155              : 
     156            1 :     ResourceOwnerDelete(resowner);
     157              : 
     158            1 :     PG_RETURN_VOID();
     159              : }
     160              : 
     161            2 : PG_FUNCTION_INFO_V1(test_resowner_remember_between_phases);
     162              : Datum
     163            1 : test_resowner_remember_between_phases(PG_FUNCTION_ARGS)
     164              : {
     165              :     ResourceOwner resowner;
     166              : 
     167            1 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
     168              : 
     169            1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
     170              : 
     171              :     /*
     172              :      * Try to remember a new resource.  Fails because we already called
     173              :      * ResourceOwnerRelease.
     174              :      */
     175            1 :     ResourceOwnerEnlarge(resowner);
     176            0 :     ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
     177              : 
     178              :     /* unreachable */
     179            0 :     elog(ERROR, "ResourceOwnerEnlarge should have errored out");
     180              : 
     181              :     PG_RETURN_VOID();
     182              : }
     183              : 
     184            2 : PG_FUNCTION_INFO_V1(test_resowner_forget_between_phases);
     185              : Datum
     186            1 : test_resowner_forget_between_phases(PG_FUNCTION_ARGS)
     187              : {
     188              :     ResourceOwner resowner;
     189              :     Datum       str_resource;
     190              : 
     191            1 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
     192              : 
     193            1 :     ResourceOwnerEnlarge(resowner);
     194            1 :     str_resource = CStringGetDatum("my string");
     195            1 :     ResourceOwnerRemember(resowner, str_resource, &string_desc);
     196              : 
     197            1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
     198              : 
     199              :     /*
     200              :      * Try to forget the resource that was remembered earlier.  Fails because
     201              :      * we already called ResourceOwnerRelease.
     202              :      */
     203            1 :     ResourceOwnerForget(resowner, str_resource, &string_desc);
     204              : 
     205              :     /* unreachable */
     206            0 :     elog(ERROR, "ResourceOwnerForget should have errored out");
     207              : 
     208              :     PG_RETURN_VOID();
     209              : }
        

Generated by: LCOV version 2.0-1