Make createlang and droplang proof against weird search_path settings
authorTom Lane <[email protected]>
Mon, 15 Aug 2005 21:02:26 +0000 (21:02 +0000)
committerTom Lane <[email protected]>
Mon, 15 Aug 2005 21:02:26 +0000 (21:02 +0000)
by forcing search_path to be just pg_catalog.

src/bin/scripts/common.c
src/bin/scripts/common.h
src/bin/scripts/createlang.c
src/bin/scripts/droplang.c

index 6ae4fc30f5434473a06b8ffc8ce4015910a014d8..49faaed8ebba4eafaf1408350f41aef458635fdb 100644 (file)
@@ -1,6 +1,8 @@
 /*-------------------------------------------------------------------------
  *
- * Miscellaneous shared code
+ *     common.c
+ *             Common support routines for bin/scripts/
+ *
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  */
 
 #include "postgres_fe.h"
-#include "common.h"
-#include "libpq-fe.h"
 
 #include <pwd.h>
 #include <unistd.h>
 
+#include "common.h"
+
+#ifndef HAVE_INT_OPTRESET
+int            optreset;
+#endif
+
 
 /*
  * Returns the current user name.
@@ -55,7 +61,8 @@ get_user_name(const char *progname)
  * options.
  */
 void
-handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
+handle_help_version_opts(int argc, char *argv[],
+                                                const char *fixed_progname, help_handler hlp)
 {
        if (argc > 1)
        {
@@ -79,7 +86,8 @@ handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, hel
  */
 PGconn *
 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
-                const char *pguser, bool require_password, const char *progname)
+                               const char *pguser, bool require_password,
+                               const char *progname)
 {
        PGconn     *conn;
        char       *password = NULL;
@@ -146,8 +154,10 @@ executeQuery(PGconn *conn, const char *query, const char *progname, bool echo)
        if (!res ||
                PQresultStatus(res) != PGRES_TUPLES_OK)
        {
-               fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
-               fprintf(stderr, _("%s: query was: %s\n"), progname, query);
+               fprintf(stderr, _("%s: query failed: %s"),
+                               progname, PQerrorMessage(conn));
+               fprintf(stderr, _("%s: query was: %s\n"),
+                               progname, query);
                PQfinish(conn);
                exit(1);
        }
@@ -156,6 +166,34 @@ executeQuery(PGconn *conn, const char *query, const char *progname, bool echo)
 }
 
 
+/*
+ * As above for a SQL command (which returns nothing).
+ */
+void
+executeCommand(PGconn *conn, const char *query,
+                          const char *progname, bool echo)
+{
+       PGresult   *res;
+
+       if (echo)
+               printf("%s\n", query);
+
+       res = PQexec(conn, query);
+       if (!res ||
+               PQresultStatus(res) != PGRES_COMMAND_OK)
+       {
+               fprintf(stderr, _("%s: query failed: %s"),
+                               progname, PQerrorMessage(conn));
+               fprintf(stderr, _("%s: query was: %s\n"),
+                               progname, query);
+               PQfinish(conn);
+               exit(1);
+       }
+
+       PQclear(res);
+}
+
+
 /*
  * Check yes/no answer in a localized way.     1=yes, 0=no, -1=neither.
  */
index 46e2a610aaa7dc9b73d12173e4a0a872a9781b5a..0d63cda82bd13f6d37537b47bec49fd3d4000462 100644 (file)
@@ -1,24 +1,40 @@
-#include "postgres_fe.h"
+/*
+ *     common.h
+ *             Common support routines for bin/scripts/
+ *
+ *     Copyright (c) 2003-2005, PostgreSQL Global Development Group
+ *
+ *     $PostgreSQL$
+ */
+#ifndef COMMON_H
+#define COMMON_H
 
 #include "libpq-fe.h"
 #include "pqexpbuffer.h"
 #include "getopt_long.h"
 
 #ifndef HAVE_INT_OPTRESET
