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