droplang.c 9.04 KB
Newer Older
1 2 3 4
/*-------------------------------------------------------------------------
 *
 * droplang
 *
Bruce Momjian's avatar
Bruce Momjian committed
5
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
6 7
 * Portions Copyright (c) 1994, Regents of the University of California
 *
8
 * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.31 2009/02/26 16:02:39 petere Exp $
9 10 11 12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */

#include "postgres_fe.h"
#include "common.h"
#include "print.h"

17 18
#define atooid(x)  ((Oid) strtoul((x), NULL, 10))

19 20 21 22 23 24 25 26 27 28 29 30

static void help(const char *progname);


int
main(int argc, char *argv[])
{
	static struct option long_options[] = {
		{"list", no_argument, NULL, 'l'},
		{"host", required_argument, NULL, 'h'},
		{"port", required_argument, NULL, 'p'},
		{"username", required_argument, NULL, 'U'},
31
		{"no-password", no_argument, NULL, 'w'},
32 33 34 35 36 37
		{"password", no_argument, NULL, 'W'},
		{"dbname", required_argument, NULL, 'd'},
		{"echo", no_argument, NULL, 'e'},
		{NULL, 0, NULL, 0}
	};

38
	const char *progname;
39 40 41 42 43 44 45 46
	int			optindex;
	int			c;

	bool		listlangs = false;
	const char *dbname = NULL;
	char	   *host = NULL;
	char	   *port = NULL;
	char	   *username = NULL;
47
	enum trivalue prompt_password = TRI_DEFAULT;
48 49 50 51
	bool		echo = false;
	char	   *langname = NULL;

	char	   *p;
52 53
	Oid			lanplcallfoid;
	Oid			lanvalidator;
54
	char	   *handler;
55
	char	   *validator;
56 57
	char	   *handler_ns;
	char	   *validator_ns;
58
	bool		keephandler;
59
	bool		keepvalidator;
60 61 62 63 64 65 66

	PQExpBufferData sql;

	PGconn	   *conn;
	PGresult   *result;

	progname = get_progname(argv[0]);
67
	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
68

69 70
	handle_help_version_opts(argc, argv, "droplang", help);

71
	while ((c = getopt_long(argc, argv, "lh:p:U:wWd:e", long_options, &optindex)) != -1)
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
	{
		switch (c)
		{
			case 'l':
				listlangs = true;
				break;
			case 'h':
				host = optarg;
				break;
			case 'p':
				port = optarg;
				break;
			case 'U':
				username = optarg;
				break;
87 88 89
			case 'w':
				prompt_password = TRI_NO;
				break;
90
			case 'W':
91
				prompt_password = TRI_YES;
92 93 94 95 96 97 98 99
				break;
			case 'd':
				dbname = optarg;
				break;
			case 'e':
				echo = true;
				break;
			default:
100
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
				exit(1);
		}
	}

	if (argc - optind > 0)
	{
		if (listlangs)
			dbname = argv[optind++];
		else
		{
			langname = argv[optind++];
			if (argc - optind > 0)
				dbname = argv[optind++];
		}
	}

	if (argc - optind > 0)
	{
Bruce Momjian's avatar
Bruce Momjian committed
119
		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
120
				progname, argv[optind]);
Bruce Momjian's avatar
Bruce Momjian committed
121
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
		exit(1);
	}

	if (dbname == NULL)
	{
		if (getenv("PGDATABASE"))
			dbname = getenv("PGDATABASE");
		else if (getenv("PGUSER"))
			dbname = getenv("PGUSER");
		else
			dbname = get_user_name(progname);
	}

	initPQExpBuffer(&sql);

	/*
	 * List option
	 */
	if (listlangs)
	{
		printQueryOpt popt;
143
		static const bool translate_columns[] = {false, true};
144

145
		conn = connectDatabase(dbname, host, port, username, prompt_password,
146
							   progname);
147

148
		printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
149 150
				"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
						  "FROM pg_catalog.pg_language WHERE lanispl;",
151 152 153
						  gettext_noop("Name"),
						  gettext_noop("yes"), gettext_noop("no"),
						  gettext_noop("Trusted?"));
154 155 156 157 158
		result = executeQuery(conn, sql.data, progname, echo);

		memset(&popt, 0, sizeof(popt));
		popt.topt.format = PRINT_ALIGNED;
		popt.topt.border = 1;
159 160
		popt.topt.start_table = true;
		popt.topt.stop_table = true;
161 162
		popt.topt.encoding = PQclientEncoding(conn);
		popt.title = _("Procedural Languages");
163 164
		popt.translate_header = true;
		popt.translate_columns = translate_columns;
165
		printQuery(result, &popt, stdout, NULL);
166 167 168 169 170 171 172

		PQfinish(conn);
		exit(0);
	}

	if (langname == NULL)
	{
173
		fprintf(stderr, _("%s: missing required argument language name\n"),
174
				progname);
175
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
176
				progname);
177 178 179 180 181 182 183
		exit(1);
	}

	for (p = langname; *p; p++)
		if (*p >= 'A' && *p <= 'Z')
			*p += ('a' - 'A');

184
	conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
185

186
	/*
187 188
	 * Force schema search path to be just pg_catalog, so that we don't have
	 * to be paranoid about search paths below.
189
	 */
Bruce Momjian's avatar
Bruce Momjian committed
190
	executeCommand(conn, "SET search_path = pg_catalog;", progname, echo);
191

192
	/*
193 194
	 * Make sure the language is installed and find the OIDs of the handler
	 * and validator functions
195
	 */
196
	printfPQExpBuffer(&sql, "SELECT lanplcallfoid, lanvalidator "
197
					  "FROM pg_language WHERE lanname = '%s' AND lanispl;",
198
					  langname);
