1 /*
2  *	pg_upgrade_support.c
3  *
4  *	server-side functions to set backend global variables
5  *	to control oid and relfilenode assignment, and do other special
6  *	hacks needed for pg_upgrade.
7  *
8  *	Copyright (c) 2010-2018, PostgreSQL Global Development Group
9  *	src/backend/utils/adt/pg_upgrade_support.c
10  */
11 
12 #include "postgres.h"
13 
14 #include "catalog/binary_upgrade.h"
15 #include "catalog/heap.h"
16 #include "catalog/namespace.h"
17 #include "catalog/pg_type.h"
18 #include "commands/extension.h"
19 #include "miscadmin.h"
20 #include "utils/array.h"
21 #include "utils/builtins.h"
22 
23 
24 #define CHECK_IS_BINARY_UPGRADE									\
25 do {															\
26 	if (!IsBinaryUpgrade)										\
27 		ereport(ERROR,											\
28 				(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),	\
29 				 (errmsg("function can only be called when server is in binary upgrade mode")))); \
30 } while (0)
31 
32 Datum
binary_upgrade_set_next_pg_type_oid(PG_FUNCTION_ARGS)33 binary_upgrade_set_next_pg_type_oid(PG_FUNCTION_ARGS)
34 {
35 	Oid			typoid = PG_GETARG_OID(0);
36 
37 	CHECK_IS_BINARY_UPGRADE;
38 	binary_upgrade_next_pg_type_oid = typoid;
39 
40 	PG_RETURN_VOID();
41 }
42 
43 Datum
binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS)44 binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS)
45 {
46 	Oid			typoid = PG_GETARG_OID(0);
47 
48 	CHECK_IS_BINARY_UPGRADE;
49 	binary_upgrade_next_array_pg_type_oid = typoid;
50 
51 	PG_RETURN_VOID();
52 }
53 
54 Datum
binary_upgrade_set_next_toast_pg_type_oid(PG_FUNCTION_ARGS)55 binary_upgrade_set_next_toast_pg_type_oid(PG_FUNCTION_ARGS)
56 {
57 	Oid			typoid = PG_GETARG_OID(0);
58 
59 	CHECK_IS_BINARY_UPGRADE;
60 	binary_upgrade_next_toast_pg_type_oid = typoid;
61 
62 	PG_RETURN_VOID();
63 }
64 
65 Datum
binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS)66 binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS)
67 {
68 	Oid			reloid = PG_GETARG_OID(0);
69 
70 	CHECK_IS_BINARY_UPGRADE;
71 	binary_upgrade_next_heap_pg_class_oid = reloid;
72 
73 	PG_RETURN_VOID();
74 }
75 
76 Datum
binary_upgrade_set_next_index_pg_class_oid(PG_FUNCTION_ARGS)77 binary_upgrade_set_next_index_pg_class_oid(PG_FUNCTION_ARGS)
78 {
79 	Oid			reloid = PG_GETARG_OID(0);
80 
81 	CHECK_IS_BINARY_UPGRADE;
82 	binary_upgrade_next_index_pg_class_oid = reloid;
83 
84 	PG_RETURN_VOID();
85 }
86 
87 Datum
binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS)88 binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS)
89 {
90 	Oid			reloid = PG_GETARG_OID(0);
91 
92 	CHECK_IS_BINARY_UPGRADE;
93 	binary_upgrade_next_toast_pg_class_oid = reloid;
94 
95 	PG_RETURN_VOID();
96 }
97 
98 Datum
binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS)99 binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS)
100 {
101 	Oid			enumoid = PG_GETARG_OID(0);
102 
103 	CHECK_IS_BINARY_UPGRADE;
104 	binary_upgrade_next_pg_enum_oid = enumoid;
105 
106 	PG_RETURN_VOID();
107 }
108 
109 Datum
binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS)110 binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS)
111 {
112 	Oid			authoid = PG_GETARG_OID(0);
113 
114 	CHECK_IS_BINARY_UPGRADE;
115 	binary_upgrade_next_pg_authid_oid = authoid;
116 	PG_RETURN_VOID();
117 }
118 
119 Datum
binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)120 binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)
121 {
122 	text	   *extName;
123 	text	   *schemaName;
124 	bool		relocatable;
125 	text	   *extVersion;
126 	Datum		extConfig;
127 	Datum		extCondition;
128 	List	   *requiredExtensions;
129 
130 	CHECK_IS_BINARY_UPGRADE;
131 
132 	/* We must check these things before dereferencing the arguments */
133 	if (PG_ARGISNULL(0) ||
134 		PG_ARGISNULL(1) ||
135 		PG_ARGISNULL(2) ||
136 		PG_ARGISNULL(3))
137 		elog(ERROR, "null argument to binary_upgrade_create_empty_extension is not allowed");
138 
139 	extName = PG_GETARG_TEXT_PP(0);
140 	schemaName = PG_GETARG_TEXT_PP(1);
141 	relocatable = PG_GETARG_BOOL(2);
142 	extVersion = PG_GETARG_TEXT_PP(3);
143 
144 	if (PG_ARGISNULL(4))
145 		extConfig = PointerGetDatum(NULL);
146 	else
147 		extConfig = PG_GETARG_DATUM(4);
148 
149 	if (PG_ARGISNULL(5))
150 		extCondition = PointerGetDatum(NULL);
151 	else
152 		extCondition = PG_GETARG_DATUM(5);
153 
154 	requiredExtensions = NIL;
155 	if (!PG_ARGISNULL(6))
156 	{
157 		ArrayType  *textArray = PG_GETARG_ARRAYTYPE_P(6);
158 		Datum	   *textDatums;
159 		int			ndatums;
160 		int			i;
161 
162 		deconstruct_array(textArray,
163 						  TEXTOID, -1, false, 'i',
164 						  &textDatums, NULL, &ndatums);
165 		for (i = 0; i < ndatums; i++)
166 		{
167 			char	   *extName = TextDatumGetCString(textDatums[i]);
168 			Oid			extOid = get_extension_oid(extName, false);
169 
170 			requiredExtensions = lappend_oid(requiredExtensions, extOid);
171 		}
172 	}
173 
174 	InsertExtensionTuple(text_to_cstring(extName),
175 						 GetUserId(),
176 						 get_namespace_oid(text_to_cstring(schemaName), false),
177 						 relocatable,
178 						 text_to_cstring(extVersion),
179 						 extConfig,
180 						 extCondition,
181 						 requiredExtensions);
182 
183 	PG_RETURN_VOID();
184 }
185 
186 Datum
binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS)187 binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS)
188 {
189 	bool		record_init_privs = PG_GETARG_BOOL(0);
190 
191 	CHECK_IS_BINARY_UPGRADE;
192 	binary_upgrade_record_init_privs = record_init_privs;
193 
194 	PG_RETURN_VOID();
195 }
196 
197 Datum
binary_upgrade_set_missing_value(PG_FUNCTION_ARGS)198 binary_upgrade_set_missing_value(PG_FUNCTION_ARGS)
199 {
200 	Oid			table_id = PG_GETARG_OID(0);
201 	text	   *attname = PG_GETARG_TEXT_P(1);
202 	text	   *value = PG_GETARG_TEXT_P(2);
203 	char	   *cattname = text_to_cstring(attname);
204 	char	   *cvalue = text_to_cstring(value);
205 
206 	CHECK_IS_BINARY_UPGRADE;
207 	SetAttrMissing(table_id, cattname, cvalue);
208 
209 	PG_RETURN_VOID();
210 }
211