1 /*-------------------------------------------------------------------------
2  *
3  * droplang
4  *
5  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
6  * Portions Copyright (c) 1994, Regents of the University of California
7  *
8  * src/bin/scripts/droplang.c
9  *
10  *-------------------------------------------------------------------------
11  */
12 #include "postgres_fe.h"
13 
14 #include "common.h"
15 #include "fe_utils/print.h"
16 
17 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
18 
19 
20 static void help(const char *progname);
21 
22 
23 int
main(int argc,char * argv[])24 main(int argc, char *argv[])
25 {
26 	static struct option long_options[] = {
27 		{"list", no_argument, NULL, 'l'},
28 		{"host", required_argument, NULL, 'h'},
29 		{"port", required_argument, NULL, 'p'},
30 		{"username", required_argument, NULL, 'U'},
31 		{"no-password", no_argument, NULL, 'w'},
32 		{"password", no_argument, NULL, 'W'},
33 		{"dbname", required_argument, NULL, 'd'},
34 		{"echo", no_argument, NULL, 'e'},
35 		{NULL, 0, NULL, 0}
36 	};
37 
38 	const char *progname;
39 	int			optindex;
40 	int			c;
41 	bool		listlangs = false;
42 	const char *dbname = NULL;
43 	char	   *host = NULL;
44 	char	   *port = NULL;
45 	char	   *username = NULL;
46 	enum trivalue prompt_password = TRI_DEFAULT;
47 	ConnParams	cparams;
48 	bool		echo = false;
49 	char	   *langname = NULL;
50 	char	   *p;
51 	PQExpBufferData sql;
52 	PGconn	   *conn;
53 	PGresult   *result;
54 
55 	progname = get_progname(argv[0]);
56 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
57 
58 	handle_help_version_opts(argc, argv, "droplang", help);
59 
60 	while ((c = getopt_long(argc, argv, "lh:p:U:wWd:e", long_options, &optindex)) != -1)
61 	{
62 		switch (c)
63 		{
64 			case 'l':
65 				listlangs = true;
66 				break;
67 			case 'h':
68 				host = pg_strdup(optarg);
69 				break;
70 			case 'p':
71 				port = pg_strdup(optarg);
72 				break;
73 			case 'U':
74 				username = pg_strdup(optarg);
75 				break;
76 			case 'w':
77 				prompt_password = TRI_NO;
78 				break;
79 			case 'W':
80 				prompt_password = TRI_YES;
81 				break;
82 			case 'd':
83 				dbname = pg_strdup(optarg);
84 				break;
85 			case 'e':
86 				echo = true;
87 				break;
88 			default:
89 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
90 				exit(1);
91 		}
92 	}
93 
94 	/*
95 	 * We set dbname from positional arguments if it is not already set by
96 	 * option arguments -d. If not doing listlangs, positional dbname must
97 	 * follow positional langname.
98 	 */
99 
100 	if (argc - optind > 0)
101 	{
102 		if (listlangs)
103 		{
104 			if (dbname == NULL)
105 				dbname = argv[optind++];
106 		}
107 		else
108 		{
109 			langname = argv[optind++];
110 			if (argc - optind > 0 && dbname == NULL)
111 				dbname = argv[optind++];
112 		}
113 	}
114 
115 	if (argc - optind > 0)
116 	{
117 		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
118 				progname, argv[optind]);
119 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
120 		exit(1);
121 	}
122 
123 	if (dbname == NULL)
124 	{
125 		if (getenv("PGDATABASE"))
126 			dbname = getenv("PGDATABASE");
127 		else if (getenv("PGUSER"))
128 			dbname = getenv("PGUSER");
129 		else
130 			dbname = get_user_name_or_exit(progname);
131 	}
132 
133 	cparams.dbname = dbname;
134 	cparams.pghost = host;
135 	cparams.pgport = port;
136 	cparams.pguser = username;
137 	cparams.prompt_password = prompt_password;
138 	cparams.override_dbname = NULL;
139 
140 	initPQExpBuffer(&sql);
141 
142 	/*
143 	 * List option
144 	 */
145 	if (listlangs)
146 	{
147 		printQueryOpt popt;
148 		static const bool translate_columns[] = {false, true};
149 
150 		conn = connectDatabase(&cparams,
151 							   progname, echo, false, false);
152 
153 		printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
154 				"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
155 						  "FROM pg_catalog.pg_language WHERE lanispl;",
156 						  gettext_noop("Name"),
157 						  gettext_noop("yes"), gettext_noop("no"),
158 						  gettext_noop("Trusted?"));
159 		result = executeQuery(conn, sql.data, progname, echo);
160 
161 		memset(&popt, 0, sizeof(popt));
162 		popt.topt.format = PRINT_ALIGNED;
163 		popt.topt.border = 1;
164 		popt.topt.start_table = true;
165 		popt.topt.stop_table = true;
166 		popt.topt.encoding = PQclientEncoding(conn);
167 		popt.title = _("Procedural Languages");
168 		popt.translate_header = true;
169 		popt.translate_columns = translate_columns;
170 		popt.n_translate_columns = lengthof(translate_columns);
171 
172 		printQuery(result, &popt, stdout, false, NULL);
173 
174 		PQfinish(conn);
175 		exit(0);
176 	}
177 
178 	if (langname == NULL)
179 	{
180 		fprintf(stderr, _("%s: missing required argument language name\n"),
181 				progname);
182 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
183 				progname);
184 		exit(1);
185 	}
186 
187 	/* lower case language name */
188 	for (p = langname; *p; p++)
189 		if (*p >= 'A' && *p <= 'Z')
190 			*p += ('a' - 'A');
191 
192 	conn = connectDatabase(&cparams,
193 						   progname, echo, false, false);
194 
195 	/*
196 	 * Make sure the language is installed
197 	 */
198 	printfPQExpBuffer(&sql, "SELECT oid "
199 					  "FROM pg_language WHERE lanname = '%s' AND lanispl;",
200 					  langname);
201 	result = executeQuery(conn, sql.data, progname, echo);
202 	if (PQntuples(result) == 0)
203 	{
204 		fprintf(stderr, _("%s: language \"%s\" is not installed in "
205 						  "database \"%s\"\n"),
206 				progname, langname, PQdb(conn));
207 		PQfinish(conn);
208 		exit(1);
209 	}
210 	PQclear(result);
211 
212 	/*
213 	 * Attempt to drop the language.  We do not use CASCADE, so that the drop
214 	 * will fail if there are any functions in the language.
215 	 */
216 	printfPQExpBuffer(&sql, "DROP EXTENSION \"%s\";", langname);
217 
218 	if (echo)
219 		printf("%s\n", sql.data);
220 	result = PQexec(conn, sql.data);
221 	if (PQresultStatus(result) != PGRES_COMMAND_OK)
222 	{
223 		fprintf(stderr, _("%s: language removal failed: %s"),
224 				progname, PQerrorMessage(conn));
225 		PQfinish(conn);
226 		exit(1);
227 	}
228 
229 	PQclear(result);
230 	PQfinish(conn);
231 	exit(0);
232 }
233 
234 
235 static void
help(const char * progname)236 help(const char *progname)
237 {
238 	printf(_("%s removes a procedural language from a database.\n\n"), progname);
239 	printf(_("Usage:\n"));
240 	printf(_("  %s [OPTION]... LANGNAME [DBNAME]\n"), progname);
241 	printf(_("\nOptions:\n"));
242 	printf(_("  -d, --dbname=DBNAME       database from which to remove the language\n"));
243 	printf(_("  -e, --echo                show the commands being sent to the server\n"));
244 	printf(_("  -l, --list                show a list of currently installed languages\n"));
245 	printf(_("  -V, --version             output version information, then exit\n"));
246 	printf(_("  -?, --help                show this help, then exit\n"));
247 	printf(_("\nConnection options:\n"));
248 	printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
249 	printf(_("  -p, --port=PORT           database server port\n"));
250 	printf(_("  -U, --username=USERNAME   user name to connect as\n"));
251 	printf(_("  -w, --no-password         never prompt for password\n"));
252 	printf(_("  -W, --password            force password prompt\n"));
253 	printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
254 }
255