PageRenderTime 36ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/src/bin/scripts/vacuumdb.c

https://bitbucket.org/gencer/postgres
C | 382 lines | 328 code | 38 blank | 16 comment | 40 complexity | 4150b5e74e22f07a37d14d4af95074a7 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * vacuumdb
  4. *
  5. * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  6. * Portions Copyright (c) 1994, Regents of the University of California
  7. *
  8. * src/bin/scripts/vacuumdb.c
  9. *
  10. *-------------------------------------------------------------------------
  11. */
  12. #include "postgres_fe.h"
  13. #include "common.h"
  14. #include "dumputils.h"
  15. static void vacuum_one_database(const char *dbname, bool full, bool verbose,
  16. bool and_analyze, bool analyze_only, bool freeze,
  17. const char *table, const char *host, const char *port,
  18. const char *username, enum trivalue prompt_password,
  19. const char *progname, bool echo);
  20. static void vacuum_all_databases(bool full, bool verbose, bool and_analyze,
  21. bool analyze_only, bool freeze,
  22. const char *maintenance_db,
  23. const char *host, const char *port,
  24. const char *username, enum trivalue prompt_password,
  25. const char *progname, bool echo, bool quiet);
  26. static void help(const char *progname);
  27. int
  28. main(int argc, char *argv[])
  29. {
  30. static struct option long_options[] = {
  31. {"host", required_argument, NULL, 'h'},
  32. {"port", required_argument, NULL, 'p'},
  33. {"username", required_argument, NULL, 'U'},
  34. {"no-password", no_argument, NULL, 'w'},
  35. {"password", no_argument, NULL, 'W'},
  36. {"echo", no_argument, NULL, 'e'},
  37. {"quiet", no_argument, NULL, 'q'},
  38. {"dbname", required_argument, NULL, 'd'},
  39. {"analyze", no_argument, NULL, 'z'},
  40. {"analyze-only", no_argument, NULL, 'Z'},
  41. {"freeze", no_argument, NULL, 'F'},
  42. {"all", no_argument, NULL, 'a'},
  43. {"table", required_argument, NULL, 't'},
  44. {"full", no_argument, NULL, 'f'},
  45. {"verbose", no_argument, NULL, 'v'},
  46. {"maintenance-db", required_argument, NULL, 2},
  47. {NULL, 0, NULL, 0}
  48. };
  49. const char *progname;
  50. int optindex;
  51. int c;
  52. const char *dbname = NULL;
  53. const char *maintenance_db = NULL;
  54. char *host = NULL;
  55. char *port = NULL;
  56. char *username = NULL;
  57. enum trivalue prompt_password = TRI_DEFAULT;
  58. bool echo = false;
  59. bool quiet = false;
  60. bool and_analyze = false;
  61. bool analyze_only = false;
  62. bool freeze = false;
  63. bool alldb = false;
  64. bool full = false;
  65. bool verbose = false;
  66. SimpleStringList tables = {NULL, NULL};
  67. progname = get_progname(argv[0]);
  68. set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
  69. handle_help_version_opts(argc, argv, "vacuumdb", help);
  70. while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fv", long_options, &optindex)) != -1)
  71. {
  72. switch (c)
  73. {
  74. case 'h':
  75. host = pg_strdup(optarg);
  76. break;
  77. case 'p':
  78. port = pg_strdup(optarg);
  79. break;
  80. case 'U':
  81. username = pg_strdup(optarg);
  82. break;
  83. case 'w':
  84. prompt_password = TRI_NO;
  85. break;
  86. case 'W':
  87. prompt_password = TRI_YES;
  88. break;
  89. case 'e':
  90. echo = true;
  91. break;
  92. case 'q':
  93. quiet = true;
  94. break;
  95. case 'd':
  96. dbname = pg_strdup(optarg);
  97. break;
  98. case 'z':
  99. and_analyze = true;
  100. break;
  101. case 'Z':
  102. analyze_only = true;
  103. break;
  104. case 'F':
  105. freeze = true;
  106. break;
  107. case 'a':
  108. alldb = true;
  109. break;
  110. case 't':
  111. simple_string_list_append(&tables, optarg);
  112. break;
  113. case 'f':
  114. full = true;
  115. break;
  116. case 'v':
  117. verbose = true;
  118. break;
  119. case 2:
  120. maintenance_db = pg_strdup(optarg);
  121. break;
  122. default:
  123. fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
  124. exit(1);
  125. }
  126. }
  127. /*
  128. * Non-option argument specifies database name as long as it wasn't
  129. * already specified with -d / --dbname
  130. */
  131. if (optind < argc && dbname == NULL)
  132. {
  133. dbname = argv[optind];
  134. optind++;
  135. }
  136. if (optind < argc)
  137. {
  138. fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
  139. progname, argv[optind]);
  140. fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
  141. exit(1);
  142. }
  143. if (analyze_only)
  144. {
  145. if (full)
  146. {
  147. fprintf(stderr, _("%s: cannot use the \"full\" option when performing only analyze\n"),
  148. progname);
  149. exit(1);
  150. }
  151. if (freeze)
  152. {
  153. fprintf(stderr, _("%s: cannot use the \"freeze\" option when performing only analyze\n"),
  154. progname);
  155. exit(1);
  156. }
  157. /* allow 'and_analyze' with 'analyze_only' */
  158. }
  159. setup_cancel_handler();
  160. if (alldb)
  161. {
  162. if (dbname)
  163. {
  164. fprintf(stderr, _("%s: cannot vacuum all databases and a specific one at the same time\n"),
  165. progname);
  166. exit(1);
  167. }
  168. if (tables.head != NULL)
  169. {
  170. fprintf(stderr, _("%s: cannot vacuum specific table(s) in all databases\n"),
  171. progname);
  172. exit(1);
  173. }
  174. vacuum_all_databases(full, verbose, and_analyze, analyze_only, freeze,
  175. maintenance_db, host, port, username,
  176. prompt_password, progname, echo, quiet);
  177. }
  178. else
  179. {
  180. if (dbname == NULL)
  181. {
  182. if (getenv("PGDATABASE"))
  183. dbname = getenv("PGDATABASE");
  184. else if (getenv("PGUSER"))
  185. dbname = getenv("PGUSER");
  186. else
  187. dbname = get_user_name_or_exit(progname);
  188. }
  189. if (tables.head != NULL)
  190. {
  191. SimpleStringListCell *cell;
  192. for (cell = tables.head; cell; cell = cell->next)
  193. {
  194. vacuum_one_database(dbname, full, verbose, and_analyze,
  195. analyze_only,
  196. freeze, cell->val,
  197. host, port, username, prompt_password,
  198. progname, echo);
  199. }
  200. }
  201. else
  202. vacuum_one_database(dbname, full, verbose, and_analyze,
  203. analyze_only,
  204. freeze, NULL,
  205. host, port, username, prompt_password,
  206. progname, echo);
  207. }
  208. exit(0);
  209. }
  210. static void
  211. vacuum_one_database(const char *dbname, bool full, bool verbose, bool and_analyze,
  212. bool analyze_only, bool freeze, const char *table,
  213. const char *host, const char *port,
  214. const char *username, enum trivalue prompt_password,
  215. const char *progname, bool echo)
  216. {
  217. PQExpBufferData sql;
  218. PGconn *conn;
  219. initPQExpBuffer(&sql);
  220. conn = connectDatabase(dbname, host, port, username, prompt_password,
  221. progname, false);
  222. if (analyze_only)
  223. {
  224. appendPQExpBufferStr(&sql, "ANALYZE");
  225. if (verbose)
  226. appendPQExpBufferStr(&sql, " VERBOSE");
  227. }
  228. else
  229. {
  230. appendPQExpBufferStr(&sql, "VACUUM");
  231. if (PQserverVersion(conn) >= 90000)
  232. {
  233. const char *paren = " (";
  234. const char *comma = ", ";
  235. const char *sep = paren;
  236. if (full)
  237. {
  238. appendPQExpBuffer(&sql, "%sFULL", sep);
  239. sep = comma;
  240. }
  241. if (freeze)
  242. {
  243. appendPQExpBuffer(&sql, "%sFREEZE", sep);
  244. sep = comma;
  245. }
  246. if (verbose)
  247. {
  248. appendPQExpBuffer(&sql, "%sVERBOSE", sep);
  249. sep = comma;
  250. }
  251. if (and_analyze)
  252. {
  253. appendPQExpBuffer(&sql, "%sANALYZE", sep);
  254. sep = comma;
  255. }
  256. if (sep != paren)
  257. appendPQExpBufferStr(&sql, ")");
  258. }
  259. else
  260. {
  261. if (full)
  262. appendPQExpBufferStr(&sql, " FULL");
  263. if (freeze)
  264. appendPQExpBufferStr(&sql, " FREEZE");
  265. if (verbose)
  266. appendPQExpBufferStr(&sql, " VERBOSE");
  267. if (and_analyze)
  268. appendPQExpBufferStr(&sql, " ANALYZE");
  269. }
  270. }
  271. if (table)
  272. appendPQExpBuffer(&sql, " %s", table);
  273. appendPQExpBufferStr(&sql, ";");
  274. if (!executeMaintenanceCommand(conn, sql.data, echo))
  275. {
  276. if (table)
  277. fprintf(stderr, _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
  278. progname, table, dbname, PQerrorMessage(conn));
  279. else
  280. fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
  281. progname, dbname, PQerrorMessage(conn));
  282. PQfinish(conn);
  283. exit(1);
  284. }
  285. PQfinish(conn);
  286. termPQExpBuffer(&sql);
  287. }
  288. static void
  289. vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_only,
  290. bool freeze, const char *maintenance_db,
  291. const char *host, const char *port,
  292. const char *username, enum trivalue prompt_password,
  293. const char *progname, bool echo, bool quiet)
  294. {
  295. PGconn *conn;
  296. PGresult *result;
  297. int i;
  298. conn = connectMaintenanceDatabase(maintenance_db, host, port,
  299. username, prompt_password, progname);
  300. result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
  301. PQfinish(conn);
  302. for (i = 0; i < PQntuples(result); i++)
  303. {
  304. char *dbname = PQgetvalue(result, i, 0);
  305. if (!quiet)
  306. {
  307. printf(_("%s: vacuuming database \"%s\"\n"), progname, dbname);
  308. fflush(stdout);
  309. }
  310. vacuum_one_database(dbname, full, verbose, and_analyze, analyze_only,
  311. freeze, NULL, host, port, username, prompt_password,
  312. progname, echo);
  313. }
  314. PQclear(result);
  315. }
  316. static void
  317. help(const char *progname)
  318. {
  319. printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
  320. printf(_("Usage:\n"));
  321. printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
  322. printf(_("\nOptions:\n"));
  323. printf(_(" -a, --all vacuum all databases\n"));
  324. printf(_(" -d, --dbname=DBNAME database to vacuum\n"));
  325. printf(_(" -e, --echo show the commands being sent to the server\n"));
  326. printf(_(" -f, --full do full vacuuming\n"));
  327. printf(_(" -F, --freeze freeze row transaction information\n"));
  328. printf(_(" -q, --quiet don't write any messages\n"));
  329. printf(_(" -t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only\n"));
  330. printf(_(" -v, --verbose write a lot of output\n"));
  331. printf(_(" -V, --version output version information, then exit\n"));
  332. printf(_(" -z, --analyze update optimizer statistics\n"));
  333. printf(_(" -Z, --analyze-only only update optimizer statistics\n"));
  334. printf(_(" -?, --help show this help, then exit\n"));
  335. printf(_("\nConnection options:\n"));
  336. printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
  337. printf(_(" -p, --port=PORT database server port\n"));
  338. printf(_(" -U, --username=USERNAME user name to connect as\n"));
  339. printf(_(" -w, --no-password never prompt for password\n"));
  340. printf(_(" -W, --password force password prompt\n"));
  341. printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
  342. printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
  343. printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
  344. }