PostgreSQL Source Code  git master
function.c File Reference
#include "postgres_fe.h"
#include "access/transam.h"
#include "catalog/pg_language_d.h"
#include "pg_upgrade.h"
Include dependency graph for function.c:

Go to the source code of this file.

Functions

static int library_name_compare (const void *p1, const void *p2)
 
void get_loadable_libraries (void)
 
void check_loadable_libraries (void)
 

Function Documentation

◆ check_loadable_libraries()

void check_loadable_libraries ( void  )

Definition at line 180 of file function.c.

References _, check_ok(), conn, connectToServer(), DbInfo::db_name, ClusterInfo::dbarr, LibraryInfo::dbnum, DbInfoArr::dbs, fopen_priv, fprintf, GET_MAJOR_VERSION, OSInfo::libraries, library_name_compare(), ClusterInfo::major_version, MAXPGPATH, LibraryInfo::name, new_cluster, OSInfo::num_libraries, old_cluster, os_info, pg_fatal, pg_log(), PG_REPORT, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQescapeStringConn(), PQexec(), PQfinish(), PQresultStatus(), prep_status(), qsort, snprintf, and strerror.

Referenced by check_new_cluster().

181 {
182  PGconn *conn = connectToServer(&new_cluster, "template1");
183  int libnum;
184  int was_load_failure = false;
185  FILE *script = NULL;
186  bool found = false;
187  char output_path[MAXPGPATH];
188 
189  prep_status("Checking for presence of required libraries");
190 
191  snprintf(output_path, sizeof(output_path), "loadable_libraries.txt");
192 
193  /*
194  * Now we want to sort the library names into order. This avoids multiple
195  * probes of the same library, and ensures that libraries are probed in a
196  * consistent order, which is important for reproducible behavior if one
197  * library depends on another.
198  */
201 
202  for (libnum = 0; libnum < os_info.num_libraries; libnum++)
203  {
204  char *lib = os_info.libraries[libnum].name;
205  int llen = strlen(lib);
206  char cmd[7 + 2 * MAXPGPATH + 1];
207  PGresult *res;
208 
209  /* Did the library name change? Probe it. */
210  if (libnum == 0 || strcmp(lib, os_info.libraries[libnum - 1].name) != 0)
211  {
212  /*
213  * In Postgres 9.0, Python 3 support was added, and to do that, a
214  * plpython2u language was created with library name plpython2.so
215  * as a symbolic link to plpython.so. In Postgres 9.1, only the
216  * plpython2.so library was created, and both plpythonu and
217  * plpython2u point to it. For this reason, any reference to
218  * library name "plpython" in an old PG <= 9.1 cluster must look
219  * for "plpython2" in the new cluster.
220  */
222  strcmp(lib, "$libdir/plpython") == 0)
223  {
224  lib = "$libdir/plpython2";
225  llen = strlen(lib);
226  }
227 
228  strcpy(cmd, "LOAD '");
229  PQescapeStringConn(conn, cmd + strlen(cmd), lib, llen, NULL);
230  strcat(cmd, "'");
231 
232  res = PQexec(conn, cmd);
233 
234  if (PQresultStatus(res) != PGRES_COMMAND_OK)
235  {
236  found = true;
237  was_load_failure = true;
238 
239  if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
240  pg_fatal("could not open file \"%s\": %s\n",
241  output_path, strerror(errno));
242  fprintf(script, _("could not load library \"%s\": %s"),
243  lib,
244  PQerrorMessage(conn));
245  }
246  else
247  was_load_failure = false;
248 
249  PQclear(res);
250  }
251 
252  if (was_load_failure)
253  fprintf(script, _("In database: %s\n"),
255  }
256 
257  PQfinish(conn);
258 
259  if (found)
260  {
261  fclose(script);
262  pg_log(PG_REPORT, "fatal\n");
263  pg_fatal("Your installation references loadable libraries that are missing from the\n"
264  "new installation. You can add these libraries to the new installation,\n"
265  "or remove the functions using them from the old installation. A list of\n"
266  "problem libraries is in the file:\n"
267  " %s\n\n", output_path);
268  }
269  else
270  check_ok();
271 }
char * name
Definition: pg_upgrade.h:299
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6687
uint32 major_version
Definition: pg_upgrade.h:267
int num_libraries
Definition: pg_upgrade.h:314
#define GET_MAJOR_VERSION(v)
Definition: pg_upgrade.h:23
#define pg_fatal(...)
Definition: pg_rewind.h:41
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4185
#define fprintf
Definition: port.h:197
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
ClusterInfo new_cluster
Definition: pg_upgrade.c:59
PGconn * conn
Definition: streamutil.c:54
#define MAXPGPATH
void prep_status(const char *fmt,...) pg_attribute_printf(1
ClusterInfo old_cluster
Definition: pg_upgrade.c:59
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from, size_t length, int *error)
Definition: fe-exec.c:3410
static int library_name_compare(const void *p1, const void *p2)
Definition: function.c:28
LibraryInfo * libraries
Definition: pg_upgrade.h:313
static void check_ok(void)
Definition: initdb.c:2039
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
void PQclear(PGresult *res)
Definition: fe-exec.c:694
DbInfoArr dbarr
Definition: pg_upgrade.h:258
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
#define strerror
Definition: port.h:206
#define fopen_priv(path, mode)
Definition: pg_upgrade.h:380
OSInfo os_info
Definition: pg_upgrade.c:61
char * db_name
Definition: pg_upgrade.h:179
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
#define qsort(a, b, c, d)
Definition: port.h:479
DbInfo * dbs
Definition: pg_upgrade.h:190
#define snprintf
Definition: port.h:193
#define _(x)
Definition: elog.c:88

