| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * pg_restore.c |
| 4 | * pg_restore is an utility extracting postgres database definitions |
| 5 | * from a backup archive created by pg_dump using the archiver |
| 6 | * interface. |
| 7 | * |
| 8 | * pg_restore will read the backup archive and |
| 9 | * dump out a script that reproduces |
| 10 | * the schema of the database in terms of |
| 11 | * user-defined types |
| 12 | * user-defined functions |
| 13 | * tables |
| 14 | * indexes |
| 15 | * aggregates |
| 16 | * operators |
| 17 | * ACL - grant/revoke |
| 18 | * |
| 19 | * the output script is SQL that is understood by PostgreSQL |
| 20 | * |
| 21 | * Basic process in a restore operation is: |
| 22 | * |
| 23 | * Open the Archive and read the TOC. |
| 24 | * Set flags in TOC entries, and *maybe* reorder them. |
| 25 | * Generate script to stdout |
| 26 | * Exit |
| 27 | * |
| 28 | * Copyright (c) 2000, Philip Warner |
| 29 | * Rights are granted to use this software in any way so long |
| 30 | * as this notice is not removed. |
| 31 | * |
| 32 | * The author is not responsible for loss or damages that may |
| 33 | * result from its use. |
| 34 | * |
| 35 | * |
| 36 | * IDENTIFICATION |
| 37 | * src/bin/pg_dump/pg_restore.c |
| 38 | * |
| 39 | *------------------------------------------------------------------------- |
| 40 | */ |
| 41 | #include "postgres_fe.h" |
| 42 | |
| 43 | #include <ctype.h> |
| 44 | #ifdef HAVE_TERMIOS_H |
| 45 | #include <termios.h> |
| 46 | #endif |
| 47 | |
| 48 | #include "getopt_long.h" |
| 49 | |
| 50 | #include "dumputils.h" |
| 51 | #include "parallel.h" |
| 52 | #include "pg_backup_utils.h" |
| 53 | |
| 54 | |
| 55 | static void usage(const char *progname); |
| 56 | |
| 57 | typedef struct option optType; |
| 58 | |
| 59 | int |
| 60 | main(int argc, char **argv) |
| 61 | { |
| 62 | RestoreOptions *opts; |
| 63 | int c; |
| 64 | int exit_code; |
| 65 | int numWorkers = 1; |
| 66 | Archive *AH; |
| 67 | char *inputFileSpec; |
| 68 | static int disable_triggers = 0; |
| 69 | static int enable_row_security = 0; |
| 70 | static int if_exists = 0; |
| 71 | static int no_data_for_failed_tables = 0; |
| 72 | static int outputNoTablespaces = 0; |
| 73 | static int use_setsessauth = 0; |
| 74 | static int = 0; |
| 75 | static int no_publications = 0; |
| 76 | static int no_security_labels = 0; |
| 77 | static int no_subscriptions = 0; |
| 78 | static int strict_names = 0; |
| 79 | |
| 80 | struct option cmdopts[] = { |
| 81 | {"clean" , 0, NULL, 'c'}, |
| 82 | {"create" , 0, NULL, 'C'}, |
| 83 | {"data-only" , 0, NULL, 'a'}, |
| 84 | {"dbname" , 1, NULL, 'd'}, |
| 85 | {"exit-on-error" , 0, NULL, 'e'}, |
| 86 | {"exclude-schema" , 1, NULL, 'N'}, |
| 87 | {"file" , 1, NULL, 'f'}, |
| 88 | {"format" , 1, NULL, 'F'}, |
| 89 | {"function" , 1, NULL, 'P'}, |
| 90 | {"host" , 1, NULL, 'h'}, |
| 91 | {"index" , 1, NULL, 'I'}, |
| 92 | {"jobs" , 1, NULL, 'j'}, |
| 93 | {"list" , 0, NULL, 'l'}, |
| 94 | {"no-privileges" , 0, NULL, 'x'}, |
| 95 | {"no-acl" , 0, NULL, 'x'}, |
| 96 | {"no-owner" , 0, NULL, 'O'}, |
| 97 | {"no-reconnect" , 0, NULL, 'R'}, |
| 98 | {"port" , 1, NULL, 'p'}, |
| 99 | {"no-password" , 0, NULL, 'w'}, |
| 100 | {"password" , 0, NULL, 'W'}, |
| 101 | {"schema" , 1, NULL, 'n'}, |
| 102 | {"schema-only" , 0, NULL, 's'}, |
| 103 | {"superuser" , 1, NULL, 'S'}, |
| 104 | {"table" , 1, NULL, 't'}, |
| 105 | {"trigger" , 1, NULL, 'T'}, |
| 106 | {"use-list" , 1, NULL, 'L'}, |
| 107 | {"username" , 1, NULL, 'U'}, |
| 108 | {"verbose" , 0, NULL, 'v'}, |
| 109 | {"single-transaction" , 0, NULL, '1'}, |
| 110 | |
| 111 | /* |
| 112 | * the following options don't have an equivalent short option letter |
| 113 | */ |
| 114 | {"disable-triggers" , no_argument, &disable_triggers, 1}, |
| 115 | {"enable-row-security" , no_argument, &enable_row_security, 1}, |
| 116 | {"if-exists" , no_argument, &if_exists, 1}, |
| 117 | {"no-data-for-failed-tables" , no_argument, &no_data_for_failed_tables, 1}, |
| 118 | {"no-tablespaces" , no_argument, &outputNoTablespaces, 1}, |
| 119 | {"role" , required_argument, NULL, 2}, |
| 120 | {"section" , required_argument, NULL, 3}, |
| 121 | {"strict-names" , no_argument, &strict_names, 1}, |
| 122 | {"use-set-session-authorization" , no_argument, &use_setsessauth, 1}, |
| 123 | {"no-comments" , no_argument, &no_comments, 1}, |
| 124 | {"no-publications" , no_argument, &no_publications, 1}, |
| 125 | {"no-security-labels" , no_argument, &no_security_labels, 1}, |
| 126 | {"no-subscriptions" , no_argument, &no_subscriptions, 1}, |
| 127 | |
| 128 | {NULL, 0, NULL, 0} |
| 129 | }; |
| 130 | |
| 131 | pg_logging_init(argv[0]); |
| 132 | pg_logging_set_level(PG_LOG_WARNING); |
| 133 | set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump" )); |
| 134 | |
| 135 | init_parallel_dump_utils(); |
| 136 | |
| 137 | opts = NewRestoreOptions(); |
| 138 | |
| 139 | progname = get_progname(argv[0]); |
| 140 | |
| 141 | if (argc > 1) |
| 142 | { |
| 143 | if (strcmp(argv[1], "--help" ) == 0 || strcmp(argv[1], "-?" ) == 0) |
| 144 | { |
| 145 | usage(progname); |
| 146 | exit_nicely(0); |
| 147 | } |
| 148 | if (strcmp(argv[1], "--version" ) == 0 || strcmp(argv[1], "-V" ) == 0) |
| 149 | { |
| 150 | puts("pg_restore (PostgreSQL) " PG_VERSION); |
| 151 | exit_nicely(0); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | while ((c = getopt_long(argc, argv, "acCd:ef:F:h:I:j:lL:n:N:Op:P:RsS:t:T:U:vwWx1" , |
| 156 | cmdopts, NULL)) != -1) |
| 157 | { |
| 158 | switch (c) |
| 159 | { |
| 160 | case 'a': /* Dump data only */ |
| 161 | opts->dataOnly = 1; |
| 162 | break; |
| 163 | case 'c': /* clean (i.e., drop) schema prior to create */ |
| 164 | opts->dropSchema = 1; |
| 165 | break; |
| 166 | case 'C': |
| 167 | opts->createDB = 1; |
| 168 | break; |
| 169 | case 'd': |
| 170 | opts->dbname = pg_strdup(optarg); |
| 171 | break; |
| 172 | case 'e': |
| 173 | opts->exit_on_error = true; |
| 174 | break; |
| 175 | case 'f': /* output file name */ |
| 176 | opts->filename = pg_strdup(optarg); |
| 177 | break; |
| 178 | case 'F': |
| 179 | if (strlen(optarg) != 0) |
| 180 | opts->formatName = pg_strdup(optarg); |
| 181 | break; |
| 182 | case 'h': |
| 183 | if (strlen(optarg) != 0) |
| 184 | opts->pghost = pg_strdup(optarg); |
| 185 | break; |
| 186 | |
| 187 | case 'j': /* number of restore jobs */ |
| 188 | numWorkers = atoi(optarg); |
| 189 | break; |
| 190 | |
| 191 | case 'l': /* Dump the TOC summary */ |
| 192 | opts->tocSummary = 1; |
| 193 | break; |
| 194 | |
| 195 | case 'L': /* input TOC summary file name */ |
| 196 | opts->tocFile = pg_strdup(optarg); |
| 197 | break; |
| 198 | |
| 199 | case 'n': /* Dump data for this schema only */ |
| 200 | simple_string_list_append(&opts->schemaNames, optarg); |
| 201 | break; |
| 202 | |
| 203 | case 'N': /* Do not dump data for this schema */ |
| 204 | simple_string_list_append(&opts->schemaExcludeNames, optarg); |
| 205 | break; |
| 206 | |
| 207 | case 'O': |
| 208 | opts->noOwner = 1; |
| 209 | break; |
| 210 | |
| 211 | case 'p': |
| 212 | if (strlen(optarg) != 0) |
| 213 | opts->pgport = pg_strdup(optarg); |
| 214 | break; |
| 215 | case 'R': |
| 216 | /* no-op, still accepted for backwards compatibility */ |
| 217 | break; |
| 218 | case 'P': /* Function */ |
| 219 | opts->selTypes = 1; |
| 220 | opts->selFunction = 1; |
| 221 | simple_string_list_append(&opts->functionNames, optarg); |
| 222 | break; |
| 223 | case 'I': /* Index */ |
| 224 | opts->selTypes = 1; |
| 225 | opts->selIndex = 1; |
| 226 | simple_string_list_append(&opts->indexNames, optarg); |
| 227 | break; |
| 228 | case 'T': /* Trigger */ |
| 229 | opts->selTypes = 1; |
| 230 | opts->selTrigger = 1; |
| 231 | simple_string_list_append(&opts->triggerNames, optarg); |
| 232 | break; |
| 233 | case 's': /* dump schema only */ |
| 234 | opts->schemaOnly = 1; |
| 235 | break; |
| 236 | case 'S': /* Superuser username */ |
| 237 | if (strlen(optarg) != 0) |
| 238 | opts->superuser = pg_strdup(optarg); |
| 239 | break; |
| 240 | case 't': /* Dump specified table(s) only */ |
| 241 | opts->selTypes = 1; |
| 242 | opts->selTable = 1; |
| 243 | simple_string_list_append(&opts->tableNames, optarg); |
| 244 | break; |
| 245 | |
| 246 | case 'U': |
| 247 | opts->username = pg_strdup(optarg); |
| 248 | break; |
| 249 | |
| 250 | case 'v': /* verbose */ |
| 251 | opts->verbose = 1; |
| 252 | pg_logging_set_level(PG_LOG_INFO); |
| 253 | break; |
| 254 | |
| 255 | case 'w': |
| 256 | opts->promptPassword = TRI_NO; |
| 257 | break; |
| 258 | |
| 259 | case 'W': |
| 260 | opts->promptPassword = TRI_YES; |
| 261 | break; |
| 262 | |
| 263 | case 'x': /* skip ACL dump */ |
| 264 | opts->aclsSkip = 1; |
| 265 | break; |
| 266 | |
| 267 | case '1': /* Restore data in a single transaction */ |
| 268 | opts->single_txn = true; |
| 269 | opts->exit_on_error = true; |
| 270 | break; |
| 271 | |
| 272 | case 0: |
| 273 | |
| 274 | /* |
| 275 | * This covers the long options without a short equivalent. |
| 276 | */ |
| 277 | break; |
| 278 | |
| 279 | case 2: /* SET ROLE */ |
| 280 | opts->use_role = pg_strdup(optarg); |
| 281 | break; |
| 282 | |
| 283 | case 3: /* section */ |
| 284 | set_dump_section(optarg, &(opts->dumpSections)); |
| 285 | break; |
| 286 | |
| 287 | default: |
| 288 | fprintf(stderr, _("Try \"%s --help\" for more information.\n" ), progname); |
| 289 | exit_nicely(1); |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | /* Get file name from command line */ |
| 294 | if (optind < argc) |
| 295 | inputFileSpec = argv[optind++]; |
| 296 | else |
| 297 | inputFileSpec = NULL; |
| 298 | |
| 299 | /* Complain if any arguments remain */ |
| 300 | if (optind < argc) |
| 301 | { |
| 302 | pg_log_error("too many command-line arguments (first is \"%s\")" , |
| 303 | argv[optind]); |
| 304 | fprintf(stderr, _("Try \"%s --help\" for more information.\n" ), |
| 305 | progname); |
| 306 | exit_nicely(1); |
| 307 | } |
| 308 | |
| 309 | /* Complain if neither -f nor -d was specified (except if dumping TOC) */ |
| 310 | if (!opts->dbname && !opts->filename && !opts->tocSummary) |
| 311 | { |
| 312 | pg_log_error("one of -d/--dbname and -f/--file must be specified" ); |
| 313 | exit_nicely(1); |
| 314 | } |
| 315 | |
| 316 | /* Should get at most one of -d and -f, else user is confused */ |
| 317 | if (opts->dbname) |
| 318 | { |
| 319 | if (opts->filename) |
| 320 | { |
| 321 | pg_log_error("options -d/--dbname and -f/--file cannot be used together" ); |
| 322 | fprintf(stderr, _("Try \"%s --help\" for more information.\n" ), |
| 323 | progname); |
| 324 | exit_nicely(1); |
| 325 | } |
| 326 | opts->useDB = 1; |
| 327 | } |
| 328 | |
| 329 | if (opts->dataOnly && opts->schemaOnly) |
| 330 | { |
| 331 | pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together" ); |
| 332 | exit_nicely(1); |
| 333 | } |
| 334 | |
| 335 | if (opts->dataOnly && opts->dropSchema) |
| 336 | { |
| 337 | pg_log_error("options -c/--clean and -a/--data-only cannot be used together" ); |
| 338 | exit_nicely(1); |
| 339 | } |
| 340 | |
| 341 | /* |
| 342 | * -C is not compatible with -1, because we can't create a database inside |
| 343 | * a transaction block. |
| 344 | */ |
| 345 | if (opts->createDB && opts->single_txn) |
| 346 | { |
| 347 | pg_log_error("options -C/--create and -1/--single-transaction cannot be used together" ); |
| 348 | exit_nicely(1); |
| 349 | } |
| 350 | |
| 351 | if (numWorkers <= 0) |
| 352 | { |
| 353 | pg_log_error("invalid number of parallel jobs" ); |
| 354 | exit(1); |
| 355 | } |
| 356 | |
| 357 | /* See comments in pg_dump.c */ |
| 358 | #ifdef WIN32 |
| 359 | if (numWorkers > MAXIMUM_WAIT_OBJECTS) |
| 360 | { |
| 361 | pg_log_error("maximum number of parallel jobs is %d" , |
| 362 | MAXIMUM_WAIT_OBJECTS); |
| 363 | exit(1); |
| 364 | } |
| 365 | #endif |
| 366 | |
| 367 | /* Can't do single-txn mode with multiple connections */ |
| 368 | if (opts->single_txn && numWorkers > 1) |
| 369 | { |
| 370 | pg_log_error("cannot specify both --single-transaction and multiple jobs" ); |
| 371 | exit_nicely(1); |
| 372 | } |
| 373 | |
| 374 | opts->disable_triggers = disable_triggers; |
| 375 | opts->enable_row_security = enable_row_security; |
| 376 | opts->noDataForFailedTables = no_data_for_failed_tables; |
| 377 | opts->noTablespace = outputNoTablespaces; |
| 378 | opts->use_setsessauth = use_setsessauth; |
| 379 | opts->no_comments = no_comments; |
| 380 | opts->no_publications = no_publications; |
| 381 | opts->no_security_labels = no_security_labels; |
| 382 | opts->no_subscriptions = no_subscriptions; |
| 383 | |
| 384 | if (if_exists && !opts->dropSchema) |
| 385 | { |
| 386 | pg_log_error("option --if-exists requires option -c/--clean" ); |
| 387 | exit_nicely(1); |
| 388 | } |
| 389 | opts->if_exists = if_exists; |
| 390 | opts->strict_names = strict_names; |
| 391 | |
| 392 | if (opts->formatName) |
| 393 | { |
| 394 | switch (opts->formatName[0]) |
| 395 | { |
| 396 | case 'c': |
| 397 | case 'C': |
| 398 | opts->format = archCustom; |
| 399 | break; |
| 400 | |
| 401 | case 'd': |
| 402 | case 'D': |
| 403 | opts->format = archDirectory; |
| 404 | break; |
| 405 | |
| 406 | case 't': |
| 407 | case 'T': |
| 408 | opts->format = archTar; |
| 409 | break; |
| 410 | |
| 411 | default: |
| 412 | pg_log_error("unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"" , |
| 413 | opts->formatName); |
| 414 | exit_nicely(1); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | AH = OpenArchive(inputFileSpec, opts->format); |
| 419 | |
| 420 | SetArchiveOptions(AH, NULL, opts); |
| 421 | |
| 422 | /* |
| 423 | * We don't have a connection yet but that doesn't matter. The connection |
| 424 | * is initialized to NULL and if we terminate through exit_nicely() while |
| 425 | * it's still NULL, the cleanup function will just be a no-op. |
| 426 | */ |
| 427 | on_exit_close_archive(AH); |
| 428 | |
| 429 | /* Let the archiver know how noisy to be */ |
| 430 | AH->verbose = opts->verbose; |
| 431 | |
| 432 | /* |
| 433 | * Whether to keep submitting sql commands as "pg_restore ... | psql ... " |
| 434 | */ |
| 435 | AH->exit_on_error = opts->exit_on_error; |
| 436 | |
| 437 | if (opts->tocFile) |
| 438 | SortTocFromFile(AH); |
| 439 | |
| 440 | AH->numWorkers = numWorkers; |
| 441 | |
| 442 | if (opts->tocSummary) |
| 443 | PrintTOCSummary(AH); |
| 444 | else |
| 445 | { |
| 446 | ProcessArchiveRestoreOptions(AH); |
| 447 | RestoreArchive(AH); |
| 448 | } |
| 449 | |
| 450 | /* done, print a summary of ignored errors */ |
| 451 | if (AH->n_errors) |
| 452 | pg_log_warning("errors ignored on restore: %d" , AH->n_errors); |
| 453 | |
| 454 | /* AH may be freed in CloseArchive? */ |
| 455 | exit_code = AH->n_errors ? 1 : 0; |
| 456 | |
| 457 | CloseArchive(AH); |
| 458 | |
| 459 | return exit_code; |
| 460 | } |
| 461 | |
| 462 | static void |
| 463 | usage(const char *progname) |
| 464 | { |
| 465 | printf(_("%s restores a PostgreSQL database from an archive created by pg_dump.\n\n" ), progname); |
| 466 | printf(_("Usage:\n" )); |
| 467 | printf(_(" %s [OPTION]... [FILE]\n" ), progname); |
| 468 | |
| 469 | printf(_("\nGeneral options:\n" )); |
| 470 | printf(_(" -d, --dbname=NAME connect to database name\n" )); |
| 471 | printf(_(" -f, --file=FILENAME output file name (- for stdout)\n" )); |
| 472 | printf(_(" -F, --format=c|d|t backup file format (should be automatic)\n" )); |
| 473 | printf(_(" -l, --list print summarized TOC of the archive\n" )); |
| 474 | printf(_(" -v, --verbose verbose mode\n" )); |
| 475 | printf(_(" -V, --version output version information, then exit\n" )); |
| 476 | printf(_(" -?, --help show this help, then exit\n" )); |
| 477 | |
| 478 | printf(_("\nOptions controlling the restore:\n" )); |
| 479 | printf(_(" -a, --data-only restore only the data, no schema\n" )); |
| 480 | printf(_(" -c, --clean clean (drop) database objects before recreating\n" )); |
| 481 | printf(_(" -C, --create create the target database\n" )); |
| 482 | printf(_(" -e, --exit-on-error exit on error, default is to continue\n" )); |
| 483 | printf(_(" -I, --index=NAME restore named index\n" )); |
| 484 | printf(_(" -j, --jobs=NUM use this many parallel jobs to restore\n" )); |
| 485 | printf(_(" -L, --use-list=FILENAME use table of contents from this file for\n" |
| 486 | " selecting/ordering output\n" )); |
| 487 | printf(_(" -n, --schema=NAME restore only objects in this schema\n" )); |
| 488 | printf(_(" -N, --exclude-schema=NAME do not restore objects in this schema\n" )); |
| 489 | printf(_(" -O, --no-owner skip restoration of object ownership\n" )); |
| 490 | printf(_(" -P, --function=NAME(args) restore named function\n" )); |
| 491 | printf(_(" -s, --schema-only restore only the schema, no data\n" )); |
| 492 | printf(_(" -S, --superuser=NAME superuser user name to use for disabling triggers\n" )); |
| 493 | printf(_(" -t, --table=NAME restore named relation (table, view, etc.)\n" )); |
| 494 | printf(_(" -T, --trigger=NAME restore named trigger\n" )); |
| 495 | printf(_(" -x, --no-privileges skip restoration of access privileges (grant/revoke)\n" )); |
| 496 | printf(_(" -1, --single-transaction restore as a single transaction\n" )); |
| 497 | printf(_(" --disable-triggers disable triggers during data-only restore\n" )); |
| 498 | printf(_(" --enable-row-security enable row security\n" )); |
| 499 | printf(_(" --if-exists use IF EXISTS when dropping objects\n" )); |
| 500 | printf(_(" --no-comments do not restore comments\n" )); |
| 501 | printf(_(" --no-data-for-failed-tables do not restore data of tables that could not be\n" |
| 502 | " created\n" )); |
| 503 | printf(_(" --no-publications do not restore publications\n" )); |
| 504 | printf(_(" --no-security-labels do not restore security labels\n" )); |
| 505 | printf(_(" --no-subscriptions do not restore subscriptions\n" )); |
| 506 | printf(_(" --no-tablespaces do not restore tablespace assignments\n" )); |
| 507 | printf(_(" --section=SECTION restore named section (pre-data, data, or post-data)\n" )); |
| 508 | printf(_(" --strict-names require table and/or schema include patterns to\n" |
| 509 | " match at least one entity each\n" )); |
| 510 | printf(_(" --use-set-session-authorization\n" |
| 511 | " use SET SESSION AUTHORIZATION commands instead of\n" |
| 512 | " ALTER OWNER commands to set ownership\n" )); |
| 513 | |
| 514 | printf(_("\nConnection options:\n" )); |
| 515 | printf(_(" -h, --host=HOSTNAME database server host or socket directory\n" )); |
| 516 | printf(_(" -p, --port=PORT database server port number\n" )); |
| 517 | printf(_(" -U, --username=NAME connect as specified database user\n" )); |
| 518 | printf(_(" -w, --no-password never prompt for password\n" )); |
| 519 | printf(_(" -W, --password force password prompt (should happen automatically)\n" )); |
| 520 | printf(_(" --role=ROLENAME do SET ROLE before restore\n" )); |
| 521 | |
| 522 | printf(_("\n" |
| 523 | "The options -I, -n, -N, -P, -t, -T, and --section can be combined and specified\n" |
| 524 | "multiple times to select multiple objects.\n" )); |
| 525 | printf(_("\nIf no input file name is supplied, then standard input is used.\n\n" )); |
| 526 | printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n" )); |
| 527 | } |
| 528 | |