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