mirror of https://github.com/postgres/postgres
parent
098e043849
commit
94bb87f94b
@ -0,0 +1,24 @@ |
||||
# $Header: /cvsroot/pgsql/contrib/vacuumlo/Makefile,v 1.1 1999/04/10 16:48:04 peter Exp $
|
||||
|
||||
SRCDIR= ../../src
|
||||
|
||||
include $(SRCDIR)/Makefile.global |
||||
|
||||
CONTRIBDIR=$(LIBDIR)/contrib
|
||||
|
||||
CFLAGS+= -I$(HEADERDIR)
|
||||
|
||||
TARGETS= vacuumlo
|
||||
CLEANFILES+= $(TARGETS)
|
||||
CURDIR=`pwd`
|
||||
|
||||
all:: $(TARGETS) |
||||
|
||||
$(TARGETS): vacuumlo.o |
||||
$(CC) -o vacuumlo -L $(LIBDIR) -lpq -lcrypt vacuumlo.o
|
||||
|
||||
clean: |
||||
rm -f $(TARGETS) *.o
|
||||
|
||||
dist: |
||||
tar cf vacuumlo.tar README Makefile vacuumlo.c
|
@ -0,0 +1,38 @@ |
||||
$Header: /cvsroot/pgsql/contrib/vacuumlo/Attic/README,v 1.1 1999/04/10 16:48:04 peter Exp $ |
||||
|
||||
This is a simple utility that will remove any orphaned large objects out of a |
||||
PostgreSQL database. |
||||
|
||||
Compiling |
||||
-------- |
||||
|
||||
Simply run make. A single executable "vacuumlo" is created. |
||||
|
||||
Useage |
||||
------ |
||||
|
||||
vacuumlo [-v] database [db2 ... dbn] |
||||
|
||||
The -v flag outputs some progress messages to stdout. |
||||
|
||||
Method |
||||
------ |
||||
|
||||
First, it builds a temporary table which contains all of the oid's of the |
||||
large objects in that database. |
||||
|
||||
It then scans through any columns in the database that are of type 'oid', and |
||||
removes any entries from the temporary table. |
||||
|
||||
Finally, it runs through the first table, and removes from the second table, any |
||||
oid's it finds. What is left are the orphans, and these are removed. |
||||
|
||||
I decided to place this in contrib as it needs further testing, but hopefully, |
||||
this (or a variant of it) would make it into the backed as a "vacuum lo" command |
||||
in a later release. |
||||
|
||||
Peter Mount <peter@retep.org.uk> |
||||
http://www.retep.org.uk |
||||
March 21 1999 |
||||
|
||||
Committed April 10 1999 Peter |
@ -0,0 +1,201 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* vacuumlo.c |
||||
* This removes orphaned large objects from a database. |
||||
* |
||||
* Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* $Header: /cvsroot/pgsql/contrib/vacuumlo/vacuumlo.c,v 1.1 1999/04/10 16:48:05 peter Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <strings.h> |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "libpq-fe.h" |
||||
#include "libpq/libpq-fs.h" |
||||
|
||||
#define BUFSIZE 1024 |
||||
|
||||
int vacuumlo(char *,int); |
||||
|
||||
|
||||
/*
|
||||
* This vacuums a database. It returns 1 on success, -1 on failure. |
||||
*/ |
||||
int vacuumlo(char *database,int verbose) |
||||
{ |
||||
PGconn *conn; |
||||
PGresult *res, *res2; |
||||
char buf[BUFSIZE]; |
||||
int matched=0; /* Number matched per scan */ |
||||
int i; |
||||
|
||||
conn = PQsetdb(NULL, NULL, NULL, NULL, database); |
||||
|
||||
/* check to see that the backend connection was successfully made */ |
||||
if (PQstatus(conn) == CONNECTION_BAD) |
||||
{ |
||||
fprintf(stderr, "Connection to database '%s' failed.\n", database); |
||||
fprintf(stderr, "%s", PQerrorMessage(conn)); |
||||
return -1; |
||||
} |
||||
|
||||
if(verbose) |
||||
fprintf(stdout,"Connected to %s\n",database); |
||||
|
||||
/*
|
||||
* First we create and populate the lo temp table |
||||
*/ |
||||
buf[0]='\0'; |
||||
strcat(buf,"SELECT oid AS lo "); |
||||
strcat(buf,"INTO TEMP TABLE vacuum_l "); |
||||
strcat(buf,"FROM pg_class "); |
||||
strcat(buf,"WHERE relkind='l'"); |
||||
if(!(res = PQexec(conn,buf))) { |
||||
fprintf(stderr,"Failed to create temp table.\n"); |
||||
PQfinish(conn); |
||||
return -1; |
||||
} |
||||
PQclear(res); |
||||
|
||||
/*
|
||||
* Now find any candidate tables who have columns of type oid (the column |
||||
* oid is ignored, as it has attnum < 1) |
||||
*/ |
||||
buf[0]='\0'; |
||||
strcat(buf,"SELECT c.relname, a.attname "); |
||||
strcat(buf,"FROM pg_class c, pg_attribute a, pg_type t "); |
||||
strcat(buf,"WHERE a.attnum > 0 "); |
||||
strcat(buf," AND a.attrelid = c.oid "); |
||||
strcat(buf," AND a.atttypid = t.oid "); |
||||
strcat(buf," AND t.typname = 'oid' "); |
||||
strcat(buf," AND c.relname NOT LIKE 'pg_%'"); |
||||
if(!(res = PQexec(conn,buf))) { |
||||
fprintf(stderr,"Failed to create temp table.\n"); |
||||
PQfinish(conn); |
||||
return -1; |
||||
} |
||||
for(i=0;i<PQntuples(res);i++) |
||||
{ |
||||
char *table,*field; |
||||
|
||||
table = PQgetvalue(res,i,0); |
||||
field = PQgetvalue(res,i,1); |
||||
|
||||
if(verbose) { |
||||
fprintf(stdout,"Checking %s in %s: ",field,table); |
||||
fflush(stdout); |
||||
} |
||||
|
||||
res2 = PQexec(conn, "begin"); |
||||
PQclear(res2); |
||||
|
||||
buf[0] = '\0'; |
||||
strcat(buf,"DELETE FROM vacuum_l "); |
||||
strcat(buf,"WHERE lo IN ("); |
||||
strcat(buf,"SELECT "); |
||||
strcat(buf,field); |
||||
strcat(buf," FROM "); |
||||
strcat(buf,table); |
||||
strcat(buf,");"); |
||||
if(!(res2 = PQexec(conn,buf))) { |
||||
fprintf(stderr,"Failed to check %s in table %s\n",field,table); |
||||
PQclear(res); |
||||
PQfinish(conn); |
||||
return -1; |
||||
} |
||||
if(PQresultStatus(res2)!=PGRES_COMMAND_OK) { |
||||
fprintf(stderr, |
||||
"Failed to check %s in table %s\n%s\n", |
||||
field,table, |
||||
PQerrorMessage(conn) |
||||
); |
||||
PQclear(res2); |
||||
PQclear(res); |
||||
PQfinish(conn); |
||||
return -1; |
||||
} |
||||
PQclear(res2); |
||||
|
||||
res2 = PQexec(conn, "end"); |
||||
PQclear(res2); |
||||
|
||||
} |
||||
PQclear(res); |
||||
|
||||
/* Start the transaction */ |
||||
res = PQexec(conn, "begin"); |
||||
PQclear(res); |
||||
|
||||
/*
|
||||
* Finally, those entries remaining in vacuum_l are orphans. |
||||
*/ |
||||
buf[0]='\0'; |
||||
strcat(buf,"SELECT lo "); |
||||
strcat(buf,"FROM vacuum_l"); |
||||
if(!(res = PQexec(conn,buf))) { |
||||
fprintf(stderr,"Failed to read temp table.\n"); |
||||
PQfinish(conn); |
||||
return -1; |
||||
} |
||||
matched=PQntuples(res); |
||||
for(i=0;i<matched;i++) |
||||
{ |
||||
Oid lo = (Oid) atoi(PQgetvalue(res,i,0)); |
||||
|
||||
if(verbose) { |
||||
fprintf(stdout,"\rRemoving lo %6d \n",lo); |
||||
fflush(stdout); |
||||
} |
||||
|
||||
if(lo_unlink(conn,lo)<0) { |
||||
fprintf(stderr,"Failed to remove lo %d\n",lo); |
||||
} |
||||
} |
||||
PQclear(res); |
||||
|
||||
/*
|
||||
* That's all folks! |
||||
*/ |
||||
res = PQexec(conn, "end"); |
||||
PQclear(res); |
||||
PQfinish(conn); |
||||
|
||||
if(verbose) |
||||
fprintf(stdout,"\rRemoved %d large objects from %s.\n",matched,database); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
int verbose = 0; |
||||
int arg; |
||||
int rc=0; |
||||
|
||||
if (argc < 2) |
||||
{ |
||||
fprintf(stderr, "Usage: %s [-v] database_name [db2 ... dbn]\n", |
||||
argv[0]); |
||||
exit(1); |
||||
} |
||||
|
||||
for(arg=1;arg<argc;arg++) { |
||||
if(strcmp("-v",argv[arg])==0) |
||||
verbose=!verbose; |
||||
else |
||||
rc += vacuumlo(argv[arg],verbose); |
||||
} |
||||
|
||||
return rc; |
||||
} |
Loading…
Reference in new issue