diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c new file mode 100644 index f6e2a28..64dcad8 *** a/contrib/vacuumlo/vacuumlo.c --- b/contrib/vacuumlo/vacuumlo.c *************** *** 23,28 **** --- 23,29 ---- #include "libpq-fe.h" #include "libpq/libpq-fs.h" + #include #define atooid(x) ((Oid) strtoul((x), NULL, 10)) *************** struct _param *** 48,53 **** --- 49,55 ---- char *pg_host; int verbose; int dry_run; + int transaction_limit; }; int vacuumlo(char *, struct _param *); *************** vacuumlo(char *database, struct _param * *** 70,75 **** --- 72,78 ---- int i; static char *password = NULL; bool new_pass; + bool success = true; if (param->pg_prompt == TRI_YES && password == NULL) password = simple_prompt("Password: ", 100, false); *************** vacuumlo(char *database, struct _param * *** 280,291 **** --- 283,303 ---- { fprintf(stderr, "\nFailed to remove lo %u: ", lo); fprintf(stderr, "%s", PQerrorMessage(conn)); + if (PQtransactionStatus(conn) == PQTRANS_INERROR) { + fprintf(stderr, + "Bailing out. Try using -l LIMIT flag, " + "with a LIMIT of %d\n", i); + success = false; + break; + } } else deleted++; } else deleted++; + if (param->transaction_limit != 0 && deleted >= param->transaction_limit) + break; } PQclear(res); *************** vacuumlo(char *database, struct _param * *** 297,307 **** PQfinish(conn); ! if (param->verbose) ! fprintf(stdout, "\r%s %d large objects from %s.\n", ! (param->dry_run ? "Would remove" : "Removed"), deleted, database); ! return 0; } void --- 309,326 ---- PQfinish(conn); ! if (param->verbose) { ! if (param->dry_run) ! fprintf(stdout, "\rWould remove"); ! else if (success) ! fprintf(stdout, "\rSuccessfully removed"); ! else ! fprintf(stdout, "\rFailed to remove"); ! fprintf(stdout, " %d large objects from %s.\n", deleted, database); ! } ! ! return ((param->dry_run || success) ? 0 : -1); } void *************** usage(const char *progname) *** 311,316 **** --- 330,336 ---- printf("Usage:\n %s [OPTION]... DBNAME...\n\n", progname); printf("Options:\n"); printf(" -h HOSTNAME database server host or socket directory\n"); + printf(" -l LIMIT stop after removing LIMIT large objects\n"); printf(" -n don't remove large objects, just show what would be done\n"); printf(" -p PORT database server port\n"); printf(" -U USERNAME user name to connect as\n"); *************** main(int argc, char **argv) *** 342,347 **** --- 362,368 ---- param.pg_port = NULL; param.verbose = 0; param.dry_run = 0; + param.transaction_limit = 0; if (argc > 1) { *************** main(int argc, char **argv) *** 359,365 **** while (1) { ! c = getopt(argc, argv, "h:U:p:vnwW"); if (c == -1) break; --- 380,386 ---- while (1) { ! c = getopt(argc, argv, "h:l:U:p:vnwW"); if (c == -1) break; *************** main(int argc, char **argv) *** 395,400 **** --- 416,429 ---- } param.pg_port = strdup(optarg); break; + case 'l': + param.transaction_limit = strtol(optarg, NULL, 10); + if ((param.transaction_limit < 0) || (param.transaction_limit > INT_MAX)) + { + fprintf(stderr, "%s: invalid transaction limit number: %s, valid range is form 0(disabled) to INT_MAX(%i).\n", progname, optarg, INT_MAX); + exit(1); + } + break; case 'h': param.pg_host = strdup(optarg); break; diff --git a/doc/src/sgml/vacuumlo.sgml b/doc/src/sgml/vacuumlo.sgml new file mode 100644 index 471a6ca..905eae1 *** a/doc/src/sgml/vacuumlo.sgml --- b/doc/src/sgml/vacuumlo.sgml *************** vacuumlo [options] database [database2 . *** 57,62 **** --- 57,72 ---- + limit + + + Stop after removing LIMIT large objects. Useful to avoid + exceeding max_locks_per_transaction. + + + + +