-int                    optreset;
+extern int             optreset;
 #endif
 
-const char *get_user_name(const char *progname);
+typedef void (*help_handler) (const char *progname);
 
-typedef void (*help_handler) (const char *);
+extern const char *get_user_name(const char *progname);
 
-void           handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp);
+extern void handle_help_version_opts(int argc, char *argv[],
+                                                                        const char *fixed_progname,
+                                                                        help_handler hlp);
 
-PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
-               const char *pguser, bool require_password, const char *progname);
+extern PGconn *connectDatabase(const char *dbname, const char *pghost,
+                                                          const char *pgport, const char *pguser,
+                                                          bool require_password, const char *progname);
 
-PGresult *
-                       executeQuery(PGconn *conn, const char *command, const char *progname, bool echo);
+extern PGresult *executeQuery(PGconn *conn, const char *query,
+                                                         const char *progname, bool echo);
 
-int
-                       check_yesno_response(const char *string);
+extern void executeCommand(PGconn *conn, const char *query,
+                                                  const char *progname, bool echo);
+
+extern int     check_yesno_response(const char *string);
+
+#endif /* COMMON_H */
index 5f7cbfdbd40f3be6c3d291c8544f55c5a5210899..2f941fe8d6ecb56d498e14541723e9c0b3ef3113 100644 (file)
@@ -138,11 +138,12 @@ main(int argc, char *argv[])
        {
                printQueryOpt popt;
 
-               conn = connectDatabase(dbname, host, port, username, password, progname);
+               conn = connectDatabase(dbname, host, port, username, password,
+                                                          progname);
 
-               printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", (CASE WHEN lanpltrusted "
-                                                 "THEN '%s' ELSE '%s' END) as \"%s\" FROM pg_language "
-                                                 "WHERE lanispl IS TRUE;", 
+               printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
+                                                 "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
+                                                 "FROM pg_catalog.pg_language WHERE lanispl;", 
                                                  _("Name"), _("yes"), _("no"), _("Trusted?"));
                result = executeQuery(conn, sql.data, progname, echo);
 
@@ -221,6 +222,13 @@ main(int argc, char *argv[])
 
        conn = connectDatabase(dbname, host, port, username, password, progname);
 
+       /*
+        * Force schema search path to be just pg_catalog, so that we don't
+        * have to be paranoid about search paths below.
+        */
+       executeCommand(conn, "SET search_path = pg_catalog;",
+                                  progname, echo);
+
        /*
         * Make sure the language isn't already installed
         */
