://nPrivileges.PrivilegshowCard(380,150,8,2);

/ pgsql953
项目语言:None
权限:read-only(如需更高权限请先加入项目)
Index: createuser.c
===================================================================
--- createuser.c (revision 0)
+++ createuser.c (revision 2)
@@ -0,0 +1,381 @@
+/*-------------------------------------------------------------------------
+ * createuser
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/createuser.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &dumputils.h&
+static void help(const char *progname);
+main(int argc, char *argv[])
+ static struct option long_options[] = {
{&host&, required_argument, NULL, 'h'},
{&port&, required_argument, NULL, 'p'},
{&username&, required_argument, NULL, 'U'},
{&role&, required_argument, NULL, 'g'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&echo&, no_argument, NULL, 'e'},
{&createdb&, no_argument, NULL, 'd'},
{&no-createdb&, no_argument, NULL, 'D'},
{&superuser&, no_argument, NULL, 's'},
{&no-superuser&, no_argument, NULL, 'S'},
{&createrole&, no_argument, NULL, 'r'},
{&no-createrole&, no_argument, NULL, 'R'},
{&inherit&, no_argument, NULL, 'i'},
{&no-inherit&, no_argument, NULL, 'I'},
{&login&, no_argument, NULL, 'l'},
{&no-login&, no_argument, NULL, 'L'},
{&replication&, no_argument, NULL, 1},
{&no-replication&, no_argument, NULL, 2},
{&interactive&, no_argument, NULL, 3},
/* adduser is obsolete, undocumented spelling of superuser */
{&adduser&, no_argument, NULL, 'a'},
{&no-adduser&, no_argument, NULL, 'A'},
{&connection-limit&, required_argument, NULL, 'c'},
{&pwprompt&, no_argument, NULL, 'P'},
{&encrypted&, no_argument, NULL, 'E'},
{&unencrypted&, no_argument, NULL, 'N'},
{NULL, 0, NULL, 0}
+ const char *
+ const char *newuser = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ SimpleStringList roles = {NULL, NULL};
+ enum trivalue prompt_password = TRI_DEFAULT;
interactive =
*conn_limit = NULL;
pwprompt =
*newpassword = NULL;
+ /* Tri-valued variables.
+ enum trivalue createdb = TRI_DEFAULT,
superuser = TRI_DEFAULT,
createrole = TRI_DEFAULT,
inherit = TRI_DEFAULT,
login = TRI_DEFAULT,
replication = TRI_DEFAULT,
encrypted = TRI_DEFAULT;
+ PQExpBufferD
+ PGresult
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &createuser&, help);
+ while ((c = getopt_long(argc, argv, &h:p:U:g:wWedDsSaArRiIlLc:PEN&,
long_options, &optindex)) != -1)
switch (c)
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'g':
simple_string_list_append(&roles, optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'e':
case 'd':
createdb = TRI_YES;
case 'D':
createdb = TRI_NO;
case 's':
case 'a':
superuser = TRI_YES;
case 'S':
case 'A':
superuser = TRI_NO;
case 'r':
createrole = TRI_YES;
case 'R':
createrole = TRI_NO;
case 'i':
inherit = TRI_YES;
case 'I':
inherit = TRI_NO;
case 'l':
login = TRI_YES;
case 'L':
login = TRI_NO;
case 'c':
conn_limit = pg_strdup(optarg);
case 'P':
pwprompt =
case 'E':
encrypted = TRI_YES;
case 'N':
encrypted = TRI_NO;
replication = TRI_YES;
replication = TRI_NO;
interactive =
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ switch (argc - optind)
newuser = argv[optind];
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind + 1]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (newuser == NULL)
if (interactive)
newuser = simple_prompt(&Enter name of role to add: &, 128, true);
if (getenv(&PGUSER&))
newuser = getenv(&PGUSER&);
newuser = get_user_name_or_exit(progname);
+ if (pwprompt)
pw1 = simple_prompt(&Enter password for new role: &, 100, false);
pw2 = simple_prompt(&Enter it again: &, 100, false);
if (strcmp(pw1, pw2) != 0)
fprintf(stderr, _(&Passwords didn't match.\n&));
newpassword = pw1;
free(pw2);
+ if (superuser == 0)
if (interactive && yesno_prompt(&Shall the new role be a superuser?&))
superuser = TRI_YES;
superuser = TRI_NO;
+ if (superuser == TRI_YES)
/* Not much point in trying to restrict a superuser */
createdb = TRI_YES;
createrole = TRI_YES;
+ if (createdb == 0)
if (interactive && yesno_prompt(&Shall the new role be allowed to create databases?&))
createdb = TRI_YES;
createdb = TRI_NO;
+ if (createrole == 0)
if (interactive && yesno_prompt(&Shall the new role be allowed to create more new roles?&))
createrole = TRI_YES;
createrole = TRI_NO;
+ if (inherit == 0)
inherit = TRI_YES;
+ if (login == 0)
login = TRI_YES;
+ conn = connectDatabase(&postgres&, host, port, username, prompt_password,
progname, false, false);
+ initPQExpBuffer(&sql);
+ printfPQExpBuffer(&sql, &CREATE ROLE %s&, fmtId(newuser));
+ if (newpassword)
if (encrypted == TRI_YES)
appendPQExpBufferStr(&sql, & ENCRYPTED&);
if (encrypted == TRI_NO)
appendPQExpBufferStr(&sql, & UNENCRYPTED&);
appendPQExpBufferStr(&sql, & PASSWORD &);
if (encrypted != TRI_NO)
*encrypted_
encrypted_password = PQencryptPassword(newpassword,
if (!encrypted_password)
fprintf(stderr, _(&Password encryption failed.\n&));
appendStringLiteralConn(&sql, encrypted_password, conn);
PQfreemem(encrypted_password);
appendStringLiteralConn(&sql, newpassword, conn);
+ if (superuser == TRI_YES)
appendPQExpBufferStr(&sql, & SUPERUSER&);
+ if (superuser == TRI_NO)
appendPQExpBufferStr(&sql, & NOSUPERUSER&);
+ if (createdb == TRI_YES)
appendPQExpBufferStr(&sql, & CREATEDB&);
+ if (createdb == TRI_NO)
appendPQExpBufferStr(&sql, & NOCREATEDB&);
+ if (createrole == TRI_YES)
appendPQExpBufferStr(&sql, & CREATEROLE&);
+ if (createrole == TRI_NO)
appendPQExpBufferStr(&sql, & NOCREATEROLE&);
+ if (inherit == TRI_YES)
appendPQExpBufferStr(&sql, & INHERIT&);
+ if (inherit == TRI_NO)
appendPQExpBufferStr(&sql, & NOINHERIT&);
+ if (login == TRI_YES)
appendPQExpBufferStr(&sql, & LOGIN&);
+ if (login == TRI_NO)
appendPQExpBufferStr(&sql, & NOLOGIN&);
+ if (replication == TRI_YES)
appendPQExpBufferStr(&sql, & REPLICATION&);
+ if (replication == TRI_NO)
appendPQExpBufferStr(&sql, & NOREPLICATION&);
+ if (conn_limit != NULL)
appendPQExpBuffer(&sql, & CONNECTION LIMIT %s&, conn_limit);
+ if (roles.head != NULL)
SimpleStringListCell *
appendPQExpBufferStr(&sql, & IN ROLE &);
for (cell = roles. cell = cell-&next)
if (cell-&next)
appendPQExpBuffer(&sql, &%s,&, fmtId(cell-&val));
appendPQExpBuffer(&sql, &%s&, fmtId(cell-&val));
+ appendPQExpBufferChar(&sql, ';');
+ if (echo)
printf(&%s\n&, sql.data);
+ result = PQexec(conn, sql.data);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
fprintf(stderr, _(&%s: creation of new role failed: %s&),
progname, PQerrorMessage(conn));
PQfinish(conn);
+ PQclear(result);
+ PQfinish(conn);
+ exit(0);
+static void
+help(const char *progname)
+ printf(_(&%s creates a new PostgreSQL role.\n\n&), progname);
+ printf(_(&Usage:\n&));
+ printf(_(&
%s [OPTION]... [ROLENAME]\n&), progname);
+ printf(_(&\nOptions:\n&));
+ printf(_(&
-c, --connection-limit=N
connection limit for role (default: no limit)\n&));
+ printf(_(&
-d, --createdb
role can create new databases\n&));
+ printf(_(&
-D, --no-createdb
role cannot create databases (default)\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-E, --encrypted
encrypt stored password\n&));
+ printf(_(&
-g, --role=ROLE
new role will be a member of this role\n&));
+ printf(_(&
-i, --inherit
role inherits privileges of roles it is a\n&
member of (default)\n&));
+ printf(_(&
-I, --no-inherit
role does not inherit privileges\n&));
+ printf(_(&
-l, --login
role can login (default)\n&));
+ printf(_(&
-L, --no-login
role cannot login\n&));
+ printf(_(&
-N, --unencrypted
do not encrypt stored password\n&));
+ printf(_(&
-P, --pwprompt
assign a password to new role\n&));
+ printf(_(&
-r, --createrole
role can create new roles\n&));
+ printf(_(&
-R, --no-createrole
role cannot create roles (default)\n&));
+ printf(_(&
-s, --superuser
role will be superuser\n&));
+ printf(_(&
-S, --no-superuser
role will not be superuser (default)\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
--interactive
prompt for missing role name and attributes rather\n&
than using defaults\n&));
+ printf(_(&
--replication
role can initiate replication\n&));
+ printf(_(&
--no-replication
role cannot initiate replication\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as (not the one to create)\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: dropuser.c
===================================================================
--- dropuser.c (revision 0)
+++ dropuser.c (revision 2)
@@ -0,0 +1,172 @@
+/*-------------------------------------------------------------------------
+ * dropuser
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/dropuser.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &dumputils.h&
+static void help(const char *progname);
+main(int argc, char *argv[])
+ static int if_exists = 0;
+ static struct option long_options[] = {
{&host&, required_argument, NULL, 'h'},
{&port&, required_argument, NULL, 'p'},
{&username&, required_argument, NULL, 'U'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&echo&, no_argument, NULL, 'e'},
{&interactive&, no_argument, NULL, 'i'},
{&if-exists&, no_argument, &if_exists, 1},
{NULL, 0, NULL, 0}
+ const char *
*dropuser = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
interactive =
+ PQExpBufferD
+ PGresult
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &dropuser&, help);
+ while ((c = getopt_long(argc, argv, &h:p:U:wWei&, long_options, &optindex)) != -1)
switch (c)
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'e':
case 'i':
interactive =
/* this covers the long options */
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ switch (argc - optind)
dropuser = argv[optind];
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind + 1]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (dropuser == NULL)
if (interactive)
dropuser = simple_prompt(&Enter name of role to drop: &, 128, true);
fprintf(stderr, _(&%s: missing required argument role name\n&), progname);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (interactive)
printf(_(&Role \&%s\& will be permanently removed.\n&), dropuser);
if (!yesno_prompt(&Are you sure?&))
+ initPQExpBuffer(&sql);
+ appendPQExpBuffer(&sql, &DROP ROLE %s%s;&,
(if_exists ? &IF EXISTS & : &&), fmtId(dropuser));
+ conn = connectDatabase(&postgres&, host, port, username, prompt_password,
progname, false, false);
+ if (echo)
printf(&%s\n&, sql.data);
+ result = PQexec(conn, sql.data);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
fprintf(stderr, _(&%s: removal of role \&%s\& failed: %s&),
progname, dropuser, PQerrorMessage(conn));
PQfinish(conn);
+ PQclear(result);
+ PQfinish(conn);
+ exit(0);
+static void
+help(const char *progname)
+ printf(_(&%s removes a PostgreSQL role.\n\n&), progname);
+ printf(_(&Usage:\n&));
+ printf(_(&
%s [OPTION]... [ROLENAME]\n&), progname);
+ printf(_(&\nOptions:\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-i, --interactive
prompt before deleting anything, and prompt for\n&
role name if not specified\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
--if-exists
don't report error if user doesn't exist\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as (not the one to drop)\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: reindexdb.c
===================================================================
--- reindexdb.c (revision 0)
+++ reindexdb.c (revision 2)
@@ -0,0 +1,415 @@
+/*-------------------------------------------------------------------------
+ * reindexdb
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * src/bin/scripts/reindexdb.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &dumputils.h&
+static void reindex_one_database(const char *name, const char *dbname,
const char *type, const char *host,
const char *port, const char *username,
enum trivalue prompt_password, const char *progname,
bool echo, bool verbose);
+static void reindex_all_databases(const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo,
bool quiet, bool verbose);
+static void reindex_system_catalogs(const char *dbname,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool verbose);
+static void help(const char *progname);
+main(int argc, char *argv[])
+ static struct option long_options[] = {
{&host&, required_argument, NULL, 'h'},
{&port&, required_argument, NULL, 'p'},
{&username&, required_argument, NULL, 'U'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&echo&, no_argument, NULL, 'e'},
{&quiet&, no_argument, NULL, 'q'},
{&schema&, required_argument, NULL, 'S'},
{&dbname&, required_argument, NULL, 'd'},
{&all&, no_argument, NULL, 'a'},
{&system&, no_argument, NULL, 's'},
{&table&, required_argument, NULL, 't'},
{&index&, required_argument, NULL, 'i'},
{&verbose&, no_argument, NULL, 'v'},
{&maintenance-db&, required_argument, NULL, 2},
{NULL, 0, NULL, 0}
+ const char *
+ const char *dbname = NULL;
+ const char *maintenance_db = NULL;
+ const char *host = NULL;
+ const char *port = NULL;
+ const char *username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
syscatalog =
+ SimpleStringList indexes = {NULL, NULL};
+ SimpleStringList tables = {NULL, NULL};
+ SimpleStringList schemas = {NULL, NULL};
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &reindexdb&, help);
+ /* process command-line options */
+ while ((c = getopt_long(argc, argv, &h:p:U:wWeqS:d:ast:i:v&, long_options, &optindex)) != -1)
switch (c)
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'e':
case 'q':
case 'S':
simple_string_list_append(&schemas, optarg);
case 'd':
dbname = pg_strdup(optarg);
case 'a':
case 's':
syscatalog =
case 't':
simple_string_list_append(&tables, optarg);
case 'i':
simple_string_list_append(&indexes, optarg);
case 'v':
maintenance_db = pg_strdup(optarg);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
* Non-option argument specifies database name as long as it wasn't
* already specified with -d / --dbname
+ if (optind & argc && dbname == NULL)
dbname = argv[optind];
+ if (optind & argc)
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ setup_cancel_handler();
+ if (alldb)
if (dbname)
fprintf(stderr, _(&%s: cannot reindex all databases and a specific one at the same time\n&), progname);
if (syscatalog)
fprintf(stderr, _(&%s: cannot reindex all databases and system catalogs at the same time\n&), progname);
if (schemas.head != NULL)
fprintf(stderr, _(&%s: cannot reindex specific schema(s) in all databases\n&), progname);
if (tables.head != NULL)
fprintf(stderr, _(&%s: cannot reindex specific table(s) in all databases\n&), progname);
if (indexes.head != NULL)
fprintf(stderr, _(&%s: cannot reindex specific index(es) in all databases\n&), progname);
reindex_all_databases(maintenance_db, host, port, username,
prompt_password, progname, echo, quiet, verbose);
+ else if (syscatalog)
if (schemas.head != NULL)
fprintf(stderr, _(&%s: cannot reindex specific schema(s) and system catalogs at the same time\n&), progname);
if (tables.head != NULL)
fprintf(stderr, _(&%s: cannot reindex specific table(s) and system catalogs at the same time\n&), progname);
if (indexes.head != NULL)
fprintf(stderr, _(&%s: cannot reindex specific index(es) and system catalogs at the same time\n&), progname);
if (dbname == NULL)
if (getenv(&PGDATABASE&))
dbname = getenv(&PGDATABASE&);
else if (getenv(&PGUSER&))
dbname = getenv(&PGUSER&);
dbname = get_user_name_or_exit(progname);
reindex_system_catalogs(dbname, host, port, username, prompt_password,
progname, echo, verbose);
if (dbname == NULL)
if (getenv(&PGDATABASE&))
dbname = getenv(&PGDATABASE&);
else if (getenv(&PGUSER&))
dbname = getenv(&PGUSER&);
dbname = get_user_name_or_exit(progname);
if (schemas.head != NULL)
SimpleStringListCell *
for (cell = schemas. cell = cell-&next)
reindex_one_database(cell-&val, dbname, &SCHEMA&, host, port,
username, prompt_password, progname, echo, verbose);
if (indexes.head != NULL)
SimpleStringListCell *
for (cell = indexes. cell = cell-&next)
reindex_one_database(cell-&val, dbname, &INDEX&, host, port,
username, prompt_password, progname, echo, verbose);
if (tables.head != NULL)
SimpleStringListCell *
for (cell = tables. cell = cell-&next)
reindex_one_database(cell-&val, dbname, &TABLE&, host, port,
username, prompt_password, progname, echo, verbose);
* reindex database only if neither index nor table nor schema is
* specified
if (indexes.head == NULL && tables.head == NULL && schemas.head == NULL)
reindex_one_database(dbname, dbname, &DATABASE&, host, port,
username, prompt_password, progname, echo, verbose);
+ exit(0);
+static void
+reindex_one_database(const char *name, const char *dbname, const char *type,
const char *host, const char *port, const char *username,
enum trivalue prompt_password, const char *progname, bool echo,
bool verbose)
+ PQExpBufferD
+ initPQExpBuffer(&sql);
+ appendPQExpBufferStr(&sql, &REINDEX&);
+ if (verbose)
appendPQExpBufferStr(&sql, & (VERBOSE)&);
+ if (strcmp(type, &TABLE&) == 0)
appendPQExpBuffer(&sql, & TABLE %s&, name);
+ else if (strcmp(type, &INDEX&) == 0)
appendPQExpBuffer(&sql, & INDEX %s&, name);
+ else if (strcmp(type, &SCHEMA&) == 0)
appendPQExpBuffer(&sql, & SCHEMA %s&, name);
+ else if (strcmp(type, &DATABASE&) == 0)
appendPQExpBuffer(&sql, & DATABASE %s&, fmtId(name));
+ appendPQExpBufferChar(&sql, ';');
+ conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, false);
+ if (!executeMaintenanceCommand(conn, sql.data, echo))
if (strcmp(type, &TABLE&) == 0)
fprintf(stderr, _(&%s: reindexing of table \&%s\& in database \&%s\& failed: %s&),
progname, name, dbname, PQerrorMessage(conn));
if (strcmp(type, &INDEX&) == 0)
fprintf(stderr, _(&%s: reindexing of index \&%s\& in database \&%s\& failed: %s&),
progname, name, dbname, PQerrorMessage(conn));
if (strcmp(type, &SCHEMA&) == 0)
fprintf(stderr, _(&%s: reindexing of schema \&%s\& in database \&%s\& failed: %s&),
progname, name, dbname, PQerrorMessage(conn));
fprintf(stderr, _(&%s: reindexing of database \&%s\& failed: %s&),
progname, dbname, PQerrorMessage(conn));
PQfinish(conn);
+ PQfinish(conn);
+ termPQExpBuffer(&sql);
+static void
+reindex_all_databases(const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool quiet, bool verbose)
+ PGresult
+ conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
prompt_password, progname);
+ result = executeQuery(conn, &SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;&, progname, echo);
+ PQfinish(conn);
+ for (i = 0; i & PQntuples(result); i++)
*dbname = PQgetvalue(result, i, 0);
if (!quiet)
printf(_(&%s: reindexing database \&%s\&\n&), progname, dbname);
fflush(stdout);
reindex_one_database(dbname, dbname, &DATABASE&, host, port, username,
prompt_password, progname, echo, verbose);
+ PQclear(result);
+static void
+reindex_system_catalogs(const char *dbname, const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool verbose)
+ PQExpBufferD
+ initPQExpBuffer(&sql);
+ appendPQExpBuffer(&sql, &REINDEX&);
+ if (verbose)
appendPQExpBuffer(&sql, & (VERBOSE)&);
+ appendPQExpBuffer(&sql, & SYSTEM %s;&, dbname);
+ conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, false);
+ if (!executeMaintenanceCommand(conn, sql.data, echo))
fprintf(stderr, _(&%s: reindexing of system catalogs failed: %s&),
progname, PQerrorMessage(conn));
PQfinish(conn);
+ PQfinish(conn);
+ termPQExpBuffer(&sql);
+static void
+help(const char *progname)
+ printf(_(&%s reindexes a PostgreSQL database.\n\n&), progname);
+ printf(_(&Usage:\n&));
+ printf(_(&
%s [OPTION]... [DBNAME]\n&), progname);
+ printf(_(&\nOptions:\n&));
+ printf(_(&
reindex all databases\n&));
+ printf(_(&
-d, --dbname=DBNAME
database to reindex\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-i, --index=INDEX
recreate specific index(es) only\n&));
+ printf(_(&
-q, --quiet
don't write any messages\n&));
+ printf(_(&
-s, --system
reindex system catalogs\n&));
+ printf(_(&
-S, --schema=SCHEMA
reindex specific schema(s) only\n&));
+ printf(_(&
-t, --table=TABLE
reindex specific table(s) only\n&));
+ printf(_(&
-v, --verbose
write a lot of output\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&
--maintenance-db=DBNAME
alternate maintenance database\n&));
+ printf(_(&\nRead the description of the SQL command REINDEX for details.\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: createlang.c
===================================================================
--- createlang.c (revision 0)
+++ createlang.c (revision 2)
@@ -0,0 +1,251 @@
+/*-------------------------------------------------------------------------
+ * createlang
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/createlang.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &print.h&
+static void help(const char *progname);
+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'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&dbname&, required_argument, NULL, 'd'},
{&echo&, no_argument, NULL, 'e'},
{NULL, 0, NULL, 0}
+ const char *
listlangs =
+ const char *dbname = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
*langname = NULL;
+ PQExpBufferD
+ PGresult
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &createlang&, help);
+ while ((c = getopt_long(argc, argv, &lh:p:U:wWd:e&, long_options, &optindex)) != -1)
switch (c)
case 'l':
listlangs =
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'd':
dbname = pg_strdup(optarg);
case 'e':
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
* We set dbname from positional arguments if it is not already set by
* option arguments -d. If not doing listlangs, positional dbname must
* follow positional langname.
+ if (argc - optind & 0)
if (listlangs)
if (dbname == NULL)
dbname = argv[optind++];
langname = argv[optind++];
if (argc - optind & 0 && dbname == NULL)
dbname = argv[optind++];
+ if (argc - optind & 0)
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (dbname == NULL)
if (getenv(&PGDATABASE&))
dbname = getenv(&PGDATABASE&);
else if (getenv(&PGUSER&))
dbname = getenv(&PGUSER&);
dbname = get_user_name_or_exit(progname);
+ initPQExpBuffer(&sql);
* List option
+ if (listlangs)
printQueryO
static const bool translate_columns[] = {false, true};
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, false);
printfPQExpBuffer(&sql, &SELECT lanname as \&%s\&, &
&(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \&%s\& &
&FROM pg_catalog.pg_language WHERE&,
gettext_noop(&Name&),
gettext_noop(&yes&), gettext_noop(&no&),
gettext_noop(&Trusted?&));
result = executeQuery(conn, sql.data, progname, echo);
memset(&popt, 0, sizeof(popt));
popt.topt.format = PRINT_ALIGNED;
popt.topt.border = 1;
popt.topt.start_table =
popt.topt.stop_table =
popt.topt.encoding = PQclientEncoding(conn);
popt.title = _(&Procedural Languages&);
popt.translate_header =
popt.translate_columns = translate_
popt.n_translate_columns = lengthof(translate_columns);
printQuery(result, &popt, stdout, false, NULL);
PQfinish(conn);
+ if (langname == NULL)
fprintf(stderr, _(&%s: missing required argument language name\n&), progname);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ /* lower case language name */
+ for (p = *p; p++)
if (*p &= 'A' && *p &= 'Z')
*p += ('a' - 'A');
+ conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, false);
* Make sure the language isn't already installed
+ printfPQExpBuffer(&sql,
&SELECT oid FROM pg_catalog.pg_language WHERE lanname = '%s';&,
langname);
+ result = executeQuery(conn, sql.data, progname, echo);
+ if (PQntuples(result) & 0)
PQfinish(conn);
fprintf(stderr,
_(&%s: language \&%s\& is already installed in database \&%s\&\n&),
progname, langname, dbname);
/* separate exit status for &already installed& */
+ PQclear(result);
* In 9.1 and up, assume that languages should be installed using CREATE
* EXTENSION.
However, it's possible this tool could be used against an
* older server, and it's easy enough to continue supporting the old way.
+ if (PQserverVersion(conn) &= 90100)
printfPQExpBuffer(&sql, &CREATE EXTENSION \&%s\&;&, langname);
printfPQExpBuffer(&sql, &CREATE LANGUAGE \&%s\&;&, langname);
+ if (echo)
printf(&%s\n&, sql.data);
+ result = PQexec(conn, sql.data);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
fprintf(stderr, _(&%s: language installation failed: %s&),
progname, PQerrorMessage(conn));
PQfinish(conn);
+ PQclear(result);
+ PQfinish(conn);
+ exit(0);
+static void
+help(const char *progname)
+ printf(_(&%s installs a procedural language into a PostgreSQL database.\n\n&), progname);
+ printf(_(&Usage:\n&));
+ printf(_(&
%s [OPTION]... LANGNAME [DBNAME]\n&), progname);
+ printf(_(&\nOptions:\n&));
+ printf(_(&
-d, --dbname=DBNAME
database to install language in\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-l, --list
show a list of currently installed languages\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: droplang.c
===================================================================
--- droplang.c (revision 0)
+++ droplang.c (revision 2)
@@ -0,0 +1,252 @@
+/*-------------------------------------------------------------------------
+ * droplang
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/droplang.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &print.h&
+#define atooid(x)
((Oid) strtoul((x), NULL, 10))
+static void help(const char *progname);
+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'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&dbname&, required_argument, NULL, 'd'},
{&echo&, no_argument, NULL, 'e'},
{NULL, 0, NULL, 0}
+ const char *
listlangs =
+ const char *dbname = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
*langname = NULL;
+ PQExpBufferD
+ PGresult
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &droplang&, help);
+ while ((c = getopt_long(argc, argv, &lh:p:U:wWd:e&, long_options, &optindex)) != -1)
switch (c)
case 'l':
listlangs =
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'd':
dbname = pg_strdup(optarg);
case 'e':
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
* We set dbname from positional arguments if it is not already set by
* option arguments -d. If not doing listlangs, positional dbname must
* follow positional langname.
+ if (argc - optind & 0)
if (listlangs)
if (dbname == NULL)
dbname = argv[optind++];
langname = argv[optind++];
if (argc - optind & 0 && dbname == NULL)
dbname = argv[optind++];
+ if (argc - optind & 0)
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (dbname == NULL)
if (getenv(&PGDATABASE&))
dbname = getenv(&PGDATABASE&);
else if (getenv(&PGUSER&))
dbname = getenv(&PGUSER&);
dbname = get_user_name_or_exit(progname);
+ initPQExpBuffer(&sql);
* List option
+ if (listlangs)
printQueryO
static const bool translate_columns[] = {false, true};
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, false);
printfPQExpBuffer(&sql, &SELECT lanname as \&%s\&, &
&(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \&%s\& &
&FROM pg_catalog.pg_language WHERE&,
gettext_noop(&Name&),
gettext_noop(&yes&), gettext_noop(&no&),
gettext_noop(&Trusted?&));
result = executeQuery(conn, sql.data, progname, echo);
memset(&popt, 0, sizeof(popt));
popt.topt.format = PRINT_ALIGNED;
popt.topt.border = 1;
popt.topt.start_table =
popt.topt.stop_table =
popt.topt.encoding = PQclientEncoding(conn);
popt.title = _(&Procedural Languages&);
popt.translate_header =
popt.translate_columns = translate_
popt.n_translate_columns = lengthof(translate_columns);
printQuery(result, &popt, stdout, false, NULL);
PQfinish(conn);
+ if (langname == NULL)
fprintf(stderr, _(&%s: missing required argument language name\n&),
progname);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&),
progname);
+ /* lower case language name */
+ for (p = *p; p++)
if (*p &= 'A' && *p &= 'Z')
*p += ('a' - 'A');
+ conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, false);
* 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_&, progname, echo);
* Make sure the language is installed
+ printfPQExpBuffer(&sql, &SELECT oid &
&FROM pg_language WHERE lanname = '%s' AND&,
langname);
+ result = executeQuery(conn, sql.data, progname, echo);
+ if (PQntuples(result) == 0)
PQfinish(conn);
fprintf(stderr, _(&%s: language \&%s\& is not installed in &
&database \&%s\&\n&),
progname, langname, dbname);
+ PQclear(result);
* Attempt to drop the language.
We do not use CASCADE, so that the drop
* will fail if there are any functions in the language.
+ printfPQExpBuffer(&sql, &DROP EXTENSION \&%s\&;&, langname);
+ if (echo)
printf(&%s\n&, 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);
+ PQclear(result);
+ 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&));
+ printf(_(&
-d, --dbname=DBNAME
database from which to remove the language\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-l, --list
show a list of currently installed languages\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: vacuumdb.c
===================================================================
--- vacuumdb.c (revision 0)
+++ vacuumdb.c (revision 2)
@@ -0,0 +1,958 @@
+/*-------------------------------------------------------------------------
+ * vacuumdb
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/vacuumdb.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &dumputils.h&
+#define ERRCODE_UNDEFINED_TABLE
+/* Parallel vacuuming stuff */
+typedef struct ParallelSlot
+ pgsocket
+} ParallelS
+/* vacuum options controlled by user flags */
+typedef struct vacuumingOptions
+} vacuumingO
+static void vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
int stage,
SimpleStringList *tables,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
int concurrentCons,
const char *progname, bool echo, bool quiet);
+static void vacuum_all_databases(vacuumingOptions *vacopts,
bool analyze_in_stages,
const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
int concurrentCons,
const char *progname, bool echo, bool quiet);
+static void prepare_vacuum_command(PQExpBuffer sql, PGconn *conn,
vacuumingOptions *vacopts, const char *table);
+static void run_vacuum_command(PGconn *conn, const char *sql, bool echo,
const char *dbname, const char *table,
const char *progname, bool async);
+static ParallelSlot *GetIdleSlot(ParallelSlot slots[], int numslots,
const char *dbname, const char *progname);
+static bool GetQueryResult(PGconn *conn, const char *dbname,
const char *progname);
+static void DisconnectDatabase(ParallelSlot *slot);
+static int select_loop(int maxFd, fd_set *workerset, bool *aborting);
+static void init_slot(ParallelSlot *slot, PGconn *conn);
+static void help(const char *progname);
+/* For analyze-in-stages mode */
+#define ANALYZE_NO_STAGE -1
+#define ANALYZE_NUM_STAGES 3
+main(int argc, char *argv[])
+ static struct option long_options[] = {
{&host&, required_argument, NULL, 'h'},
{&port&, required_argument, NULL, 'p'},
{&username&, required_argument, NULL, 'U'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&echo&, no_argument, NULL, 'e'},
{&quiet&, no_argument, NULL, 'q'},
{&dbname&, required_argument, NULL, 'd'},
{&analyze&, no_argument, NULL, 'z'},
{&analyze-only&, no_argument, NULL, 'Z'},
{&freeze&, no_argument, NULL, 'F'},
{&all&, no_argument, NULL, 'a'},
{&table&, required_argument, NULL, 't'},
{&full&, no_argument, NULL, 'f'},
{&verbose&, no_argument, NULL, 'v'},
{&jobs&, required_argument, NULL, 'j'},
{&maintenance-db&, required_argument, NULL, 2},
{&analyze-in-stages&, no_argument, NULL, 3},
{NULL, 0, NULL, 0}
+ const char *
+ const char *dbname = NULL;
+ const char *maintenance_db = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
+ vacuumingO
analyze_in_stages =
+ SimpleStringList tables = {NULL, NULL};
concurrentCons = 1;
tbl_count = 0;
+ /* initialize options to all false */
+ memset(&vacopts, 0, sizeof(vacopts));
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &vacuumdb&, help);
+ while ((c = getopt_long(argc, argv, &h:p:U:wWeqd:zZFat:fvj:&, long_options, &optindex)) != -1)
switch (c)
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'e':
case 'q':
case 'd':
dbname = pg_strdup(optarg);
case 'z':
vacopts.and_analyze =
case 'Z':
vacopts.analyze_only =
case 'F':
vacopts.freeze =
case 'a':
case 't':
simple_string_list_append(&tables, optarg);
tbl_count++;
case 'f':
vacopts.full =
case 'v':
vacopts.verbose =
case 'j':
concurrentCons = atoi(optarg);
if (concurrentCons &= 0)
fprintf(stderr, _(&%s: number of parallel jobs must be at least 1\n&),
progname);
if (concurrentCons & FD_SETSIZE - 1)
fprintf(stderr, _(&%s: too many parallel jobs requested (maximum: %d)\n&),
progname, FD_SETSIZE - 1);
maintenance_db = pg_strdup(optarg);
analyze_in_stages = vacopts.analyze_only =
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
* Non-option argument specifies database name as long as it wasn't
* already specified with -d / --dbname
+ if (optind & argc && dbname == NULL)
dbname = argv[optind];
+ if (optind & argc)
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (vacopts.analyze_only)
if (vacopts.full)
fprintf(stderr, _(&%s: cannot use the \&%s\& option when performing only analyze\n&),
progname, &full&);
if (vacopts.freeze)
fprintf(stderr, _(&%s: cannot use the \&%s\& option when performing only analyze\n&),
progname, &freeze&);
/* allow 'and_analyze' with 'analyze_only' */
+ setup_cancel_handler();
+ /* Avoid opening extra connections. */
+ if (tbl_count && (concurrentCons & tbl_count))
concurrentCons = tbl_
+ if (alldb)
if (dbname)
fprintf(stderr, _(&%s: cannot vacuum all databases and a specific one at the same time\n&),
progname);
if (tables.head != NULL)
fprintf(stderr, _(&%s: cannot vacuum specific table(s) in all databases\n&),
progname);
vacuum_all_databases(&vacopts,
analyze_in_stages,
maintenance_db,
host, port, username, prompt_password,
concurrentCons,
progname, echo, quiet);
if (dbname == NULL)
if (getenv(&PGDATABASE&))
dbname = getenv(&PGDATABASE&);
else if (getenv(&PGUSER&))
dbname = getenv(&PGUSER&);
dbname = get_user_name_or_exit(progname);
if (analyze_in_stages)
for (stage = 0; stage & ANALYZE_NUM_STAGES; stage++)
vacuum_one_database(dbname, &vacopts,
host, port, username, prompt_password,
concurrentCons,
progname, echo, quiet);
vacuum_one_database(dbname, &vacopts,
ANALYZE_NO_STAGE,
host, port, username, prompt_password,
concurrentCons,
progname, echo, quiet);
+ exit(0);
+ * vacuum_one_database
+ * Process tables in the given database.
If the 'tables' list is empty,
+ * process all tables in the database.
+ * Note that this function is only concerned with running exactly one stage
+ * when in analyze-in- caller must iterate on us if necessary.
+ * If concurrentCons is & 1, multiple connections are used to vacuum tables
+ * in parallel.
In this case and if the table list is empty, we first obtain
+ * a list of tables from the database.
+static void
+vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
int stage,
SimpleStringList *tables,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
int concurrentCons,
const char *progname, bool echo, bool quiet)
+ PQExpBufferD
+ SimpleStringListCell *
+ ParallelSlot *slots = NULL;
+ SimpleStringList dbtables = {NULL, NULL};
parallel = concurrentCons & 1;
+ const char *stage_commands[] = {
&SET default_statistics_target=1; SET vacuum_cost_delay=0;&,
&SET default_statistics_target=10; RESET vacuum_cost_&,
&RESET default_statistics_&
+ const char *stage_messages[] = {
gettext_noop(&Generating minimal optimizer statistics (1 target)&),
gettext_noop(&Generating medium optimizer statistics (10 targets)&),
gettext_noop(&Generating default (full) optimizer statistics&)
+ Assert(stage == ANALYZE_NO_STAGE ||
(stage &= 0 && stage & ANALYZE_NUM_STAGES));
+ if (!quiet)
if (stage != ANALYZE_NO_STAGE)
printf(_(&%s: processing database \&%s\&: %s\n&), progname, dbname,
stage_messages[stage]);
printf(_(&%s: vacuuming database \&%s\&\n&), progname, dbname);
fflush(stdout);
+ conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, true);
+ initPQExpBuffer(&sql);
* If a table list is not provided and we're using multiple connections,
* prepare the list of tables by querying the catalogs.
+ if (parallel && (!tables || !tables-&head))
PQExpBufferD
initPQExpBuffer(&buf);
res = executeQuery(conn,
&SELECT c.relname, ns.nspname FROM pg_class c, pg_namespace ns\n&
& WHERE relkind IN (\'r\', \'m\') AND c.relnamespace = ns.oid\n&
& ORDER BY c.relpages DESC;&,
progname, echo);
ntups = PQntuples(res);
for (i = 0; i & i++)
appendPQExpBufferStr(&buf,
fmtQualifiedId(PQserverVersion(conn),
PQgetvalue(res, i, 1),
PQgetvalue(res, i, 0)));
simple_string_list_append(&dbtables, buf.data);
resetPQExpBuffer(&buf);
termPQExpBuffer(&buf);
tables = &
* If there are more connections than vacuumable relations, we don't
* need to use them all.
if (concurrentCons & ntups)
concurrentCons =
if (concurrentCons &= 1)
parallel =
PQclear(res);
* Setup the database connections. We reuse the connection we already have
* for the first slot.
If not in parallel mode, the first slot in the
* array contains the connection.
+ slots = (ParallelSlot *) pg_malloc(sizeof(ParallelSlot) * concurrentCons);
+ init_slot(slots, conn);
+ if (parallel)
for (i = 1; i & concurrentC i++)
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false, true);
init_slot(slots + i, conn);
* Prepare all the connections to run the appropriate analyze stage, if
* caller requested that mode.
+ if (stage != ANALYZE_NO_STAGE)
/* We already emitted the message above */
for (j = 0; j & concurrentC j++)
executeCommand((slots + j)-&connection,
stage_commands[stage], progname, echo);
+ cell = tables ? tables-&head : NULL;
ParallelSlot *free_
const char *tabname = cell ? cell-&val : NULL;
prepare_vacuum_command(&sql, conn, vacopts, tabname);
if (CancelRequested)
* Get the connection slot to use.
If in parallel mode, here we wait
* for one connection to become available if none already is.
* non-parallel mode we simply use the only slot we have, which we
* know to be free.
if (parallel)
* Get a free slot, waiting until one becomes free if none
* currently is.
free_slot = GetIdleSlot(slots, concurrentCons, dbname, progname);
if (!free_slot)
free_slot-&isFree =
free_slot =
* Execute the vacuum.
If not in parallel mode, this terminates the
* program in case of an error.
(The parallel case handles query
* errors in GetQueryResult through GetIdleSlot.)
run_vacuum_command(free_slot-&connection, sql.data,
echo, dbname, tabname, progname, parallel);
cell = cell-&
+ } while (cell != NULL);
+ if (parallel)
for (j = 0; j & concurrentC j++)
/* wait for all connection to return the results */
if (!GetQueryResult((slots + j)-&connection, dbname, progname))
(slots + j)-&isFree =
+ for (i = 0; i & concurrentC i++)
DisconnectDatabase(slots + i);
+ pfree(slots);
+ termPQExpBuffer(&sql);
+ if (failed)
+ * Vacuum/analyze all connectable databases.
+ * In analyze-in-stages mode, we process all databases in one stage before
+ * moving on to the next stage.
That ensure minimal stats are available
+ * quickly everywhere before generating more detailed ones.
+static void
+vacuum_all_databases(vacuumingOptions *vacopts,
bool analyze_in_stages,
const char *maintenance_db, const char *host,
const char *port, const char *username,
enum trivalue prompt_password,
int concurrentCons,
const char *progname, bool echo, bool quiet)
+ PGresult
+ conn = connectMaintenanceDatabase(maintenance_db, host, port,
username, prompt_password, progname);
+ result = executeQuery(conn,
&SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;&,
progname, echo);
+ PQfinish(conn);
+ if (analyze_in_stages)
* When analyzing all databases in stages, we analyze them all in the
* fastest stage first, so that initial statistics become available
* for all of them as soon as possible.
* This means we establish several times as many connections, but
* that's a secondary consideration.
for (stage = 0; stage & ANALYZE_NUM_STAGES; stage++)
for (i = 0; i & PQntuples(result); i++)
const char *
dbname = PQgetvalue(result, i, 0);
vacuum_one_database(dbname, vacopts,
host, port, username, prompt_password,
concurrentCons,
progname, echo, quiet);
for (i = 0; i & PQntuples(result); i++)
const char *
dbname = PQgetvalue(result, i, 0);
vacuum_one_database(dbname, vacopts,
ANALYZE_NO_STAGE,
host, port, username, prompt_password,
concurrentCons,
progname, echo, quiet);
+ PQclear(result);
+ * Construct a vacuum/analyze command to run based on the given options, in the
+ * given string buffer, which may contain previous garbage.
+ * An optional tabl this must be already be properly
+ * quoted.
The command is semicolon-terminated.
+static void
+prepare_vacuum_command(PQExpBuffer sql, PGconn *conn, vacuumingOptions *vacopts,
const char *table)
+ resetPQExpBuffer(sql);
+ if (vacopts-&analyze_only)
appendPQExpBufferStr(sql, &ANALYZE&);
if (vacopts-&verbose)
appendPQExpBufferStr(sql, & VERBOSE&);
appendPQExpBufferStr(sql, &VACUUM&);
if (PQserverVersion(conn) &= 90000)
const char *paren = & (&;
const char *comma = &, &;
const char *sep =
if (vacopts-&full)
appendPQExpBuffer(sql, &%sFULL&, sep);
if (vacopts-&freeze)
appendPQExpBuffer(sql, &%sFREEZE&, sep);
if (vacopts-&verbose)
appendPQExpBuffer(sql, &%sVERBOSE&, sep);
if (vacopts-&and_analyze)
appendPQExpBuffer(sql, &%sANALYZE&, sep);
if (sep != paren)
appendPQExpBufferChar(sql, ')');
if (vacopts-&full)
appendPQExpBufferStr(sql, & FULL&);
if (vacopts-&freeze)
appendPQExpBufferStr(sql, & FREEZE&);
if (vacopts-&verbose)
appendPQExpBufferStr(sql, & VERBOSE&);
if (vacopts-&and_analyze)
appendPQExpBufferStr(sql, & ANALYZE&);
+ if (table)
appendPQExpBuffer(sql, & %s&, table);
+ appendPQExpBufferChar(sql, ';');
+ * Execute a vacuum/analyze command to the server.
+ * Any errors during command execution are reported to stderr.
If async is
+ * false, this function exits the program after reporting the error.
+static void
+run_vacuum_command(PGconn *conn, const char *sql, bool echo,
const char *dbname, const char *table,
const char *progname, bool async)
+ if (async)
printf(&%s\n&, sql);
status = PQsendQuery(conn, sql) == 1;
status = executeMaintenanceCommand(conn, sql, echo);
+ if (!status)
if (table)
fprintf(stderr,
_(&%s: vacuuming of table \&%s\& in database \&%s\& failed: %s&),
progname, table, dbname, PQerrorMessage(conn));
fprintf(stderr, _(&%s: vacuuming of database \&%s\& failed: %s&),
progname, dbname, PQerrorMessage(conn));
if (!async)
PQfinish(conn);
+ * GetIdleSlot
Return a connection slot that is ready to execute a command.
+ * We return the first slot we find that is marked isFree,
+ * otherwise, we loop on select() until one socket becomes available.
+ * this happens, we read the whole set and mark as free all sockets that become
+ * available.
+ * Process the slot list, if any free slot is available then return the slotid
+ * else perform the select on all the socket's and wait until at least one slot
+ * becomes available.
+ * If an error occurs, NULL is returned.
+static ParallelSlot *
+GetIdleSlot(ParallelSlot slots[], int numslots, const char *dbname,
const char *progname)
firstFree = -1;
+ pgsocket maxFd;
+ for (i = 0; i & i++)
if ((slots + i)-&isFree)
return slots +
+ FD_ZERO(&slotset);
+ maxFd = slots-&
+ for (i = 0; i & i++)
FD_SET((slots + i)-&sock, &slotset);
if ((slots + i)-&sock & maxFd)
maxFd = (slots + i)-&
* No free slot found, so wait until one of the connections has finished
* its task and return the available slot.
+ for (firstFree = -1; firstFree & 0;)
SetCancelConn(slots-&connection);
i = select_loop(maxFd, &slotset, &aborting);
ResetCancelConn();
if (aborting)
* We set the cancel-receiving connection to the one in the zeroth
* slot above, so fetch the error from there.
GetQueryResult(slots-&connection, dbname, progname);
return NULL;
Assert(i != 0);
for (i = 0; i & i++)
if (!FD_ISSET((slots + i)-&sock, &slotset))
PQconsumeInput((slots + i)-&connection);
if (PQisBusy((slots + i)-&connection))
(slots + i)-&isFree =
if (!GetQueryResult((slots + i)-&connection, dbname, progname))
return NULL;
if (firstFree & 0)
firstFree =
+ return slots + firstF
+ * GetQueryResult
+ * Process the query result.
Returns true if there's no error, false
+ * otherwise -- but errors about trying to vacuum a missing relation are
+ * reported and subsequently ignored.
+static bool
+GetQueryResult(PGconn *conn, const char *dbname, const char *progname)
+ PGresult
+ SetCancelConn(conn);
+ while ((result = PQgetResult(conn)) != NULL)
* If errors are found, report them.
Errors about a missing table are
* harmless so we but die for other errors.
if (PQresultStatus(result) != PGRES_COMMAND_OK)
*sqlState = PQresultErrorField(result, PG_DIAG_SQLSTATE);
fprintf(stderr, _(&%s: vacuuming of database \&%s\& failed: %s&),
progname, dbname, PQerrorMessage(conn));
if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) != 0)
PQclear(result);
PQclear(result);
+ ResetCancelConn();
+ * DisconnectDatabase
Disconnect the connection associated with the given slot
+static void
+DisconnectDatabase(ParallelSlot *slot)
errbuf[256];
+ if (!slot-&connection)
+ if (PQtransactionStatus(slot-&connection) == PQTRANS_ACTIVE)
if ((cancel = PQgetCancel(slot-&connection)))
PQcancel(cancel, errbuf, sizeof(errbuf));
PQfreeCancel(cancel);
+ PQfinish(slot-&connection);
+ slot-&connection = NULL;
+ * Loop on select() until a descriptor from the given set becomes readable.
+ * If we get a cancel request while we're waiting, we forego all further
+ * processing and set the *aborting flag to true.
The return value must be
+ * ignored in this case.
Otherwise, *aborting is set to false.
+static int
+select_loop(int maxFd, fd_set *workerset, bool *aborting)
saveSet = *
+ if (CancelRequested)
*aborting =
return -1;
*aborting =
+ for (;;)
* On Windows, we need to check once in a while
* on other platforms we rely on select() returning when interrupted.
struct timeval *
+#ifdef WIN32
struct timeval tv = {0, 1000000};
tvp = NULL;
*workerset = saveS
i = select(maxFd + 1, workerset, NULL, NULL, tvp);
+#ifdef WIN32
if (i == SOCKET_ERROR)
if (WSAGetLastError() == WSAEINTR)
errno = EINTR;
if (i & 0 && errno == EINTR)
/* ignore this */
if (i & 0 || CancelRequested)
*aborting = /* but not this */
if (i == 0)
/* timeout (Win32 only) */
+static void
+init_slot(ParallelSlot *slot, PGconn *conn)
+ slot-&connection =
+ slot-&isFree =
+ slot-&sock = PQsocket(conn);
+static void
+help(const char *progname)
+ printf(_(&%s cleans and analyzes a PostgreSQL database.\n\n&), progname);
+ printf(_(&Usage:\n&));
+ printf(_(&
%s [OPTION]... [DBNAME]\n&), progname);
+ printf(_(&\nOptions:\n&));
+ printf(_(&
vacuum all databases\n&));
+ printf(_(&
-d, --dbname=DBNAME
database to vacuum\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-f, --full
do full vacuuming\n&));
+ printf(_(&
-F, --freeze
freeze row transaction information\n&));
+ printf(_(&
-j, --jobs=NUM
use this many concurrent connections to vacuum\n&));
+ printf(_(&
-q, --quiet
don't write any messages\n&));
+ printf(_(&
-t, --table='TABLE[(COLUMNS)]'
vacuum specific table(s) only\n&));
+ printf(_(&
-v, --verbose
write a lot of output\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
-z, --analyze
update optimizer statistics\n&));
+ printf(_(&
-Z, --analyze-only
only update
no vacuum\n&));
+ printf(_(&
--analyze-in-stages
only update optimizer statistics, in multiple\n&
stage no vacuum\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&
--maintenance-db=DBNAME
alternate maintenance database\n&));
+ printf(_(&\nRead the description of the SQL command VACUUM for details.\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: createdb.c
===================================================================
--- createdb.c (revision 0)
+++ createdb.c (revision 2)
@@ -0,0 +1,274 @@
+/*-------------------------------------------------------------------------
+ * createdb
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/createdb.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &dumputils.h&
+static void help(const char *progname);
+main(int argc, char *argv[])
+ static struct option long_options[] = {
{&host&, required_argument, NULL, 'h'},
{&port&, required_argument, NULL, 'p'},
{&username&, required_argument, NULL, 'U'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&echo&, no_argument, NULL, 'e'},
{&owner&, required_argument, NULL, 'O'},
{&tablespace&, required_argument, NULL, 'D'},
{&template&, required_argument, NULL, 'T'},
{&encoding&, required_argument, NULL, 'E'},
{&lc-collate&, required_argument, NULL, 1},
{&lc-ctype&, required_argument, NULL, 2},
{&locale&, required_argument, NULL, 'l'},
{&maintenance-db&, required_argument, NULL, 3},
{NULL, 0, NULL, 0}
+ const char *
+ const char *dbname = NULL;
+ const char *maintenance_db = NULL;
*comment = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
*owner = NULL;
*tablespace = NULL;
*template = NULL;
*encoding = NULL;
*lc_collate = NULL;
*lc_ctype = NULL;
*locale = NULL;
+ PQExpBufferD
+ PGresult
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &createdb&, help);
+ while ((c = getopt_long(argc, argv, &h:p:U:wWeO:D:T:E:l:&, long_options, &optindex)) != -1)
switch (c)
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'e':
case 'O':
owner = pg_strdup(optarg);
case 'D':
tablespace = pg_strdup(optarg);
case 'T':
template = pg_strdup(optarg);
case 'E':
encoding = pg_strdup(optarg);
lc_collate = pg_strdup(optarg);
lc_ctype = pg_strdup(optarg);
case 'l':
locale = pg_strdup(optarg);
maintenance_db = pg_strdup(optarg);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ switch (argc - optind)
dbname = argv[optind];
dbname = argv[optind];
comment = argv[optind + 1];
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&),
progname, argv[optind + 2]);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ if (locale)
if (lc_ctype)
fprintf(stderr, _(&%s: only one of --locale and --lc-ctype can be specified\n&),
progname);
if (lc_collate)
fprintf(stderr, _(&%s: only one of --locale and --lc-collate can be specified\n&),
progname);
lc_ctype =
lc_collate =
+ if (encoding)
if (pg_char_to_encoding(encoding) & 0)
fprintf(stderr, _(&%s: \&%s\& is not a valid encoding name\n&),
progname, encoding);
+ if (dbname == NULL)
if (getenv(&PGDATABASE&))
dbname = getenv(&PGDATABASE&);
else if (getenv(&PGUSER&))
dbname = getenv(&PGUSER&);
dbname = get_user_name_or_exit(progname);
+ initPQExpBuffer(&sql);
+ appendPQExpBuffer(&sql, &CREATE DATABASE %s&,
fmtId(dbname));
+ if (owner)
appendPQExpBuffer(&sql, & OWNER %s&, fmtId(owner));
+ if (tablespace)
appendPQExpBuffer(&sql, & TABLESPACE %s&, fmtId(tablespace));
+ if (encoding)
appendPQExpBuffer(&sql, & ENCODING '%s'&, encoding);
+ if (template)
appendPQExpBuffer(&sql, & TEMPLATE %s&, fmtId(template));
+ if (lc_collate)
appendPQExpBuffer(&sql, & LC_COLLATE '%s'&, lc_collate);
+ if (lc_ctype)
appendPQExpBuffer(&sql, & LC_CTYPE '%s'&, lc_ctype);
+ appendPQExpBufferChar(&sql, ';');
+ /* No point in trying to use postgres db when creating postgres db. */
+ if (maintenance_db == NULL && strcmp(dbname, &postgres&) == 0)
maintenance_db = &template1&;
+ conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
prompt_password, progname);
+ if (echo)
printf(&%s\n&, sql.data);
+ result = PQexec(conn, sql.data);
+ if (PQresultStatus(result) != PGRES_COMMAND_OK)
fprintf(stderr, _(&%s: database creation failed: %s&),
progname, PQerrorMessage(conn));
PQfinish(conn);
+ PQclear(result);
+ if (comment)
printfPQExpBuffer(&sql, &COMMENT ON DATABASE %s IS &, fmtId(dbname));
appendStringLiteralConn(&sql, comment, conn);
appendPQExpBufferChar(&sql, ';');
printf(&%s\n&, sql.data);
result = PQexec(conn, sql.data);
if (PQresultStatus(result) != PGRES_COMMAND_OK)
fprintf(stderr, _(&%s: comment creation failed (database was created): %s&),
progname, PQerrorMessage(conn));
PQfinish(conn);
PQclear(result);
+ PQfinish(conn);
+ exit(0);
+static void
+help(const char *progname)
+ printf(_(&%s creates a PostgreSQL database.\n\n&), progname);
+ printf(_(&Usage:\n&));
+ printf(_(&
%s [OPTION]... [DBNAME] [DESCRIPTION]\n&), progname);
+ printf(_(&\nOptions:\n&));
+ printf(_(&
-D, --tablespace=TABLESPACE
default tablespace for the database\n&));
+ printf(_(&
-e, --echo
show the commands being sent to the server\n&));
+ printf(_(&
-E, --encoding=ENCODING
encoding for the database\n&));
+ printf(_(&
-l, --locale=LOCALE
locale settings for the database\n&));
+ printf(_(&
--lc-collate=LOCALE
LC_COLLATE setting for the database\n&));
+ printf(_(&
--lc-ctype=LOCALE
LC_CTYPE setting for the database\n&));
+ printf(_(&
-O, --owner=OWNER
database user to own the new database\n&));
+ printf(_(&
-T, --template=TEMPLATE
template database to copy\n&));
+ printf(_(&
-V, --version
output version information, then exit\n&));
+ printf(_(&
-?, --help
show this help, then exit\n&));
+ printf(_(&\nConnection options:\n&));
+ printf(_(&
-h, --host=HOSTNAME
database server host or socket directory\n&));
+ printf(_(&
-p, --port=PORT
database server port\n&));
+ printf(_(&
-U, --username=USERNAME
user name to connect as\n&));
+ printf(_(&
-w, --no-password
never prompt for password\n&));
+ printf(_(&
-W, --password
force password prompt\n&));
+ printf(_(&
--maintenance-db=DBNAME
alternate maintenance database\n&));
+ printf(_(&\nBy default, a database with the same name as the current user is created.\n&));
+ printf(_(&\nReport bugs to &pgsql-bugs@postgresql.org&.\n&));
Index: dropdb.c
===================================================================
--- dropdb.c (revision 0)
+++ dropdb.c (revision 2)
@@ -0,0 +1,171 @@
+/*-------------------------------------------------------------------------
+ * dropdb
+ * Portions Copyright (c) , PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * src/bin/scripts/dropdb.c
+ *-------------------------------------------------------------------------
+#include &postgres_fe.h&
+#include &common.h&
+#include &dumputils.h&
+static void help(const char *progname);
+main(int argc, char *argv[])
+ static int if_exists = 0;
+ static struct option long_options[] = {
{&host&, required_argument, NULL, 'h'},
{&port&, required_argument, NULL, 'p'},
{&username&, required_argument, NULL, 'U'},
{&no-password&, no_argument, NULL, 'w'},
{&password&, no_argument, NULL, 'W'},
{&echo&, no_argument, NULL, 'e'},
{&interactive&, no_argument, NULL, 'i'},
{&if-exists&, no_argument, &if_exists, 1},
{&maintenance-db&, required_argument, NULL, 2},
{NULL, 0, NULL, 0}
+ const char *
*dbname = NULL;
*maintenance_db = NULL;
*host = NULL;
*port = NULL;
*username = NULL;
+ enum trivalue prompt_password = TRI_DEFAULT;
interactive =
+ PQExpBufferD
+ PGresult
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN(&pgscripts&));
+ handle_help_version_opts(argc, argv, &dropdb&, help);
+ while ((c = getopt_long(argc, argv, &h:p:U:wWei&, long_options, &optindex)) != -1)
switch (c)
case 'h':
host = pg_strdup(optarg);
case 'p':
port = pg_strdup(optarg);
case 'U':
username = pg_strdup(optarg);
case 'w':
prompt_password = TRI_NO;
case 'W':
prompt_password = TRI_YES;
case 'e':
case 'i':
interactive =
/* this covers the long options */
maintenance_db = pg_strdup(optarg);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
+ switch (argc - optind)
fprintf(stderr, _(&%s: missing required argument database name\n&), progname);
fprintf(stderr, _(&Try \&%s --help\& for more information.\n&), progname);
dbname = argv[optind];
fprintf(stderr, _(&%s: too many command-line arguments (first is \&%s\&)\n&)

我要回帖

更多关于 适马150 2.8 的文章

 

随机推荐