◆ get_loadable_libraries()

void get_loadable_libraries ( void  )

Definition at line 53 of file function.c.

References conn, connectToServer(), DbInfo::db_name, ClusterInfo::dbarr, LibraryInfo::dbnum, DbInfoArr::dbs, executeQueryOrDie(), FirstNormalObjectId, GET_MAJOR_VERSION, OSInfo::libraries, ClusterInfo::major_version, LibraryInfo::name, DbInfoArr::ndbs, OSInfo::num_libraries, old_cluster, os_info, pg_fatal, pg_free(), pg_log(), pg_malloc(), pg_strdup(), PG_WARNING, PQclear(), PQfinish(), PQgetvalue(), and PQntuples().

Referenced by check_and_dump_old_cluster().

54 {
55  PGresult **ress;
56  int totaltups;
57  int dbnum;
58  bool found_public_plpython_handler = false;
59 
60  ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
61  totaltups = 0;
62 
63  /* Fetch all library names, removing duplicates within each DB */
64  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
65  {
66  DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
68 
69  /*
70  * Fetch all libraries containing non-built-in C functions in this DB.
71  */
72  ress[dbnum] = executeQueryOrDie(conn,
73  "SELECT DISTINCT probin "
74  "FROM pg_catalog.pg_proc "
75  "WHERE prolang = %u AND "
76  "probin IS NOT NULL AND "
77  "oid >= %u;",
78  ClanguageId,
80  totaltups += PQntuples(ress[dbnum]);
81 
82  /*
83  * Systems that install plpython before 8.1 have
84  * plpython_call_handler() defined in the "public" schema, causing
85  * pg_dump to dump it. However that function still references
86  * "plpython" (no "2"), so it throws an error on restore. This code
87  * checks for the problem function, reports affected databases to the
88  * user and explains how to remove them. 8.1 git commit:
89  * e0dedd0559f005d60c69c9772163e69c204bac69
90  * http://archives.postgresql.org/pgsql-hackers/2012-03/msg01101.php
91  * http://archives.postgresql.org/pgsql-bugs/2012-05/msg00206.php
92  */
94  {
95  PGresult *res;
96 
97  res = executeQueryOrDie(conn,
98  "SELECT 1 "
99  "FROM pg_catalog.pg_proc p "
100  " JOIN pg_catalog.pg_namespace n "
101  " ON pronamespace = n.oid "
102  "WHERE proname = 'plpython_call_handler' AND "
103  "nspname = 'public' AND "
104  "prolang = %u AND "
105  "probin = '$libdir/plpython' AND "
106  "p.oid >= %u;",
107  ClanguageId,
109  if (PQntuples(res) > 0)
110  {
111  if (!found_public_plpython_handler)
112  {
114  "\nThe old cluster has a \"plpython_call_handler\" function defined\n"
115  "in the \"public\" schema which is a duplicate of the one defined\n"
116  "in the \"pg_catalog\" schema. You can confirm this by executing\n"
117  "in psql:\n"
118  "\n"
119  " \\df *.plpython_call_handler\n"
120  "\n"
121  "The \"public\" schema version of this function was created by a\n"
122  "pre-8.1 install of plpython, and must be removed for pg_upgrade\n"
123  "to complete because it references a now-obsolete \"plpython\"\n"
124  "shared object file. You can remove the \"public\" schema version\n"
125  "of this function by running the following command:\n"
126  "\n"
127  " DROP FUNCTION public.plpython_call_handler()\n"
128  "\n"
129  "in each affected database:\n"
130  "\n");
131  }
132  pg_log(PG_WARNING, " %s\n", active_db->db_name);
133  found_public_plpython_handler = true;
134  }
135  PQclear(res);
136  }
137 
138  PQfinish(conn);
139  }
140 
141  if (found_public_plpython_handler)
142  pg_fatal("Remove the problem functions from the old cluster to continue.\n");
143 
144  os_info.libraries = (LibraryInfo *) pg_malloc(totaltups * sizeof(LibraryInfo));
145  totaltups = 0;
146 
147  for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
148  {
149  PGresult *res = ress[dbnum];
150  int ntups;
151  int rowno;
152 
153  ntups = PQntuples(res);
154  for (rowno = 0; rowno < ntups; rowno++)
155  {
156  char *lib = PQgetvalue(res, rowno, 0);
157 
158  os_info.libraries[totaltups].name = pg_strdup(lib);
159  os_info.libraries[totaltups].dbnum = dbnum;
160 
161  totaltups++;
162  }
163  PQclear(res);
164  }
165 
166  pg_free(ress);
167 
168  os_info.num_libraries = totaltups;
169 }
char * name
Definition: pg_upgrade.h:299
uint32 major_version
Definition: pg_upgrade.h:267
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int num_libraries
Definition: pg_upgrade.h:314
PGresult * executeQueryOrDie(PGconn *conn, const char *fmt,...) pg_attribute_printf(2
#define GET_MAJOR_VERSION(v)
Definition: pg_upgrade.h:23
#define pg_fatal(...)
Definition: pg_rewind.h:41
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4185
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2769
#define FirstNormalObjectId
Definition: transam.h:155
PGconn * conn
Definition: streamutil.c:54
ClusterInfo old_cluster
Definition: pg_upgrade.c:59
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
LibraryInfo * libraries
Definition: pg_upgrade.h:313
PGconn * connectToServer(ClusterInfo *cluster, const char *db_name)
Definition: server.c:27
void PQclear(PGresult *res)
Definition: fe-exec.c:694
DbInfoArr dbarr
Definition: pg_upgrade.h:258
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
void pg_free(void *ptr)
Definition: fe_memutils.c:105
OSInfo os_info
Definition: pg_upgrade.c:61
char * db_name
Definition: pg_upgrade.h:179
DbInfo * dbs
Definition: pg_upgrade.h:190

◆ library_name_compare()

static int library_name_compare ( const void *  p1,
const void *  p2 
)
static

Definition at line 28 of file function.c.

References cmp().

Referenced by check_loadable_libraries().

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 }
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742