PostgreSQL Source Code  git master
function.c
Go to the documentation of this file.
1 /*
2  * function.c
3  *
4  * server-side function support
5  *
6  * Copyright (c) 2010-2023, PostgreSQL Global Development Group
7  * src/bin/pg_upgrade/function.c
8  */
9 
10 #include "postgres_fe.h"
11 
12 #include "access/transam.h"
13 #include "catalog/pg_language_d.h"
14 #include "pg_upgrade.h"
15 
16 /*
17  * qsort comparator for pointers to library names
18  *
19  * We sort first by name length, then alphabetically for names of the
20  * same length, then database array index. This is to ensure that, eg,
21  * "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
22  * transform modules will probably fail their LOAD tests. (The backend
23  * ought to cope with that consideration, but it doesn't yet, and even
24  * when it does it'll still be a good idea to have a predictable order of
25  * probing here.)
26  */
27 static int
28 library_name_compare(const void *p1, const void *p2)
29 {
30  const char *str1 = ((const LibraryInfo *) p1)->name;
31  const char *str2 = ((const LibraryInfo *) p2)->name;
32  int slen1 = strlen(str1);
33  int slen2 = strlen(str2);
34  int cmp = strcmp(str1, str2);
35 
36  if (slen1 != slen2)
37  return slen1 - slen2;
38  if (cmp != 0)
39  return cmp;
40  else
41  return ((const LibraryInfo *) p1)->dbnum -
42  ((const LibraryInfo *) p2)->dbnum;
43 }
44 
45 
46 /*
47  * get_loadable_libraries()
48  *
49  * Fetch the names of all old libraries containing either C-language functions
50  * or are corresponding to logical replication output plugins.
51  *
52  * We will later check that they all exist in the new installation.
53  */
54 void
56 {
57  PGresult **ress;
58  int totaltups;
59  int dbnum;
60  int n_libinfos;
61 
62  ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
63  totaltups = 0;
64 
65  /* Fetch all library names, removing duplicates within each DB */
66  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
67  {
68  DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
70 
71  /*
72  * Fetch all libraries containing non-built-in C functions in this DB.
73  */
74  ress[dbnum] = executeQueryOrDie(conn,
75  "SELECT DISTINCT probin "
76  "FROM pg_catalog.pg_proc "
77  "WHERE prolang = %u AND "
78  "probin IS NOT NULL AND "
79  "oid >= %u;",
80  ClanguageId,
82  totaltups += PQntuples(ress[dbnum]);
83 
84  PQfinish(conn);
85  }
86 
87  /*
88  * Allocate memory for required libraries and logical replication output
89  * plugins.
90  */
91  n_libinfos = totaltups + count_old_cluster_logical_slots();
92  os_info.libraries = (LibraryInfo *) pg_malloc(sizeof(LibraryInfo) * n_libinfos);
93  totaltups = 0;
94 
95  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
96  {
97  PGresult *res = ress[dbnum];
98  int ntups;
99  int rowno;
100  LogicalSlotInfoArr *slot_arr = &old_cluster.dbarr.dbs[dbnum].slot_arr;
101 
102  ntups = PQntuples(res);
103  for (rowno = 0; rowno < ntups; rowno++)
104  {
105  char *lib = PQgetvalue(res, rowno, 0);
106 
107  os_info.libraries[totaltups].name = pg_strdup(lib);
108  os_info.libraries[totaltups].dbnum = dbnum;
109 
110  totaltups++;
111  }
112  PQclear(res);
113 
114  /*
115  * Store the names of output plugins as well. There is a possibility
116  * that duplicated plugins are set, but the consumer function
117  * check_loadable_libraries() will avoid checking the same library, so
118  * we do not have to consider their uniqueness here.
119  */
120  for (int slotno = 0; slotno < slot_arr->nslots; slotno++)
121  {
122  if (slot_arr->slots[slotno].invalid)
123  continue;
124 
125  os_info.libraries[totaltups].name = pg_strdup(slot_arr->slots[slotno].plugin);
126  os_info.libraries[totaltups].dbnum = dbnum;
127 
128  totaltups++;
129  }
130  }
131 
132  pg_free(ress);
133 
134  os_info.num_libraries = totaltups;
135 }
136 
137 
138 /*
139  * check_loadable_libraries()
140  *
141  * Check that the new cluster contains all required libraries.
142  * We do this by actually trying to LOAD each one, thereby testing
143  * compatibility as well as presence.
144  */
145 void
147 {
148  PGconn *conn = connectToServer(&new_cluster, "template1");
149  int libnum;
150  int was_load_failure = false;
151  FILE *script = NULL;
152  char output_path[MAXPGPATH];
153 
154  prep_status("Checking for presence of required libraries");
155 
156  snprintf(output_path, sizeof(output_path), "%s/%s",
157  log_opts.basedir, "loadable_libraries.txt");
158 
159  /*
160  * Now we want to sort the library names into order. This avoids multiple
161  * probes of the same library, and ensures that libraries are probed in a
162  * consistent order, which is important for reproducible behavior if one
163  * library depends on another.
164  */
167 
168  for (libnum = 0; libnum < os_info.num_libraries; libnum++)
169  {
170  char *lib = os_info.libraries[libnum].name;
171  int llen = strlen(lib);
172  char cmd[7 + 2 * MAXPGPATH + 1];
173  PGresult *res;
174 
175  /* Did the library name change? Probe it. */
176  if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
177  {
178  strcpy(cmd, "LOAD '");
179  PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
180  strcat(cmd, "'");
181 
182  res = PQexec(conn, cmd);
183 
185  {
186  was_load_failure = true;
187 
188  if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
189  pg_fatal("could not open file \"%s\": %s",
190  output_path, strerror(errno));
191  fprintf(script, _("could not load library \"%s\": %s"),
192  lib,
194  }
195  else
196  was_load_failure = false;
197 
198  PQclear(res);
199  }
200 
201  if (was_load_failure)
202  fprintf(script, _("In database: %s\n"),
204  }
205 
206  PQfinish(conn);
207 
208  if (script)
209  {
210  fclose(script);
211  pg_log(PG_REPORT, "fatal");
212  pg_fatal("Your installation references loadable libraries that are missing from the\n"
213  "new installation. You can add these libraries to the new installation,\n"
214  "or remove the functions using them from the old installation. A list of\n"
215  "problem libraries is in the file:\n"
216  " %s", output_path);
217  }
218  else
219  check_ok();
220 }
#define _(x)
Definition: elog.c:91
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7248
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4602
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:4086
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3352
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3422
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2221
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3817
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void check_loadable_libraries(void)
Definition: function.c:146
static int library_name_compare(const void *p1, const void *p2)
Definition: function.c:28
void get_loadable_libraries(void)
Definition: function.c:55
int count_old_cluster_logical_slots(void)
Definition: info.c:723
static void check_ok(void)
Definition: initdb.c:2036
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:97
#define pg_fatal(...)
#define MAXPGPATH
OSInfo os_info
Definition: pg_upgrade.c:66
ClusterInfo new_cluster
Definition: pg_upgrade.c:65
ClusterInfo old_cluster
Definition: pg_upgrade.c:64
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
LogOpts log_opts
Definition: util.c:17
#define fopen_priv(path, mode)
Definition: pg_upgrade.h:410
@ PG_REPORT
Definition: pg_upgrade.h:267
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:28
void prep_status(const char *fmt,...) pg_attribute_printf(1
PGresult * executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2
#define strerror
Definition: port.h:251
#define snprintf
Definition: port.h:238
#define fprintf
Definition: port.h:242
#define qsort(a, b, c, d)
Definition: port.h:445
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
PGconn * conn
Definition: streamutil.c:54
DbInfoArr dbarr
Definition: pg_upgrade.h:282
DbInfo * dbs
Definition: pg_upgrade.h:214
LogicalSlotInfoArr slot_arr
Definition: pg_upgrade.h:197
char * db_name
Definition: pg_upgrade.h:193
char * name
Definition: pg_upgrade.h:331
char * basedir
Definition: pg_upgrade.h:308
LogicalSlotInfo * slots
Definition: pg_upgrade.h:168
LibraryInfo * libraries
Definition: pg_upgrade.h:345
int num_libraries
Definition: pg_upgrade.h:346
#define FirstNormalObjectId
Definition: transam.h:197