199 200 201 202
	result = executeQuery(conn, sql.data, progname, echo);
	if (PQntuples(result) == 0)
	{
		PQfinish(conn);
203 204
		fprintf(stderr, _("%s: language \"%s\" is not installed in "
						  "database \"%s\"\n"),
205 206 207
				progname, langname, dbname);
		exit(1);
	}
208 209 210
	lanplcallfoid = atooid(PQgetvalue(result, 0, 0));
	lanvalidator = atooid(PQgetvalue(result, 0, 1));
	PQclear(result);
211 212 213 214

	/*
	 * Check that there are no functions left defined in that language
	 */
215 216 217
	printfPQExpBuffer(&sql, "SELECT count(proname) FROM pg_proc P, "
					  "pg_language L WHERE P.prolang = L.oid "
					  "AND L.lanname = '%s';", langname);
218
	result = executeQuery(conn, sql.data, progname, echo);
Bruce Momjian's avatar
Bruce Momjian committed
219
	if (strcmp(PQgetvalue(result, 0, 0), "0") != 0)
220 221 222
	{
		PQfinish(conn);
		fprintf(stderr,
223 224
				_("%s: still %s functions declared in language \"%s\"; "
				  "language not removed\n"),
225 226 227 228 229 230 231 232
				progname, PQgetvalue(result, 0, 0), langname);
		exit(1);
	}
	PQclear(result);

	/*
	 * Check that the handler function isn't used by some other language
	 */
233
	printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language "
234
					  "WHERE lanplcallfoid = %u AND lanname <> '%s';",
235
					  lanplcallfoid, langname);
236
	result = executeQuery(conn, sql.data, progname, echo);
Bruce Momjian's avatar
Bruce Momjian committed
237
	if (strcmp(PQgetvalue(result, 0, 0), "0") == 0)
238 239 240 241 242 243 244 245 246 247
		keephandler = false;
	else
		keephandler = true;
	PQclear(result);

	/*
	 * Find the handler name
	 */
	if (!keephandler)
	{
248 249
		printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname "
						  "FROM pg_namespace ns WHERE ns.oid = pronamespace) "
250
						  "AS prons FROM pg_proc WHERE oid = %u;",
251
						  lanplcallfoid);
252
		result = executeQuery(conn, sql.data, progname, echo);
253
		handler = strdup(PQgetvalue(result, 0, 0));
254
		handler_ns = strdup(PQgetvalue(result, 0, 1));
255
		PQclear(result);
256 257
	}
	else
258
	{
259
		handler = NULL;
260 261
		handler_ns = NULL;
	}
262 263

	/*
264 265 266 267
	 * Check that the validator function isn't used by some other language
	 */
	if (OidIsValid(lanvalidator))
	{
268
		printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language "
269
						  "WHERE lanvalidator = %u AND lanname <> '%s';",
270
						  lanvalidator, langname);
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
		result = executeQuery(conn, sql.data, progname, echo);
		if (strcmp(PQgetvalue(result, 0, 0), "0") == 0)
			keepvalidator = false;
		else
			keepvalidator = true;
		PQclear(result);
	}
	else
		keepvalidator = true;	/* don't try to delete it */

	/*
	 * Find the validator name
	 */
	if (!keepvalidator)
	{
286 287
		printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname "
						  "FROM pg_namespace ns WHERE ns.oid = pronamespace) "
288
						  "AS prons FROM pg_proc WHERE oid = %u;",
289
						  lanvalidator);
290 291
		result = executeQuery(conn, sql.data, progname, echo);
		validator = strdup(PQgetvalue(result, 0, 0));
292
		validator_ns = strdup(PQgetvalue(result, 0, 1));
293 294 295
		PQclear(result);
	}
	else
296
	{
297
		validator = NULL;
298 299
		validator_ns = NULL;
	}
300 301 302

	/*
	 * Drop the language and the functions
303
	 */
304
	printfPQExpBuffer(&sql, "DROP LANGUAGE \"%s\";\n", langname);
305
	if (!keephandler)
306
		appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" ();\n",
307
						  handler_ns, handler);
308
	if (!keepvalidator)
309
		appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (oid);\n",
310
						  validator_ns, validator);
311 312 313 314 315 316 317 318 319 320 321
	if (echo)
		printf("%s", sql.data);
	result = PQexec(conn, sql.data);
	if (PQresultStatus(result) != PGRES_COMMAND_OK)
	{
		fprintf(stderr, _("%s: language removal failed: %s"),
				progname, PQerrorMessage(conn));
		PQfinish(conn);
		exit(1);
	}

322
	PQclear(result);
323 324 325 326 327 328 329 330 331 332 333 334
	PQfinish(conn);
	exit(0);
}


static void
help(const char *progname)
{
	printf(_("%s removes a procedural language from a database.\n\n"), progname);
	printf(_("Usage:\n"));
	printf(_("  %s [OPTION]... LANGNAME [DBNAME]\n"), progname);
	printf(_("\nOptions:\n"));
335
	printf(_("  -d, --dbname=DBNAME       database from which to remove the language\n"));
336 337
	printf(_("  -e, --echo                show the commands being sent to the server\n"));
	printf(_("  -l, --list                show a list of currently installed languages\n"));
338 339 340
	printf(_("  --help                    show this help, then exit\n"));
	printf(_("  --version                 output version information, then exit\n"));
	printf(_("\nConnection options:\n"));
341
	printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
342 343
	printf(_("  -p, --port=PORT           database server port\n"));
	printf(_("  -U, --username=USERNAME   user name to connect as\n"));
344
	printf(_("  -w, --no-password         never prompt for password\n"));
345
	printf(_("  -W, --password            force password prompt\n"));
346 347
	printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}