@@ -232,8 +240,7 @@ main(int argc, char *argv[])
        {
                PQfinish(conn);
                fprintf(stderr,
-                               _("%s: language \"%s\" is already installed in "
-                                 "database \"%s\"\n"),
+                               _("%s: language \"%s\" is already installed in database \"%s\"\n"),
                                progname, langname, dbname);
                /* separate exit status for "already installed" */
                exit(2);
@@ -244,7 +251,8 @@ main(int argc, char *argv[])
         * Check whether the call handler exists
         */
        printfPQExpBuffer(&sql, "SELECT oid FROM pg_proc WHERE proname = '%s' "
-                                         "AND prorettype = 'pg_catalog.language_handler'::regtype "
+                                         "AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') "
+                                         "AND prorettype = 'language_handler'::regtype "
                                          "AND pronargs = 0;", handler);
        result = executeQuery(conn, sql.data, progname, echo);
        handlerexists = (PQntuples(result) > 0);
@@ -255,9 +263,10 @@ main(int argc, char *argv[])
         */
        if (validator)
        {
-               printfPQExpBuffer(&sql, "SELECT oid FROM pg_proc WHERE proname = '%s'"
-                                                 " AND proargtypes[0] = 'pg_catalog.oid'::regtype "
-                                                 " AND pronargs = 1;", validator);
+               printfPQExpBuffer(&sql, "SELECT oid FROM pg_proc WHERE proname = '%s' "
+                                                 "AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') "
+                                                 "AND proargtypes[0] = 'oid'::regtype "
+                                                 "AND pronargs = 1;", validator);
                result = executeQuery(conn, sql.data, progname, echo);
                validatorexists = (PQntuples(result) > 0);
                PQclear(result);
@@ -267,27 +276,30 @@ main(int argc, char *argv[])
 
        /*
         * Create the function(s) and the language
+        *
+        * NOTE: the functions will be created in pg_catalog because
+        * of our previous "SET search_path".
         */
        resetPQExpBuffer(&sql);
 
        if (!handlerexists)
                appendPQExpBuffer(&sql,
-                                                 "CREATE FUNCTION pg_catalog.\"%s\" () RETURNS "
-                                                 "language_handler AS '%s/%s' LANGUAGE C;\n",
+                                                 "CREATE FUNCTION \"%s\" () RETURNS language_handler "
+                                                 "AS '%s/%s' LANGUAGE C;\n",
                                                  handler, pglib, object);
 
        if (!validatorexists)
                appendPQExpBuffer(&sql,
-                                                 "CREATE FUNCTION pg_catalog.\"%s\" (oid) RETURNS "
-                                                 "void AS '%s/%s' LANGUAGE C;\n",
+                                                 "CREATE FUNCTION \"%s\" (oid) RETURNS void "
+                                                 "AS '%s/%s' LANGUAGE C;\n",
                                                  validator, pglib, object);
 
        appendPQExpBuffer(&sql,
-                                         "CREATE %sLANGUAGE \"%s\" HANDLER pg_catalog.\"%s\"",
+                                         "CREATE %sLANGUAGE \"%s\" HANDLER \"%s\"",
                                          (trusted ? "TRUSTED " : ""), langname, handler);
 
        if (validator)
-               appendPQExpBuffer(&sql, " VALIDATOR pg_catalog.\"%s\"", validator);
+               appendPQExpBuffer(&sql, " VALIDATOR \"%s\"", validator);
 
        appendPQExpBuffer(&sql, ";\n");
 
index ba2c6f2106c6034a1083b81343a429ca73d77eef..5e656685537c4997248183ff4e2dff38fb219eaf 100644 (file)
@@ -140,9 +140,9 @@ main(int argc, char *argv[])
                conn = connectDatabase(dbname, host, port, username, password, 
                                                           progname);
 
-               printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", (CASE "
-                                                 "WHEN lanpltrusted THEN '%s' ELSE '%s' END) "
-                                                 "as \"%s\" FROM pg_language WHERE lanispl IS TRUE;", 
+               printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
+                                                 "(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
+                                                 "FROM pg_catalog.pg_language WHERE lanispl;", 
                                                  _("Name"), _("yes"), _("no"), _("Trusted?"));
                result = executeQuery(conn, sql.data, progname, echo);
 
@@ -172,6 +172,13 @@ main(int argc, char *argv[])
 
        conn = connectDatabase(dbname, host, port, username, password, progname);
 
+       /*
+        * Force schema search path to be just pg_catalog, so that we don't
+        * have to be paranoid about search paths below.
+        */
+       executeCommand(conn, "SET search_path = pg_catalog;",
+                                  progname, echo);
+
        /*
         * Make sure the language is installed and find the OIDs of the
         * handler and validator functions
@@ -248,8 +255,8 @@ main(int argc, char *argv[])
         */
        if (OidIsValid(lanvalidator))
        {
-               printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language WHERE "
-                                                 "lanvalidator = %u AND lanname <> '%s';", 
+               printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language "
+                                                 "WHERE lanvalidator = %u AND lanname <> '%s';", 
                                                  lanvalidator, langname);
                result = executeQuery(conn, sql.data, progname, echo);
                if (strcmp(PQgetvalue(result, 0, 0), "0") == 0)