PageRenderTime 107ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/bin/pg_dump/pg_backup_db.c

https://bitbucket.org/gencer/postgres
C | 608 lines | 416 code | 84 blank | 108 comment | 91 complexity | 900d5f2ef62e9a176588b121020e361c MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * pg_backup_db.c
  4. *
  5. * Implements the basic DB functions used by the archiver.
  6. *
  7. * IDENTIFICATION
  8. * src/bin/pg_dump/pg_backup_db.c
  9. *
  10. *-------------------------------------------------------------------------
  11. */
  12. #include "pg_backup_db.h"
  13. #include "pg_backup_utils.h"
  14. #include "dumputils.h"
  15. #include "parallel.h"
  16. #include <unistd.h>
  17. #include <ctype.h>
  18. #ifdef HAVE_TERMIOS_H
  19. #include <termios.h>
  20. #endif
  21. #define DB_MAX_ERR_STMT 128
  22. /* translator: this is a module name */
  23. static const char *modulename = gettext_noop("archiver (db)");
  24. static void _check_database_version(ArchiveHandle *AH);
  25. static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
  26. static void notice_processor(void *arg, const char *message);
  27. static void
  28. _check_database_version(ArchiveHandle *AH)
  29. {
  30. const char *remoteversion_str;
  31. int remoteversion;
  32. remoteversion_str = PQparameterStatus(AH->connection, "server_version");
  33. remoteversion = PQserverVersion(AH->connection);
  34. if (remoteversion == 0 || !remoteversion_str)
  35. exit_horribly(modulename, "could not get server_version from libpq\n");
  36. AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
  37. AH->public.remoteVersion = remoteversion;
  38. if (!AH->archiveRemoteVersion)
  39. AH->archiveRemoteVersion = AH->public.remoteVersionStr;
  40. if (remoteversion != PG_VERSION_NUM
  41. && (remoteversion < AH->public.minRemoteVersion ||
  42. remoteversion > AH->public.maxRemoteVersion))
  43. {
  44. write_msg(NULL, "server version: %s; %s version: %s\n",
  45. remoteversion_str, progname, PG_VERSION);
  46. exit_horribly(NULL, "aborting because of server version mismatch\n");
  47. }
  48. }
  49. /*
  50. * Reconnect to the server. If dbname is not NULL, use that database,
  51. * else the one associated with the archive handle. If username is
  52. * not NULL, use that user name, else the one from the handle. If
  53. * both the database and the user match the existing connection already,
  54. * nothing will be done.
  55. *
  56. * Returns 1 in any case.
  57. */
  58. int
  59. ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
  60. {
  61. PGconn *newConn;
  62. const char *newdbname;
  63. const char *newusername;
  64. if (!dbname)
  65. newdbname = PQdb(AH->connection);
  66. else
  67. newdbname = dbname;
  68. if (!username)
  69. newusername = PQuser(AH->connection);
  70. else
  71. newusername = username;
  72. /* Let's see if the request is already satisfied */
  73. if (strcmp(newdbname, PQdb(AH->connection)) == 0 &&
  74. strcmp(newusername, PQuser(AH->connection)) == 0)
  75. return 1;
  76. newConn = _connectDB(AH, newdbname, newusername);
  77. PQfinish(AH->connection);
  78. AH->connection = newConn;
  79. return 1;
  80. }
  81. /*
  82. * Connect to the db again.
  83. *
  84. * Note: it's not really all that sensible to use a single-entry password
  85. * cache if the username keeps changing. In current usage, however, the
  86. * username never does change, so one savedPassword is sufficient. We do
  87. * update the cache on the off chance that the password has changed since the
  88. * start of the run.
  89. */
  90. static PGconn *
  91. _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
  92. {
  93. PGconn *newConn;
  94. const char *newdb;
  95. const char *newuser;
  96. char *password = AH->savedPassword;
  97. bool new_pass;
  98. if (!reqdb)
  99. newdb = PQdb(AH->connection);
  100. else
  101. newdb = reqdb;
  102. if (!requser || strlen(requser) == 0)
  103. newuser = PQuser(AH->connection);
  104. else
  105. newuser = requser;
  106. ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
  107. newdb, newuser);
  108. if (AH->promptPassword == TRI_YES && password == NULL)
  109. {
  110. password = simple_prompt("Password: ", 100, false);
  111. if (password == NULL)
  112. exit_horribly(modulename, "out of memory\n");
  113. }
  114. do
  115. {
  116. #define PARAMS_ARRAY_SIZE 7
  117. const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
  118. const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
  119. keywords[0] = "host";
  120. values[0] = PQhost(AH->connection);
  121. keywords[1] = "port";
  122. values[1] = PQport(AH->connection);
  123. keywords[2] = "user";
  124. values[2] = newuser;
  125. keywords[3] = "password";
  126. values[3] = password;
  127. keywords[4] = "dbname";
  128. values[4] = newdb;
  129. keywords[5] = "fallback_application_name";
  130. values[5] = progname;
  131. keywords[6] = NULL;
  132. values[6] = NULL;
  133. new_pass = false;
  134. newConn = PQconnectdbParams(keywords, values, true);
  135. free(keywords);
  136. free(values);
  137. if (!newConn)
  138. exit_horribly(modulename, "failed to reconnect to database\n");
  139. if (PQstatus(newConn) == CONNECTION_BAD)
  140. {
  141. if (!PQconnectionNeedsPassword(newConn))
  142. exit_horribly(modulename, "could not reconnect to database: %s",
  143. PQerrorMessage(newConn));
  144. PQfinish(newConn);
  145. if (password)
  146. fprintf(stderr, "Password incorrect\n");
  147. fprintf(stderr, "Connecting to %s as %s\n",
  148. newdb, newuser);
  149. if (password)
  150. free(password);
  151. if (AH->promptPassword != TRI_NO)
  152. password = simple_prompt("Password: ", 100, false);
  153. else
  154. exit_horribly(modulename, "connection needs password\n");
  155. if (password == NULL)
  156. exit_horribly(modulename, "out of memory\n");
  157. new_pass = true;
  158. }
  159. } while (new_pass);
  160. AH->savedPassword = password;
  161. /* check for version mismatch */
  162. _check_database_version(AH);
  163. PQsetNoticeProcessor(newConn, notice_processor, NULL);
  164. return newConn;
  165. }
  166. /*
  167. * Make a database connection with the given parameters. The
  168. * connection handle is returned, the parameters are stored in AHX.
  169. * An interactive password prompt is automatically issued if required.
  170. *
  171. * Note: it's not really all that sensible to use a single-entry password
  172. * cache if the username keeps changing. In current usage, however, the
  173. * username never does change, so one savedPassword is sufficient.
  174. */
  175. void
  176. ConnectDatabase(Archive *AHX,
  177. const char *dbname,
  178. const char *pghost,
  179. const char *pgport,
  180. const char *username,
  181. enum trivalue prompt_password)
  182. {
  183. ArchiveHandle *AH = (ArchiveHandle *) AHX;
  184. char *password = AH->savedPassword;
  185. bool new_pass;
  186. if (AH->connection)
  187. exit_horribly(modulename, "already connected to a database\n");
  188. if (prompt_password == TRI_YES && password == NULL)
  189. {
  190. password = simple_prompt("Password: ", 100, false);
  191. if (password == NULL)
  192. exit_horribly(modulename, "out of memory\n");
  193. }
  194. AH->promptPassword = prompt_password;
  195. /*
  196. * Start the connection. Loop until we have a password if requested by
  197. * backend.
  198. */
  199. do
  200. {
  201. #define PARAMS_ARRAY_SIZE 7
  202. const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
  203. const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
  204. keywords[0] = "host";
  205. values[0] = pghost;
  206. keywords[1] = "port";
  207. values[1] = pgport;
  208. keywords[2] = "user";
  209. values[2] = username;
  210. keywords[3] = "password";
  211. values[3] = password;
  212. keywords[4] = "dbname";
  213. values[4] = dbname;
  214. keywords[5] = "fallback_application_name";
  215. values[5] = progname;
  216. keywords[6] = NULL;
  217. values[6] = NULL;
  218. new_pass = false;
  219. AH->connection = PQconnectdbParams(keywords, values, true);
  220. free(keywords);
  221. free(values);
  222. if (!AH->connection)
  223. exit_horribly(modulename, "failed to connect to database\n");
  224. if (PQstatus(AH->connection) == CONNECTION_BAD &&
  225. PQconnectionNeedsPassword(AH->connection) &&
  226. password == NULL &&
  227. prompt_password != TRI_NO)
  228. {
  229. PQfinish(AH->connection);
  230. password = simple_prompt("Password: ", 100, false);
  231. if (password == NULL)
  232. exit_horribly(modulename, "out of memory\n");
  233. new_pass = true;
  234. }
  235. } while (new_pass);
  236. AH->savedPassword = password;
  237. /* check to see that the backend connection was successfully made */
  238. if (PQstatus(AH->connection) == CONNECTION_BAD)
  239. exit_horribly(modulename, "connection to database \"%s\" failed: %s",
  240. PQdb(AH->connection) ? PQdb(AH->connection) : "",
  241. PQerrorMessage(AH->connection));
  242. /* check for version mismatch */
  243. _check_database_version(AH);
  244. PQsetNoticeProcessor(AH->connection, notice_processor, NULL);
  245. }
  246. /*
  247. * Close the connection to the database and also cancel off the query if we
  248. * have one running.
  249. */
  250. void
  251. DisconnectDatabase(Archive *AHX)
  252. {
  253. ArchiveHandle *AH = (ArchiveHandle *) AHX;
  254. PGcancel *cancel;
  255. char errbuf[1];
  256. if (!AH->connection)
  257. return;
  258. if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE)
  259. {
  260. if ((cancel = PQgetCancel(AH->connection)))
  261. {
  262. PQcancel(cancel, errbuf, sizeof(errbuf));
  263. PQfreeCancel(cancel);
  264. }
  265. }
  266. PQfinish(AH->connection);
  267. AH->connection = NULL;
  268. }
  269. PGconn *
  270. GetConnection(Archive *AHX)
  271. {
  272. ArchiveHandle *AH = (ArchiveHandle *) AHX;
  273. return AH->connection;
  274. }
  275. static void
  276. notice_processor(void *arg, const char *message)
  277. {
  278. write_msg(NULL, "%s", message);
  279. }
  280. /* Like exit_horribly(), but with a complaint about a particular query. */
  281. static void
  282. die_on_query_failure(ArchiveHandle *AH, const char *modulename, const char *query)
  283. {
  284. write_msg(modulename, "query failed: %s",
  285. PQerrorMessage(AH->connection));
  286. exit_horribly(modulename, "query was: %s\n", query);
  287. }
  288. void
  289. ExecuteSqlStatement(Archive *AHX, const char *query)
  290. {
  291. ArchiveHandle *AH = (ArchiveHandle *) AHX;
  292. PGresult *res;
  293. res = PQexec(AH->connection, query);
  294. if (PQresultStatus(res) != PGRES_COMMAND_OK)
  295. die_on_query_failure(AH, modulename, query);
  296. PQclear(res);
  297. }
  298. PGresult *
  299. ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
  300. {
  301. ArchiveHandle *AH = (ArchiveHandle *) AHX;
  302. PGresult *res;
  303. res = PQexec(AH->connection, query);
  304. if (PQresultStatus(res) != status)
  305. die_on_query_failure(AH, modulename, query);
  306. return res;
  307. }
  308. /*
  309. * Convenience function to send a query.
  310. * Monitors result to detect COPY statements
  311. */
  312. static void
  313. ExecuteSqlCommand(ArchiveHandle *AH, const char *qry, const char *desc)
  314. {
  315. PGconn *conn = AH->connection;
  316. PGresult *res;
  317. char errStmt[DB_MAX_ERR_STMT];
  318. #ifdef NOT_USED
  319. fprintf(stderr, "Executing: '%s'\n\n", qry);
  320. #endif
  321. res = PQexec(conn, qry);
  322. switch (PQresultStatus(res))
  323. {
  324. case PGRES_COMMAND_OK:
  325. case PGRES_TUPLES_OK:
  326. case PGRES_EMPTY_QUERY:
  327. /* A-OK */
  328. break;
  329. case PGRES_COPY_IN:
  330. /* Assume this is an expected result */
  331. AH->pgCopyIn = true;
  332. break;
  333. default:
  334. /* trouble */
  335. strncpy(errStmt, qry, DB_MAX_ERR_STMT);
  336. if (errStmt[DB_MAX_ERR_STMT - 1] != '\0')
  337. {
  338. errStmt[DB_MAX_ERR_STMT - 4] = '.';
  339. errStmt[DB_MAX_ERR_STMT - 3] = '.';
  340. errStmt[DB_MAX_ERR_STMT - 2] = '.';
  341. errStmt[DB_MAX_ERR_STMT - 1] = '\0';
  342. }
  343. warn_or_exit_horribly(AH, modulename, "%s: %s Command was: %s\n",
  344. desc, PQerrorMessage(conn), errStmt);
  345. break;
  346. }
  347. PQclear(res);
  348. }
  349. /*
  350. * Process non-COPY table data (that is, INSERT commands).
  351. *
  352. * The commands have been run together as one long string for compressibility,
  353. * and we are receiving them in bufferloads with arbitrary boundaries, so we
  354. * have to locate command boundaries and save partial commands across calls.
  355. * All state must be kept in AH->sqlparse, not in local variables of this
  356. * routine. We assume that AH->sqlparse was filled with zeroes when created.
  357. *
  358. * We have to lex the data to the extent of identifying literals and quoted
  359. * identifiers, so that we can recognize statement-terminating semicolons.
  360. * We assume that INSERT data will not contain SQL comments, E'' literals,
  361. * or dollar-quoted strings, so this is much simpler than a full SQL lexer.
  362. */
  363. static void
  364. ExecuteInsertCommands(ArchiveHandle *AH, const char *buf, size_t bufLen)
  365. {
  366. const char *qry = buf;
  367. const char *eos = buf + bufLen;
  368. /* initialize command buffer if first time through */
  369. if (AH->sqlparse.curCmd == NULL)
  370. AH->sqlparse.curCmd = createPQExpBuffer();
  371. for (; qry < eos; qry++)
  372. {
  373. char ch = *qry;
  374. /* For neatness, we skip any newlines between commands */
  375. if (!(ch == '\n' && AH->sqlparse.curCmd->len == 0))
  376. appendPQExpBufferChar(AH->sqlparse.curCmd, ch);
  377. switch (AH->sqlparse.state)
  378. {
  379. case SQL_SCAN: /* Default state == 0, set in _allocAH */
  380. if (ch == ';')
  381. {
  382. /*
  383. * We've found the end of a statement. Send it and reset
  384. * the buffer.
  385. */
  386. ExecuteSqlCommand(AH, AH->sqlparse.curCmd->data,
  387. "could not execute query");
  388. resetPQExpBuffer(AH->sqlparse.curCmd);
  389. }
  390. else if (ch == '\'')
  391. {
  392. AH->sqlparse.state = SQL_IN_SINGLE_QUOTE;
  393. AH->sqlparse.backSlash = false;
  394. }
  395. else if (ch == '"')
  396. {
  397. AH->sqlparse.state = SQL_IN_DOUBLE_QUOTE;
  398. }
  399. break;
  400. case SQL_IN_SINGLE_QUOTE:
  401. /* We needn't handle '' specially */
  402. if (ch == '\'' && !AH->sqlparse.backSlash)
  403. AH->sqlparse.state = SQL_SCAN;
  404. else if (ch == '\\' && !AH->public.std_strings)
  405. AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
  406. else
  407. AH->sqlparse.backSlash = false;
  408. break;
  409. case SQL_IN_DOUBLE_QUOTE:
  410. /* We needn't handle "" specially */
  411. if (ch == '"')
  412. AH->sqlparse.state = SQL_SCAN;
  413. break;
  414. }
  415. }
  416. }
  417. /*
  418. * Implement ahwrite() for direct-to-DB restore
  419. */
  420. int
  421. ExecuteSqlCommandBuf(ArchiveHandle *AH, const char *buf, size_t bufLen)
  422. {
  423. if (AH->outputKind == OUTPUT_COPYDATA)
  424. {
  425. /*
  426. * COPY data.
  427. *
  428. * We drop the data on the floor if libpq has failed to enter COPY
  429. * mode; this allows us to behave reasonably when trying to continue
  430. * after an error in a COPY command.
  431. */
  432. if (AH->pgCopyIn &&
  433. PQputCopyData(AH->connection, buf, bufLen) <= 0)
  434. exit_horribly(modulename, "error returned by PQputCopyData: %s",
  435. PQerrorMessage(AH->connection));
  436. }
  437. else if (AH->outputKind == OUTPUT_OTHERDATA)
  438. {
  439. /*
  440. * Table data expressed as INSERT commands.
  441. */
  442. ExecuteInsertCommands(AH, buf, bufLen);
  443. }
  444. else
  445. {
  446. /*
  447. * General SQL commands; we assume that commands will not be split
  448. * across calls.
  449. *
  450. * In most cases the data passed to us will be a null-terminated
  451. * string, but if it's not, we have to add a trailing null.
  452. */
  453. if (buf[bufLen] == '\0')
  454. ExecuteSqlCommand(AH, buf, "could not execute query");
  455. else
  456. {
  457. char *str = (char *) pg_malloc(bufLen + 1);
  458. memcpy(str, buf, bufLen);
  459. str[bufLen] = '\0';
  460. ExecuteSqlCommand(AH, str, "could not execute query");
  461. free(str);
  462. }
  463. }
  464. return 1;
  465. }
  466. /*
  467. * Terminate a COPY operation during direct-to-DB restore
  468. */
  469. void
  470. EndDBCopyMode(ArchiveHandle *AH, TocEntry *te)
  471. {
  472. if (AH->pgCopyIn)
  473. {
  474. PGresult *res;
  475. if (PQputCopyEnd(AH->connection, NULL) <= 0)
  476. exit_horribly(modulename, "error returned by PQputCopyEnd: %s",
  477. PQerrorMessage(AH->connection));
  478. /* Check command status and return to normal libpq state */
  479. res = PQgetResult(AH->connection);
  480. if (PQresultStatus(res) != PGRES_COMMAND_OK)
  481. warn_or_exit_horribly(AH, modulename, "COPY failed for table \"%s\": %s",
  482. te->tag, PQerrorMessage(AH->connection));
  483. PQclear(res);
  484. AH->pgCopyIn = false;
  485. }
  486. }
  487. void
  488. StartTransaction(ArchiveHandle *AH)
  489. {
  490. ExecuteSqlCommand(AH, "BEGIN", "could not start database transaction");
  491. }
  492. void
  493. CommitTransaction(ArchiveHandle *AH)
  494. {
  495. ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
  496. }
  497. void
  498. DropBlobIfExists(ArchiveHandle *AH, Oid oid)
  499. {
  500. /*
  501. * If we are not restoring to a direct database connection, we have to
  502. * guess about how to detect whether the blob exists. Assume new-style.
  503. */
  504. if (AH->connection == NULL ||
  505. PQserverVersion(AH->connection) >= 90000)
  506. {
  507. ahprintf(AH,
  508. "SELECT pg_catalog.lo_unlink(oid) "
  509. "FROM pg_catalog.pg_largeobject_metadata "
  510. "WHERE oid = '%u';\n",
  511. oid);
  512. }
  513. else
  514. {
  515. /* Restoring to pre-9.0 server, so do it the old way */
  516. ahprintf(AH,
  517. "SELECT CASE WHEN EXISTS("
  518. "SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u'"
  519. ") THEN pg_catalog.lo_unlink('%u') END;\n",
  520. oid, oid);
  521. }
  522. }