LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pg_upgrade_support.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 91.6 % 154 141
Test Date: 2026-02-28 13:14:45 Functions: 95.0 % 20 19
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  *  pg_upgrade_support.c
       3              :  *
       4              :  *  server-side functions to set backend global variables
       5              :  *  to control oid and relfilenumber assignment, and do other special
       6              :  *  hacks needed for pg_upgrade.
       7              :  *
       8              :  *  Copyright (c) 2010-2026, PostgreSQL Global Development Group
       9              :  *  src/backend/utils/adt/pg_upgrade_support.c
      10              :  */
      11              : 
      12              : #include "postgres.h"
      13              : 
      14              : #include "access/relation.h"
      15              : #include "access/table.h"
      16              : #include "catalog/binary_upgrade.h"
      17              : #include "catalog/heap.h"
      18              : #include "catalog/namespace.h"
      19              : #include "catalog/pg_subscription_rel.h"
      20              : #include "catalog/pg_type.h"
      21              : #include "commands/extension.h"
      22              : #include "miscadmin.h"
      23              : #include "replication/logical.h"
      24              : #include "replication/logicallauncher.h"
      25              : #include "replication/origin.h"
      26              : #include "replication/worker_internal.h"
      27              : #include "storage/lmgr.h"
      28              : #include "utils/array.h"
      29              : #include "utils/builtins.h"
      30              : #include "utils/lsyscache.h"
      31              : #include "utils/pg_lsn.h"
      32              : 
      33              : 
      34              : #define CHECK_IS_BINARY_UPGRADE                                 \
      35              : do {                                                            \
      36              :     if (!IsBinaryUpgrade)                                       \
      37              :         ereport(ERROR,                                          \
      38              :                 (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),    \
      39              :                  errmsg("function can only be called when server is in binary upgrade mode"))); \
      40              : } while (0)
      41              : 
      42              : Datum
      43            4 : binary_upgrade_set_next_pg_tablespace_oid(PG_FUNCTION_ARGS)
      44              : {
      45            4 :     Oid         tbspoid = PG_GETARG_OID(0);
      46              : 
      47            4 :     CHECK_IS_BINARY_UPGRADE;
      48            4 :     binary_upgrade_next_pg_tablespace_oid = tbspoid;
      49              : 
      50            4 :     PG_RETURN_VOID();
      51              : }
      52              : 
      53              : Datum
      54          875 : binary_upgrade_set_next_pg_type_oid(PG_FUNCTION_ARGS)
      55              : {
      56          875 :     Oid         typoid = PG_GETARG_OID(0);
      57              : 
      58          875 :     CHECK_IS_BINARY_UPGRADE;
      59          875 :     binary_upgrade_next_pg_type_oid = typoid;
      60              : 
      61          875 :     PG_RETURN_VOID();
      62              : }
      63              : 
      64              : Datum
      65          874 : binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS)
      66              : {
      67          874 :     Oid         typoid = PG_GETARG_OID(0);
      68              : 
      69          874 :     CHECK_IS_BINARY_UPGRADE;
      70          874 :     binary_upgrade_next_array_pg_type_oid = typoid;
      71              : 
      72          874 :     PG_RETURN_VOID();
      73              : }
      74              : 
      75              : Datum
      76            6 : binary_upgrade_set_next_multirange_pg_type_oid(PG_FUNCTION_ARGS)
      77              : {
      78            6 :     Oid         typoid = PG_GETARG_OID(0);
      79              : 
      80            6 :     CHECK_IS_BINARY_UPGRADE;
      81            6 :     binary_upgrade_next_mrng_pg_type_oid = typoid;
      82              : 
      83            6 :     PG_RETURN_VOID();
      84              : }
      85              : 
      86              : Datum
      87            6 : binary_upgrade_set_next_multirange_array_pg_type_oid(PG_FUNCTION_ARGS)
      88              : {
      89            6 :     Oid         typoid = PG_GETARG_OID(0);
      90              : 
      91            6 :     CHECK_IS_BINARY_UPGRADE;
      92            6 :     binary_upgrade_next_mrng_array_pg_type_oid = typoid;
      93              : 
      94            6 :     PG_RETURN_VOID();
      95              : }
      96              : 
      97              : Datum
      98          883 : binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS)
      99              : {
     100          883 :     Oid         reloid = PG_GETARG_OID(0);
     101              : 
     102          883 :     CHECK_IS_BINARY_UPGRADE;
     103          883 :     binary_upgrade_next_heap_pg_class_oid = reloid;
     104              : 
     105          883 :     PG_RETURN_VOID();
     106              : }
     107              : 
     108              : Datum
     109          787 : binary_upgrade_set_next_heap_relfilenode(PG_FUNCTION_ARGS)
     110              : {
     111          787 :     RelFileNumber relfilenumber = PG_GETARG_OID(0);
     112              : 
     113          787 :     CHECK_IS_BINARY_UPGRADE;
     114          787 :     binary_upgrade_next_heap_pg_class_relfilenumber = relfilenumber;
     115              : 
     116          787 :     PG_RETURN_VOID();
     117              : }
     118              : 
     119              : Datum
     120          557 : binary_upgrade_set_next_index_pg_class_oid(PG_FUNCTION_ARGS)
     121              : {
     122          557 :     Oid         reloid = PG_GETARG_OID(0);
     123              : 
     124          557 :     CHECK_IS_BINARY_UPGRADE;
     125          557 :     binary_upgrade_next_index_pg_class_oid = reloid;
     126              : 
     127          557 :     PG_RETURN_VOID();
     128              : }
     129              : 
     130              : Datum
     131          617 : binary_upgrade_set_next_index_relfilenode(PG_FUNCTION_ARGS)
     132              : {
     133          617 :     RelFileNumber relfilenumber = PG_GETARG_OID(0);
     134              : 
     135          617 :     CHECK_IS_BINARY_UPGRADE;
     136          617 :     binary_upgrade_next_index_pg_class_relfilenumber = relfilenumber;
     137              : 
     138          617 :     PG_RETURN_VOID();
     139              : }
     140              : 
     141              : Datum
     142          270 : binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS)
     143              : {
     144          270 :     Oid         reloid = PG_GETARG_OID(0);
     145              : 
     146          270 :     CHECK_IS_BINARY_UPGRADE;
     147          270 :     binary_upgrade_next_toast_pg_class_oid = reloid;
     148              : 
     149          270 :     PG_RETURN_VOID();
     150              : }
     151              : 
     152              : Datum
     153          270 : binary_upgrade_set_next_toast_relfilenode(PG_FUNCTION_ARGS)
     154              : {
     155          270 :     RelFileNumber relfilenumber = PG_GETARG_OID(0);
     156              : 
     157          270 :     CHECK_IS_BINARY_UPGRADE;
     158          270 :     binary_upgrade_next_toast_pg_class_relfilenumber = relfilenumber;
     159              : 
     160          270 :     PG_RETURN_VOID();
     161              : }
     162              : 
     163              : Datum
     164           50 : binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS)
     165              : {
     166           50 :     Oid         enumoid = PG_GETARG_OID(0);
     167              : 
     168           50 :     CHECK_IS_BINARY_UPGRADE;
     169           50 :     binary_upgrade_next_pg_enum_oid = enumoid;
     170              : 
     171           50 :     PG_RETURN_VOID();
     172              : }
     173              : 
     174              : Datum
     175           17 : binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS)
     176              : {
     177           17 :     Oid         authoid = PG_GETARG_OID(0);
     178              : 
     179           17 :     CHECK_IS_BINARY_UPGRADE;
     180           17 :     binary_upgrade_next_pg_authid_oid = authoid;
     181           17 :     PG_RETURN_VOID();
     182              : }
     183              : 
     184              : Datum
     185            4 : binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)
     186              : {
     187              :     text       *extName;
     188              :     text       *schemaName;
     189              :     bool        relocatable;
     190              :     text       *extVersion;
     191              :     Datum       extConfig;
     192              :     Datum       extCondition;
     193              :     List       *requiredExtensions;
     194              : 
     195            4 :     CHECK_IS_BINARY_UPGRADE;
     196              : 
     197              :     /* We must check these things before dereferencing the arguments */
     198            4 :     if (PG_ARGISNULL(0) ||
     199            4 :         PG_ARGISNULL(1) ||
     200            4 :         PG_ARGISNULL(2) ||
     201            4 :         PG_ARGISNULL(3))
     202            0 :         elog(ERROR, "null argument to binary_upgrade_create_empty_extension is not allowed");
     203              : 
     204            4 :     extName = PG_GETARG_TEXT_PP(0);
     205            4 :     schemaName = PG_GETARG_TEXT_PP(1);
     206            4 :     relocatable = PG_GETARG_BOOL(2);
     207            4 :     extVersion = PG_GETARG_TEXT_PP(3);
     208              : 
     209            4 :     if (PG_ARGISNULL(4))
     210            4 :         extConfig = PointerGetDatum(NULL);
     211              :     else
     212            0 :         extConfig = PG_GETARG_DATUM(4);
     213              : 
     214            4 :     if (PG_ARGISNULL(5))
     215            4 :         extCondition = PointerGetDatum(NULL);
     216              :     else
     217            0 :         extCondition = PG_GETARG_DATUM(5);
     218              : 
     219            4 :     requiredExtensions = NIL;
     220            4 :     if (!PG_ARGISNULL(6))
     221              :     {
     222            4 :         ArrayType  *textArray = PG_GETARG_ARRAYTYPE_P(6);
     223              :         Datum      *textDatums;
     224              :         int         ndatums;
     225              :         int         i;
     226              : 
     227            4 :         deconstruct_array_builtin(textArray, TEXTOID, &textDatums, NULL, &ndatums);
     228            4 :         for (i = 0; i < ndatums; i++)
     229              :         {
     230            0 :             char       *extName = TextDatumGetCString(textDatums[i]);
     231            0 :             Oid         extOid = get_extension_oid(extName, false);
     232              : 
     233            0 :             requiredExtensions = lappend_oid(requiredExtensions, extOid);
     234              :         }
     235              :     }
     236              : 
     237            4 :     InsertExtensionTuple(text_to_cstring(extName),
     238              :                          GetUserId(),
     239            4 :                          get_namespace_oid(text_to_cstring(schemaName), false),
     240              :                          relocatable,
     241            4 :                          text_to_cstring(extVersion),
     242              :                          extConfig,
     243              :                          extCondition,
     244              :                          requiredExtensions);
     245              : 
     246            4 :     PG_RETURN_VOID();
     247              : }
     248              : 
     249              : Datum
     250            0 : binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS)
     251              : {
     252            0 :     bool        record_init_privs = PG_GETARG_BOOL(0);
     253              : 
     254            0 :     CHECK_IS_BINARY_UPGRADE;
     255            0 :     binary_upgrade_record_init_privs = record_init_privs;
     256              : 
     257            0 :     PG_RETURN_VOID();
     258              : }
     259              : 
     260              : Datum
     261            3 : binary_upgrade_set_missing_value(PG_FUNCTION_ARGS)
     262              : {
     263            3 :     Oid         table_id = PG_GETARG_OID(0);
     264            3 :     text       *attname = PG_GETARG_TEXT_P(1);
     265            3 :     text       *value = PG_GETARG_TEXT_P(2);
     266            3 :     char       *cattname = text_to_cstring(attname);
     267            3 :     char       *cvalue = text_to_cstring(value);
     268              : 
     269            3 :     CHECK_IS_BINARY_UPGRADE;
     270            3 :     SetAttrMissing(table_id, cattname, cvalue);
     271              : 
     272            3 :     PG_RETURN_VOID();
     273              : }
     274              : 
     275              : /*
     276              :  * Verify the given slot has already consumed all the WAL changes.
     277              :  *
     278              :  * Returns true if there are no decodable WAL records after the
     279              :  * confirmed_flush_lsn. Otherwise false.
     280              :  *
     281              :  * This is a special purpose function to ensure that the given slot can be
     282              :  * upgraded without data loss.
     283              :  */
     284              : Datum
     285            3 : binary_upgrade_check_logical_slot_pending_wal(PG_FUNCTION_ARGS)
     286              : {
     287              :     Name        slot_name;
     288              :     XLogRecPtr  end_of_wal;
     289              :     XLogRecPtr  scan_cutoff_lsn;
     290              :     XLogRecPtr  last_pending_wal;
     291              : 
     292            3 :     CHECK_IS_BINARY_UPGRADE;
     293              : 
     294              :     /*
     295              :      * Binary upgrades only allowed super-user connections so we must have
     296              :      * permission to use replication slots.
     297              :      */
     298              :     Assert(has_rolreplication(GetUserId()));
     299              : 
     300            3 :     slot_name = PG_GETARG_NAME(0);
     301            3 :     scan_cutoff_lsn = PG_GETARG_LSN(1);
     302              : 
     303              :     /* Acquire the given slot */
     304            3 :     ReplicationSlotAcquire(NameStr(*slot_name), true, true);
     305              : 
     306              :     Assert(SlotIsLogical(MyReplicationSlot));
     307              : 
     308              :     /* Slots must be valid as otherwise we won't be able to scan the WAL */
     309              :     Assert(MyReplicationSlot->data.invalidated == RS_INVAL_NONE);
     310              : 
     311            3 :     end_of_wal = GetFlushRecPtr(NULL);
     312            3 :     last_pending_wal = LogicalReplicationSlotCheckPendingWal(end_of_wal,
     313              :                                                              scan_cutoff_lsn);
     314              : 
     315              :     /* Clean up */
     316            3 :     ReplicationSlotRelease();
     317              : 
     318            3 :     if (XLogRecPtrIsValid(last_pending_wal))
     319            1 :         PG_RETURN_LSN(last_pending_wal);
     320              :     else
     321            2 :         PG_RETURN_NULL();
     322              : }
     323              : 
     324              : /*
     325              :  * binary_upgrade_add_sub_rel_state
     326              :  *
     327              :  * Add the relation with the specified relation state to pg_subscription_rel
     328              :  * catalog.
     329              :  */
     330              : Datum
     331            3 : binary_upgrade_add_sub_rel_state(PG_FUNCTION_ARGS)
     332              : {
     333              :     Relation    subrel;
     334              :     Relation    rel;
     335              :     Oid         subid;
     336              :     char       *subname;
     337              :     Oid         relid;
     338              :     char        relstate;
     339              :     XLogRecPtr  sublsn;
     340              : 
     341            3 :     CHECK_IS_BINARY_UPGRADE;
     342              : 
     343              :     /* We must check these things before dereferencing the arguments */
     344            3 :     if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
     345            0 :         elog(ERROR, "null argument to binary_upgrade_add_sub_rel_state is not allowed");
     346              : 
     347            3 :     subname = text_to_cstring(PG_GETARG_TEXT_PP(0));
     348            3 :     relid = PG_GETARG_OID(1);
     349            3 :     relstate = PG_GETARG_CHAR(2);
     350            3 :     sublsn = PG_ARGISNULL(3) ? InvalidXLogRecPtr : PG_GETARG_LSN(3);
     351              : 
     352            3 :     subrel = table_open(SubscriptionRelationId, RowExclusiveLock);
     353            3 :     subid = get_subscription_oid(subname, false);
     354            3 :     rel = relation_open(relid, AccessShareLock);
     355              : 
     356              :     /*
     357              :      * Since there are no concurrent ALTER/DROP SUBSCRIPTION commands during
     358              :      * the upgrade process, and the apply worker (which builds cache based on
     359              :      * the subscription catalog) is not running, the locks can be released
     360              :      * immediately.
     361              :      */
     362            3 :     AddSubscriptionRelState(subid, relid, relstate, sublsn, false);
     363            3 :     relation_close(rel, AccessShareLock);
     364            3 :     table_close(subrel, RowExclusiveLock);
     365              : 
     366            3 :     PG_RETURN_VOID();
     367              : }
     368              : 
     369              : /*
     370              :  * binary_upgrade_replorigin_advance
     371              :  *
     372              :  * Update the remote_lsn for the subscriber's replication origin.
     373              :  */
     374              : Datum
     375            1 : binary_upgrade_replorigin_advance(PG_FUNCTION_ARGS)
     376              : {
     377              :     Relation    rel;
     378              :     Oid         subid;
     379              :     char       *subname;
     380              :     char        originname[NAMEDATALEN];
     381              :     ReplOriginId node;
     382              :     XLogRecPtr  remote_commit;
     383              : 
     384            1 :     CHECK_IS_BINARY_UPGRADE;
     385              : 
     386              :     /*
     387              :      * We must ensure a non-NULL subscription name before dereferencing the
     388              :      * arguments.
     389              :      */
     390            1 :     if (PG_ARGISNULL(0))
     391            0 :         elog(ERROR, "null argument to binary_upgrade_replorigin_advance is not allowed");
     392              : 
     393            1 :     subname = text_to_cstring(PG_GETARG_TEXT_PP(0));
     394            1 :     remote_commit = PG_ARGISNULL(1) ? InvalidXLogRecPtr : PG_GETARG_LSN(1);
     395              : 
     396            1 :     rel = table_open(SubscriptionRelationId, RowExclusiveLock);
     397            1 :     subid = get_subscription_oid(subname, false);
     398              : 
     399            1 :     ReplicationOriginNameForLogicalRep(subid, InvalidOid, originname, sizeof(originname));
     400              : 
     401              :     /* Lock to prevent the replication origin from vanishing */
     402            1 :     LockRelationOid(ReplicationOriginRelationId, RowExclusiveLock);
     403            1 :     node = replorigin_by_name(originname, false);
     404              : 
     405              :     /*
     406              :      * The server will be stopped after setting up the objects in the new
     407              :      * cluster and the origins will be flushed during the shutdown checkpoint.
     408              :      * This will ensure that the latest LSN values for origin will be
     409              :      * available after the upgrade.
     410              :      */
     411            1 :     replorigin_advance(node, remote_commit, InvalidXLogRecPtr,
     412              :                        false /* backward */ ,
     413              :                        false /* WAL log */ );
     414              : 
     415            1 :     UnlockRelationOid(ReplicationOriginRelationId, RowExclusiveLock);
     416            1 :     table_close(rel, RowExclusiveLock);
     417              : 
     418            1 :     PG_RETURN_VOID();
     419              : }
     420              : 
     421              : /*
     422              :  * binary_upgrade_create_conflict_detection_slot
     423              :  *
     424              :  * Create a replication slot to retain information necessary for conflict
     425              :  * detection such as dead tuples, commit timestamps, and origins.
     426              :  */
     427              : Datum
     428            1 : binary_upgrade_create_conflict_detection_slot(PG_FUNCTION_ARGS)
     429              : {
     430            1 :     CHECK_IS_BINARY_UPGRADE;
     431              : 
     432            1 :     CreateConflictDetectionSlot();
     433              : 
     434            1 :     ReplicationSlotRelease();
     435              : 
     436            1 :     PG_RETURN_VOID();
     437              : }
        

Generated by: LCOV version 2.0-1