LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pg_upgrade_support.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.6 % 154 141
Test Date: 2026-07-22 12:15:41 Functions: 95.0 % 20 19
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 31.0 % 116 36

             Branch data     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                 :         945 : binary_upgrade_set_next_pg_type_oid(PG_FUNCTION_ARGS)
      55                 :             : {
      56                 :         945 :     Oid         typoid = PG_GETARG_OID(0);
      57                 :             : 
      58   [ -  +  -  - ]:         945 :     CHECK_IS_BINARY_UPGRADE;
      59                 :         945 :     binary_upgrade_next_pg_type_oid = typoid;
      60                 :             : 
      61                 :         945 :     PG_RETURN_VOID();
      62                 :             : }
      63                 :             : 
      64                 :             : Datum
      65                 :         944 : binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS)
      66                 :             : {
      67                 :         944 :     Oid         typoid = PG_GETARG_OID(0);
      68                 :             : 
      69   [ -  +  -  - ]:         944 :     CHECK_IS_BINARY_UPGRADE;
      70                 :         944 :     binary_upgrade_next_array_pg_type_oid = typoid;
      71                 :             : 
      72                 :         944 :     PG_RETURN_VOID();
      73                 :             : }
      74                 :             : 
      75                 :             : Datum
      76                 :           7 : binary_upgrade_set_next_multirange_pg_type_oid(PG_FUNCTION_ARGS)
      77                 :             : {
      78                 :           7 :     Oid         typoid = PG_GETARG_OID(0);
      79                 :             : 
      80   [ -  +  -  - ]:           7 :     CHECK_IS_BINARY_UPGRADE;
      81                 :           7 :     binary_upgrade_next_mrng_pg_type_oid = typoid;
      82                 :             : 
      83                 :           7 :     PG_RETURN_VOID();
      84                 :             : }
      85                 :             : 
      86                 :             : Datum
      87                 :           7 : binary_upgrade_set_next_multirange_array_pg_type_oid(PG_FUNCTION_ARGS)
      88                 :             : {
      89                 :           7 :     Oid         typoid = PG_GETARG_OID(0);
      90                 :             : 
      91   [ -  +  -  - ]:           7 :     CHECK_IS_BINARY_UPGRADE;
      92                 :           7 :     binary_upgrade_next_mrng_array_pg_type_oid = typoid;
      93                 :             : 
      94                 :           7 :     PG_RETURN_VOID();
      95                 :             : }
      96                 :             : 
      97                 :             : Datum
      98                 :         962 : binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS)
      99                 :             : {
     100                 :         962 :     Oid         reloid = PG_GETARG_OID(0);
     101                 :             : 
     102   [ -  +  -  - ]:         962 :     CHECK_IS_BINARY_UPGRADE;
     103                 :         962 :     binary_upgrade_next_heap_pg_class_oid = reloid;
     104                 :             : 
     105                 :         962 :     PG_RETURN_VOID();
     106                 :             : }
     107                 :             : 
     108                 :             : Datum
     109                 :         847 : binary_upgrade_set_next_heap_relfilenode(PG_FUNCTION_ARGS)
     110                 :             : {
     111                 :         847 :     RelFileNumber relfilenumber = PG_GETARG_OID(0);
     112                 :             : 
     113   [ -  +  -  - ]:         847 :     CHECK_IS_BINARY_UPGRADE;
     114                 :         847 :     binary_upgrade_next_heap_pg_class_relfilenumber = relfilenumber;
     115                 :             : 
     116                 :         847 :     PG_RETURN_VOID();
     117                 :             : }
     118                 :             : 
     119                 :             : Datum
     120                 :         610 : binary_upgrade_set_next_index_pg_class_oid(PG_FUNCTION_ARGS)
     121                 :             : {
     122                 :         610 :     Oid         reloid = PG_GETARG_OID(0);
     123                 :             : 
     124   [ -  +  -  - ]:         610 :     CHECK_IS_BINARY_UPGRADE;
     125                 :         610 :     binary_upgrade_next_index_pg_class_oid = reloid;
     126                 :             : 
     127                 :         610 :     PG_RETURN_VOID();
     128                 :             : }
     129                 :             : 
     130                 :             : Datum
     131                 :         674 : binary_upgrade_set_next_index_relfilenode(PG_FUNCTION_ARGS)
     132                 :             : {
     133                 :         674 :     RelFileNumber relfilenumber = PG_GETARG_OID(0);
     134                 :             : 
     135   [ -  +  -  - ]:         674 :     CHECK_IS_BINARY_UPGRADE;
     136                 :         674 :     binary_upgrade_next_index_pg_class_relfilenumber = relfilenumber;
     137                 :             : 
     138                 :         674 :     PG_RETURN_VOID();
     139                 :             : }
     140                 :             : 
     141                 :             : Datum
     142                 :         290 : binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS)
     143                 :             : {
     144                 :         290 :     Oid         reloid = PG_GETARG_OID(0);
     145                 :             : 
     146   [ -  +  -  - ]:         290 :     CHECK_IS_BINARY_UPGRADE;
     147                 :         290 :     binary_upgrade_next_toast_pg_class_oid = reloid;
     148                 :             : 
     149                 :         290 :     PG_RETURN_VOID();
     150                 :             : }
     151                 :             : 
     152                 :             : Datum
     153                 :         290 : binary_upgrade_set_next_toast_relfilenode(PG_FUNCTION_ARGS)
     154                 :             : {
     155                 :         290 :     RelFileNumber relfilenumber = PG_GETARG_OID(0);
     156                 :             : 
     157   [ -  +  -  - ]:         290 :     CHECK_IS_BINARY_UPGRADE;
     158                 :         290 :     binary_upgrade_next_toast_pg_class_relfilenumber = relfilenumber;
     159                 :             : 
     160                 :         290 :     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                 :          18 : binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS)
     176                 :             : {
     177                 :          18 :     Oid         authoid = PG_GETARG_OID(0);
     178                 :             : 
     179   [ -  +  -  - ]:          18 :     CHECK_IS_BINARY_UPGRADE;
     180                 :          18 :     binary_upgrade_next_pg_authid_oid = authoid;
     181                 :          18 :     PG_RETURN_VOID();
     182                 :             : }
     183                 :             : 
     184                 :             : Datum
     185                 :           5 : 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   [ -  +  -  - ]:           5 :     CHECK_IS_BINARY_UPGRADE;
     196                 :             : 
     197                 :             :     /* We must check these things before dereferencing the arguments */
     198         [ +  - ]:           5 :     if (PG_ARGISNULL(0) ||
     199         [ +  - ]:           5 :         PG_ARGISNULL(1) ||
     200         [ +  - ]:           5 :         PG_ARGISNULL(2) ||
     201         [ -  + ]:           5 :         PG_ARGISNULL(3))
     202         [ #  # ]:           0 :         elog(ERROR, "null argument to binary_upgrade_create_empty_extension is not allowed");
     203                 :             : 
     204                 :           5 :     extName = PG_GETARG_TEXT_PP(0);
     205                 :           5 :     schemaName = PG_GETARG_TEXT_PP(1);
     206                 :           5 :     relocatable = PG_GETARG_BOOL(2);
     207                 :           5 :     extVersion = PG_GETARG_TEXT_PP(3);
     208                 :             : 
     209         [ +  - ]:           5 :     if (PG_ARGISNULL(4))
     210                 :           5 :         extConfig = PointerGetDatum(NULL);
     211                 :             :     else
     212                 :           0 :         extConfig = PG_GETARG_DATUM(4);
     213                 :             : 
     214         [ +  - ]:           5 :     if (PG_ARGISNULL(5))
     215                 :           5 :         extCondition = PointerGetDatum(NULL);
     216                 :             :     else
     217                 :           0 :         extCondition = PG_GETARG_DATUM(5);
     218                 :             : 
     219                 :           5 :     requiredExtensions = NIL;
     220         [ +  - ]:           5 :     if (!PG_ARGISNULL(6))
     221                 :             :     {
     222                 :           5 :         ArrayType  *textArray = PG_GETARG_ARRAYTYPE_P(6);
     223                 :             :         Datum      *textDatums;
     224                 :             :         int         ndatums;
     225                 :             :         int         i;
     226                 :             : 
     227                 :           5 :         deconstruct_array_builtin(textArray, TEXTOID, &textDatums, NULL, &ndatums);
     228         [ -  + ]:           5 :         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                 :           5 :     InsertExtensionTuple(text_to_cstring(extName),
     238                 :             :                          GetUserId(),
     239                 :           5 :                          get_namespace_oid(text_to_cstring(schemaName), false),
     240                 :             :                          relocatable,
     241                 :           5 :                          text_to_cstring(extVersion),
     242                 :             :                          extConfig,
     243                 :             :                          extCondition,
     244                 :             :                          requiredExtensions);
     245                 :             : 
     246                 :           5 :     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                 :           4 : binary_upgrade_set_missing_value(PG_FUNCTION_ARGS)
     262                 :             : {
     263                 :           4 :     Oid         table_id = PG_GETARG_OID(0);
     264                 :           4 :     text       *attname = PG_GETARG_TEXT_P(1);
     265                 :           4 :     text       *value = PG_GETARG_TEXT_P(2);
     266                 :           4 :     char       *cattname = text_to_cstring(attname);
     267                 :           4 :     char       *cvalue = text_to_cstring(value);
     268                 :             : 
     269   [ -  +  -  - ]:           4 :     CHECK_IS_BINARY_UPGRADE;
     270                 :           4 :     SetAttrMissing(table_id, cattname, cvalue);
     271                 :             : 
     272                 :           4 :     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