1/*-------------------------------------------------------------------------
2 *
3 * createdb
4 *
5 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * src/bin/scripts/createdb.c
9 *
10 *-------------------------------------------------------------------------
11 */
12#include "postgres_fe.h"
13
14#include "common.h"
15#include "common/logging.h"
16#include "fe_utils/string_utils.h"
17
18
19static void help(const char *progname);
20
21
22int
23main(int argc, char *argv[])
24{
25 static struct option long_options[] = {
26 {"host", required_argument, NULL, 'h'},
27 {"port", required_argument, NULL, 'p'},
28 {"username", required_argument, NULL, 'U'},
29 {"no-password", no_argument, NULL, 'w'},
30 {"password", no_argument, NULL, 'W'},
31 {"echo", no_argument, NULL, 'e'},
32 {"owner", required_argument, NULL, 'O'},
33 {"tablespace", required_argument, NULL, 'D'},
34 {"template", required_argument, NULL, 'T'},
35 {"encoding", required_argument, NULL, 'E'},
36 {"lc-collate", required_argument, NULL, 1},
37 {"lc-ctype", required_argument, NULL, 2},
38 {"locale", required_argument, NULL, 'l'},
39 {"maintenance-db", required_argument, NULL, 3},
40 {NULL, 0, NULL, 0}
41 };
42
43 const char *progname;
44 int optindex;
45 int c;
46
47 const char *dbname = NULL;
48 const char *maintenance_db = NULL;
49 char *comment = NULL;
50 char *host = NULL;
51 char *port = NULL;
52 char *username = NULL;
53 enum trivalue prompt_password = TRI_DEFAULT;
54 bool echo = false;
55 char *owner = NULL;
56 char *tablespace = NULL;
57 char *template = NULL;
58 char *encoding = NULL;
59 char *lc_collate = NULL;
60 char *lc_ctype = NULL;
61 char *locale = NULL;
62
63 PQExpBufferData sql;
64
65 PGconn *conn;
66 PGresult *result;
67
68 pg_logging_init(argv[0]);
69 progname = get_progname(argv[0]);
70 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
71
72 handle_help_version_opts(argc, argv, "createdb", help);
73
74 while ((c = getopt_long(argc, argv, "h:p:U:wWeO:D:T:E:l:", long_options, &optindex)) != -1)
75 {
76 switch (c)
77 {
78 case 'h':
79 host = pg_strdup(optarg);
80 break;
81 case 'p':
82 port = pg_strdup(optarg);
83 break;
84 case 'U':
85 username = pg_strdup(optarg);
86 break;
87 case 'w':
88 prompt_password = TRI_NO;
89 break;
90 case 'W':
91 prompt_password = TRI_YES;
92 break;
93 case 'e':
94 echo = true;
95 break;
96 case 'O':
97 owner = pg_strdup(optarg);
98 break;
99 case 'D':
100 tablespace = pg_strdup(optarg);
101 break;
102 case 'T':
103 template = pg_strdup(optarg);
104 break;
105 case 'E':
106 encoding = pg_strdup(optarg);
107 break;
108 case 1:
109 lc_collate = pg_strdup(optarg);
110 break;
111 case 2:
112 lc_ctype = pg_strdup(optarg);
113 break;
114 case 'l':
115 locale = pg_strdup(optarg);
116 break;
117 case 3:
118 maintenance_db = pg_strdup(optarg);
119 break;
120 default:
121 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
122 exit(1);
123 }
124 }
125
126 switch (argc - optind)
127 {
128 case 0:
129 break;
130 case 1:
131 dbname = argv[optind];
132 break;
133 case 2:
134 dbname = argv[optind];
135 comment = argv[optind + 1];
136 break;
137 default:
138 pg_log_error("too many command-line arguments (first is \"%s\")",
139 argv[optind + 2]);
140 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
141 exit(1);
142 }
143
144 if (locale)
145 {
146 if (lc_ctype)
147 {
148 pg_log_error("only one of --locale and --lc-ctype can be specified");
149 exit(1);
150 }
151 if (lc_collate)
152 {
153 pg_log_error("only one of --locale and --lc-collate can be specified");
154 exit(1);
155 }
156 lc_ctype = locale;
157 lc_collate = locale;
158 }
159
160 if (encoding)
161 {
162 if (pg_char_to_encoding(encoding) < 0)
163 {
164 pg_log_error("\"%s\" is not a valid encoding name", encoding);
165 exit(1);
166 }
167 }
168
169 if (dbname == NULL)
170 {
171 if (getenv("PGDATABASE"))
172 dbname = getenv("PGDATABASE");
173 else if (getenv("PGUSER"))
174 dbname = getenv("PGUSER");
175 else
176 dbname = get_user_name_or_exit(progname);
177 }
178
179 initPQExpBuffer(&sql);
180
181 appendPQExpBuffer(&sql, "CREATE DATABASE %s",
182 fmtId(dbname));
183
184 if (owner)
185 appendPQExpBuffer(&sql, " OWNER %s", fmtId(owner));
186 if (tablespace)
187 appendPQExpBuffer(&sql, " TABLESPACE %s", fmtId(tablespace));
188 if (encoding)
189 appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
190 if (template)
191 appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
192 if (lc_collate)
193 appendPQExpBuffer(&sql, " LC_COLLATE '%s'", lc_collate);
194 if (lc_ctype)
195 appendPQExpBuffer(&sql, " LC_CTYPE '%s'", lc_ctype);
196
197 appendPQExpBufferChar(&sql, ';');
198
199 /* No point in trying to use postgres db when creating postgres db. */
200 if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
201 maintenance_db = "template1";
202
203 conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
204 prompt_password, progname, echo);
205
206 if (echo)
207 printf("%s\n", sql.data);
208 result = PQexec(conn, sql.data);
209
210 if (PQresultStatus(result) != PGRES_COMMAND_OK)
211 {
212 pg_log_error("database creation failed: %s", PQerrorMessage(conn));
213 PQfinish(conn);
214 exit(1);
215 }
216
217 PQclear(result);
218
219 if (comment)
220 {
221 printfPQExpBuffer(&sql, "COMMENT ON DATABASE %s IS ", fmtId(dbname));
222 appendStringLiteralConn(&sql, comment, conn);
223 appendPQExpBufferChar(&sql, ';');
224
225 if (echo)
226 printf("%s\n", sql.data);
227 result = PQexec(conn, sql.data);
228
229 if (PQresultStatus(result) != PGRES_COMMAND_OK)
230 {
231 pg_log_error("comment creation failed (database was created): %s",
232 PQerrorMessage(conn));
233 PQfinish(conn);
234 exit(1);
235 }
236
237 PQclear(result);
238 }
239
240 PQfinish(conn);
241
242 exit(0);
243}
244
245
246static void
247help(const char *progname)
248{
249 printf(_("%s creates a PostgreSQL database.\n\n"), progname);
250 printf(_("Usage:\n"));
251 printf(_(" %s [OPTION]... [DBNAME] [DESCRIPTION]\n"), progname);
252 printf(_("\nOptions:\n"));
253 printf(_(" -D, --tablespace=TABLESPACE default tablespace for the database\n"));
254 printf(_(" -e, --echo show the commands being sent to the server\n"));
255 printf(_(" -E, --encoding=ENCODING encoding for the database\n"));
256 printf(_(" -l, --locale=LOCALE locale settings for the database\n"));
257 printf(_(" --lc-collate=LOCALE LC_COLLATE setting for the database\n"));
258 printf(_(" --lc-ctype=LOCALE LC_CTYPE setting for the database\n"));
259 printf(_(" -O, --owner=OWNER database user to own the new database\n"));
260 printf(_(" -T, --template=TEMPLATE template database to copy\n"));
261 printf(_(" -V, --version output version information, then exit\n"));
262 printf(_(" -?, --help show this help, then exit\n"));
263 printf(_("\nConnection options:\n"));
264 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
265 printf(_(" -p, --port=PORT database server port\n"));
266 printf(_(" -U, --username=USERNAME user name to connect as\n"));
267 printf(_(" -w, --no-password never prompt for password\n"));
268 printf(_(" -W, --password force password prompt\n"));
269 printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
270 printf(_("\nBy default, a database with the same name as the current user is created.\n"));
271 printf(_("\nReport bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
272}
273