Age Owner Branch data TLA 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
1518 rhaas@postgresql.org 43 :GBC 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
4023 peter_e@gmx.net 54 :CBC 875 : binary_upgrade_set_next_pg_type_oid(PG_FUNCTION_ARGS)
55 : : {
5786 bruce@momjian.us 56 : 875 : Oid typoid = PG_GETARG_OID(0);
57 : :
4220 58 [ - + - - ]: 875 : CHECK_IS_BINARY_UPGRADE;
5786 59 : 875 : binary_upgrade_next_pg_type_oid = typoid;
60 : :
61 : 875 : PG_RETURN_VOID();
62 : : }
63 : :
64 : : Datum
4023 peter_e@gmx.net 65 : 874 : binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS)
66 : : {
5786 bruce@momjian.us 67 : 874 : Oid typoid = PG_GETARG_OID(0);
68 : :
4220 69 [ - + - - ]: 874 : CHECK_IS_BINARY_UPGRADE;
5546 70 : 874 : binary_upgrade_next_array_pg_type_oid = typoid;
71 : :
5786 72 : 874 : PG_RETURN_VOID();
73 : : }
74 : :
75 : : Datum
1911 akorotkov@postgresql 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
4023 peter_e@gmx.net 98 : 883 : binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS)
99 : : {
5546 bruce@momjian.us 100 : 883 : Oid reloid = PG_GETARG_OID(0);
101 : :
4220 102 [ - + - - ]: 883 : CHECK_IS_BINARY_UPGRADE;
5546 103 : 883 : binary_upgrade_next_heap_pg_class_oid = reloid;
104 : :
5786 105 : 883 : PG_RETURN_VOID();
106 : : }
107 : :
108 : : Datum
1518 rhaas@postgresql.org 109 : 787 : binary_upgrade_set_next_heap_relfilenode(PG_FUNCTION_ARGS)
110 : : {
1264 111 : 787 : RelFileNumber relfilenumber = PG_GETARG_OID(0);
112 : :
1518 113 [ - + - - ]: 787 : CHECK_IS_BINARY_UPGRADE;
1348 114 : 787 : binary_upgrade_next_heap_pg_class_relfilenumber = relfilenumber;
115 : :
1518 116 : 787 : PG_RETURN_VOID();
117 : : }
118 : :
119 : : Datum
4023 peter_e@gmx.net 120 : 557 : binary_upgrade_set_next_index_pg_class_oid(PG_FUNCTION_ARGS)
121 : : {
5546 bruce@momjian.us 122 : 557 : Oid reloid = PG_GETARG_OID(0);
123 : :
4220 124 [ - + - - ]: 557 : CHECK_IS_BINARY_UPGRADE;
5546 125 : 557 : binary_upgrade_next_index_pg_class_oid = reloid;
126 : :
5786 127 : 557 : PG_RETURN_VOID();
128 : : }
129 : :
130 : : Datum
1518 rhaas@postgresql.org 131 : 617 : binary_upgrade_set_next_index_relfilenode(PG_FUNCTION_ARGS)
132 : : {
1264 133 : 617 : RelFileNumber relfilenumber = PG_GETARG_OID(0);
134 : :
1518 135 [ - + - - ]: 617 : CHECK_IS_BINARY_UPGRADE;
1348 136 : 617 : binary_upgrade_next_index_pg_class_relfilenumber = relfilenumber;
137 : :
1518 138 : 617 : PG_RETURN_VOID();
139 : : }
140 : :
141 : : Datum
4023 peter_e@gmx.net 142 : 270 : binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS)
143 : : {
5546 bruce@momjian.us 144 : 270 : Oid reloid = PG_GETARG_OID(0);
145 : :
4220 146 [ - + - - ]: 270 : CHECK_IS_BINARY_UPGRADE;
5546 147 : 270 : binary_upgrade_next_toast_pg_class_oid = reloid;
148 : :
5786 149 : 270 : PG_RETURN_VOID();
150 : : }
151 : :
152 : : Datum
1518 rhaas@postgresql.org 153 : 270 : binary_upgrade_set_next_toast_relfilenode(PG_FUNCTION_ARGS)
154 : : {
1264 155 : 270 : RelFileNumber relfilenumber = PG_GETARG_OID(0);
156 : :
1518 157 [ - + - - ]: 270 : CHECK_IS_BINARY_UPGRADE;
1348 158 : 270 : binary_upgrade_next_toast_pg_class_relfilenumber = relfilenumber;
159 : :
1518 160 : 270 : PG_RETURN_VOID();
161 : : }
162 : :
163 : : Datum
4023 peter_e@gmx.net 164 : 50 : binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS)
165 : : {
5786 bruce@momjian.us 166 : 50 : Oid enumoid = PG_GETARG_OID(0);
167 : :
4220 168 [ - + - - ]: 50 : CHECK_IS_BINARY_UPGRADE;
5621 tgl@sss.pgh.pa.us 169 : 50 : binary_upgrade_next_pg_enum_oid = enumoid;
170 : :
5786 bruce@momjian.us 171 : 50 : PG_RETURN_VOID();
172 : : }
173 : :
174 : : Datum
4023 peter_e@gmx.net 175 : 17 : binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS)
176 : : {
5546 bruce@momjian.us 177 : 17 : Oid authoid = PG_GETARG_OID(0);
178 : :
4220 179 [ - + - - ]: 17 : CHECK_IS_BINARY_UPGRADE;
5546 180 : 17 : binary_upgrade_next_pg_authid_oid = authoid;
181 : 17 : PG_RETURN_VOID();
182 : : }
183 : :
184 : : Datum
4023 peter_e@gmx.net 185 :GBC 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 : :
4220 bruce@momjian.us 195 [ - + - - ]: 4 : CHECK_IS_BINARY_UPGRADE;
196 : :
197 : : /* We must check these things before dereferencing the arguments */
3724 tgl@sss.pgh.pa.us 198 [ + - ]: 4 : if (PG_ARGISNULL(0) ||
199 [ + - ]: 4 : PG_ARGISNULL(1) ||
200 [ + - ]: 4 : PG_ARGISNULL(2) ||
201 [ - + ]: 4 : PG_ARGISNULL(3))
3724 tgl@sss.pgh.pa.us 202 [ # # ]:UBC 0 : elog(ERROR, "null argument to binary_upgrade_create_empty_extension is not allowed");
203 : :
3724 tgl@sss.pgh.pa.us 204 :GBC 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 : :
5513 209 [ + - ]: 4 : if (PG_ARGISNULL(4))
210 : 4 : extConfig = PointerGetDatum(NULL);
211 : : else
5513 tgl@sss.pgh.pa.us 212 :UBC 0 : extConfig = PG_GETARG_DATUM(4);
213 : :
5513 tgl@sss.pgh.pa.us 214 [ + - ]:GBC 4 : if (PG_ARGISNULL(5))
215 : 4 : extCondition = PointerGetDatum(NULL);
216 : : else
5513 tgl@sss.pgh.pa.us 217 :UBC 0 : extCondition = PG_GETARG_DATUM(5);
218 : :
5513 tgl@sss.pgh.pa.us 219 :GBC 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 : :
1353 peter@eisentraut.org 227 : 4 : deconstruct_array_builtin(textArray, TEXTOID, &textDatums, NULL, &ndatums);
5513 tgl@sss.pgh.pa.us 228 [ - + ]: 4 : for (i = 0; i < ndatums; i++)
229 : : {
3290 noah@leadboat.com 230 :UBC 0 : char *extName = TextDatumGetCString(textDatums[i]);
5453 bruce@momjian.us 231 : 0 : Oid extOid = get_extension_oid(extName, false);
232 : :
5513 tgl@sss.pgh.pa.us 233 : 0 : requiredExtensions = lappend_oid(requiredExtensions, extOid);
234 : : }
235 : : }
236 : :
5513 tgl@sss.pgh.pa.us 237 :GBC 4 : InsertExtensionTuple(text_to_cstring(extName),
238 : : GetUserId(),
3189 239 : 4 : get_namespace_oid(text_to_cstring(schemaName), false),
240 : : relocatable,
5511 241 : 4 : text_to_cstring(extVersion),
242 : : extConfig,
243 : : extCondition,
244 : : requiredExtensions);
245 : :
5513 246 : 4 : PG_RETURN_VOID();
247 : : }
248 : :
249 : : Datum
3630 sfrost@snowman.net 250 :UBC 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
2823 andrew@dunslane.net 261 :CBC 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
39 msawada@postgresql.o 285 :GNC 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 : :
871 akapila@postgresql.o 292 [ - + - - ]:CBC 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 : : */
829 298 [ - + ]: 3 : Assert(has_rolreplication(GetUserId()));
299 : :
871 300 : 3 : slot_name = PG_GETARG_NAME(0);
39 msawada@postgresql.o 301 :GNC 3 : scan_cutoff_lsn = PG_GETARG_LSN(1);
302 : :
303 : : /* Acquire the given slot */
408 akapila@postgresql.o 304 :CBC 3 : ReplicationSlotAcquire(NameStr(*slot_name), true, true);
305 : :
871 306 [ - + ]: 3 : Assert(SlotIsLogical(MyReplicationSlot));
307 : :
308 : : /* Slots must be valid as otherwise we won't be able to scan the WAL */
309 [ - + ]: 3 : Assert(MyReplicationSlot->data.invalidated == RS_INVAL_NONE);
310 : :
311 : 3 : end_of_wal = GetFlushRecPtr(NULL);
39 msawada@postgresql.o 312 :GNC 3 : last_pending_wal = LogicalReplicationSlotCheckPendingWal(end_of_wal,
313 : : scan_cutoff_lsn);
314 : :
315 : : /* Clean up */
871 akapila@postgresql.o 316 :CBC 3 : ReplicationSlotRelease();
317 : :
39 msawada@postgresql.o 318 [ + + ]:GNC 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
803 akapila@postgresql.o 331 :CBC 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))
- + ]
803 akapila@postgresql.o 345 [ # # ]:UBC 0 : elog(ERROR, "null argument to binary_upgrade_add_sub_rel_state is not allowed");
346 : :
803 akapila@postgresql.o 347 :CBC 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))
803 akapila@postgresql.o 391 [ # # ]:UBC 0 : elog(ERROR, "null argument to binary_upgrade_replorigin_advance is not allowed");
392 : :
803 akapila@postgresql.o 393 :CBC 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
235 akapila@postgresql.o 428 :GNC 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 : : }
|