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-2024, 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 "common/int.h"
15 #include "pg_upgrade.h"
16 
17 /*
18  * qsort comparator for pointers to library names
19  *
20  * We sort first by name length, then alphabetically for names of the
21  * same length, then database array index. This is to ensure that, eg,
22  * "hstore_plpython" sorts after both "hstore" and "plpython"; otherwise
23  * transform modules will probably fail their LOAD tests. (The backend
24  * ought to cope with that consideration, but it doesn't yet, and even
25  * when it does it'll still be a good idea to have a predictable order of
26  * probing here.)
27  */
28 static int
29 library_name_compare(const void *p1, const void *p2)
30 {
31  const char *str1 = ((const LibraryInfo *) p1)->name;
32  const char *str2 = ((const LibraryInfo *) p2)->name;
33  size_t slen1 = strlen(str1);
34  size_t slen2 = strlen(str2);
35  int cmp = strcmp(str1, str2);
36 
37  if (slen1 != slen2)
38  return pg_cmp_size(slen1, slen2);
39  if (cmp != 0)
40  return cmp;
41  return pg_cmp_s32(((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\": %m", output_path);
190  fprintf(script, _("could not load library \"%s\": %s"),
191  lib,
193  }
194  else
195  was_load_failure = false;
196 
197  PQclear(res);
198  }
199 
200  if (was_load_failure)
201  fprintf(script, _("In database: %s\n"),
203  }
204 
205  PQfinish(conn);
206 
207  if (script)
208  {
209  fclose(script);
210  pg_log(PG_REPORT, "fatal");
211  pg_fatal("Your installation references loadable libraries that are missing from the\n"
212  "new installation. You can add these libraries to the new installation,\n"
213  "or remove the functions using them from the old installation. A list of\n"
214  "problem libraries is in the file:\n"
215  " %s", output_path);
216  }
217  else
218  check_ok();
219 }
#define _(x)
Definition: elog.c:90
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7167
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4888
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:4145
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3411
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2262
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
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:29
void get_loadable_libraries(void)
Definition: function.c:55
int count_old_cluster_logical_slots(void)
Definition: info.c:740
static void check_ok(void)
Definition: initdb.c:2036
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:483
static int pg_cmp_size(size_t a, size_t b)
Definition: int.h:507
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:100
#define pg_fatal(...)
#define MAXPGPATH
OSInfo os_info
Definition: pg_upgrade.c:73
ClusterInfo new_cluster
Definition: pg_upgrade.c:72
ClusterInfo old_cluster
Definition: pg_upgrade.c:71
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:420
@ PG_REPORT
Definition: pg_upgrade.h:271
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 snprintf
Definition: port.h:238
#define fprintf
Definition: port.h:242
#define qsort(a, b, c, d)
Definition: port.h:449
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
PGconn * conn
Definition: streamutil.c:55
DbInfoArr dbarr
Definition: pg_upgrade.h:286
DbInfo * dbs
Definition: pg_upgrade.h:217
LogicalSlotInfoArr slot_arr
Definition: pg_upgrade.h:199
char * db_name
Definition: pg_upgrade.h:195
char * name
Definition: pg_upgrade.h:335
char * basedir
Definition: pg_upgrade.h:312
LogicalSlotInfo * slots
Definition: pg_upgrade.h:170
LibraryInfo * libraries
Definition: pg_upgrade.h:349
int num_libraries
Definition: pg_upgrade.h:350
#define FirstNormalObjectId
Definition: transam.h:197