/src/bin/scripts/vacuumdb.c

https://github.com/matheusoliveira/postgres · C · 420 lines · 362 code · 42 blank · 16 comment · 42 complexity · a4d98de6e2ea24276a24d836c4da511a MD5 · raw file

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