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