]> granicus.if.org Git - postgresql/commitdiff
Well, pg_dumplo is in attache. It is really simple program and now is not
authorBruce Momjian <bruce@momjian.us>
Mon, 12 Jun 2000 04:01:52 +0000 (04:01 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 12 Jun 2000 04:01:52 +0000 (04:01 +0000)
prepared for dirtribution (it needs a little changes). I can change and work
on this, but I need motivation :-)

And Peter, I know and I agree that standard PG tree is not good space for
all interfaces and for all tools based on PG, but LO is PG feature and we
haven't backup tool for LO.

Karel Zak

contrib/README
contrib/pg_dumplo/Makefile [new file with mode: 0644]
contrib/pg_dumplo/README [new file with mode: 0644]
contrib/pg_dumplo/VERSION [new file with mode: 0644]
contrib/pg_dumplo/pg_dumplo.c [new file with mode: 0644]

index 773b0e30c3be677a8452f64d0dbeac9beaa17ae7..7dcd1ca1fe9fefbd043fa78e350d63224cdcc5d7 100644 (file)
@@ -60,6 +60,9 @@ mSQL-interface -
 noupdate -
        trigger to prevent updates on single columns
 
+pg_dumplo -
+       Dump large objects
+
 soundex -
        Prototype for soundex function
 
diff --git a/contrib/pg_dumplo/Makefile b/contrib/pg_dumplo/Makefile
new file mode 100644 (file)
index 0000000..0d4fb83
--- /dev/null
@@ -0,0 +1,26 @@
+
+PROGRAM        = pg_dumplo
+       
+OBJECTS        = pg_dumplo.o
+
+CFLAGS         = -Wall -fpic -g
+CC     = gcc
+RM     = rm -f
+INCLUDE = -I/usr/include/postgresql
+LIBS   =-lpq
+
+COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDE)
+LINK    = $(CC) $(CFLAGS) -o $@ $(LIBS)
+
+
+all: $(PROGRAM)        
+
+$(PROGRAM): $(OBJECTS)
+       $(LINK) $(OBJECTS)
+
+.c.o: $<
+       $(COMPILE) -c $<
+
+clean:
+       $(RM) -f *~ $(OBJECTS) $(PROGRAM)
+
diff --git a/contrib/pg_dumplo/README b/contrib/pg_dumplo/README
new file mode 100644 (file)
index 0000000..b36cdd0
--- /dev/null
@@ -0,0 +1,18 @@
+
+       pg_dumplo - PostgreSQL large object dumper
+        
+
+       Hmm... documentation is not available. For more information
+       see the help ( pg_dumplo -h ) and examples in this help.
+
+       Compilation:
+                       - you need the PostgreSQL's devel. libs 
+                       - and type: 'make'
+
+                                       
+                                       Karel Zak <zakkr@zf.jcu.cz>             
+               
+                               
+
+       
+
diff --git a/contrib/pg_dumplo/VERSION b/contrib/pg_dumplo/VERSION
new file mode 100644 (file)
index 0000000..05b19b1
--- /dev/null
@@ -0,0 +1 @@
+0.0.4
\ No newline at end of file
diff --git a/contrib/pg_dumplo/pg_dumplo.c b/contrib/pg_dumplo/pg_dumplo.c
new file mode 100644 (file)
index 0000000..6e6a20b
--- /dev/null
@@ -0,0 +1,379 @@
+
+#include <stdio.h>     
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>                            
+#include <time.h>
+
+#include <libpq-fe.h>
+#include <libpq/libpq-fs.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+        
+extern int     errno;        
+        
+#define QUERY_BUFSIZ   (8*1024)
+#define DIR_UMASK      0755
+#define FILE_UMASK     0666 
+
+#define        TRUE            1
+#define FALSE          0
+#define RE_OK          0
+#define RE_ERROR       1
+
+typedef struct { 
+       char    *table,
+               *attr;
+       long    lo_oid;
+} lo_attr;
+
+void usage()
+{
+       printf("\nPostgreSQL large objects dump");
+       printf("\npg_lo_dump <option>\n\n");
+       printf("-h --help                       this help\n");  
+       printf("-u --user='username'            username for connection to server\n");  
+       printf("-p --password='password'        password for connection to server\n");  
+       printf("-d --db='database'              database name\n");      
+       printf("-t --host='hostname'            server hostname\n");            
+       printf("-l <table.attr ...>             dump attribute (columns) with LO to dump tree\n");
+       printf("-i --import                     import large obj dump tree to DB\n");
+       printf("-s --space=<dir>                directory with dupm tree (for dump/import)\n");
+       printf("\nExample (dump):   pg_lo_dump -d my_db -s /my_dump/dir/ -l t1.a t1.b t2.a\n"); 
+       printf("Example (import): pg_lo_dump -i -d my_db -s /my_dump/dir/\n");  
+       printf("\nNote:  * option '-l' must be last option!\n");        
+       printf("       * option '-i' (--import) make new large obj in DB, not rewrite old,\n"); 
+       printf("         import UPDATE oid numbers in table.attr only.\n");     
+       printf("\n\n"); 
+}
+
+typedef enum {
+       ARG_USER,
+       ARG_PWD,
+       ARG_DB,
+       ARG_HELP,
+       ARG_HOST
+} _ARG_;
+
+/*-----
+ *     Init and allocate lo_attr structs
+ *
+ *     !       data is **argv 
+ *-----
+ */
+lo_attr *init_loa(char **data, int max, int start)
+{
+       lo_attr         *l, 
+                       *ll;
+       char            **d, 
+                       *loc,
+                       buff[128];
+
+       if ((l = (lo_attr *) malloc(max * sizeof(lo_attr))) == NULL) {
+               fprintf(stderr, "%s: can't allocate memory\n", data[0]);
+               exit(RE_ERROR);
+       }
+       for(d=data+start, ll=l; *d != NULL; d++, ll++) {
+               strncpy(buff, *d, 128);
+               if ((loc = strchr(buff, '.')) == NULL) {
+                       fprintf(stderr, "%s: '%s' is bad 'table.attr'\n", data[0], buff);
+                       exit(RE_ERROR); 
+               }
+               *loc = '\0';
+               ll->table = strdup(buff);
+               ll->attr = strdup(++loc);
+       }
+       ll++;
+       ll->table = ll->attr = (char *) NULL;
+       return l;
+}
+
+/*-----
+ *     Check PG result
+ *-----
+ */
+int check_res(PGresult *res, PGconn *conn) 
+{
+       if (!res && PQresultStatus(res) != PGRES_COMMAND_OK) {
+               fprintf(stderr, "%s\n",PQerrorMessage(conn));
+                PQclear(res);
+                return FALSE;
+        }
+        if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+                fprintf(stderr, "Tuples is not OK.\n");
+                PQclear(res);
+                return FALSE;
+        }
+        return TRUE;        
+}
+
+
+/*-----
+ *     LO dump
+ *-----
+ */
+ void dump_lo(PGconn *conn, char *space, lo_attr *loa, char *db, char *prog)
+ {
+       PGresult        *res;           
+       lo_attr         *ploa;
+       FILE            *majorfile;
+       char            *dir,
+                       path[BUFSIZ],
+                       Qbuff[QUERY_BUFSIZ];
+       
+       dir = space ? space : getenv("PWD");            
+       sprintf(path, "%s/%s", dir, db); 
+       if (mkdir(path, DIR_UMASK) == -1) {
+               if (errno != EEXIST) {
+                       perror(path);
+                       exit(RE_ERROR);                                 
+               }       
+       }
+       
+       sprintf(path, "%s/lo_dump.index", path);          
+       if ((majorfile = fopen(path, "w")) == NULL) {
+               perror(path);
+               exit(RE_ERROR);
+       } else {
+               time_t  t;
+               time(&t);
+               fprintf(majorfile, "#\n# This is the PostgreSQL large object dump index\n#\n");
+               fprintf(majorfile, "#\tDate:     %s", ctime(&t));
+               fprintf(majorfile, "#\tHost:     %s\n", PQhost(conn) ? PQhost(conn) : "localhost");
+               fprintf(majorfile, "#\tDatabase: %s\n", db);
+               fprintf(majorfile, "#\tUser:     %s\n", PQuser(conn));
+               fprintf(majorfile, "#\n# oid\ttable\tattribut\tinfile\n");
+       }
+
+       for(ploa=loa; ploa->table != NULL; ploa++) {
+       
+               /* query */
+               sprintf(Qbuff, "SELECT %s FROM %s WHERE %s!=0", 
+                       ploa->attr, ploa->table, ploa->attr);
+                       
+               res = PQexec(conn, Qbuff);
+       
+               if (check_res(res, conn)) {
+                       int     tuples  = PQntuples(res),
+                               t;
+                       char    *val;
+       
+                       /* Make DIR/FILE */
+                       if (tuples) {
+                               sprintf(path, "%s/%s/%s", dir, db, ploa->table);          
+                               if (mkdir(path, DIR_UMASK) == -1) {
+                                       if (errno != EEXIST) {
+                                               perror(path);
+                                               exit(RE_ERROR);                                 
+                                       }       
+                               }
+                               sprintf(path, "%s/%s", path, ploa->attr);          
+                               if (mkdir(path, DIR_UMASK) == -1) {
+                                       if (errno != EEXIST) {
+                                               perror(path);
+                                               exit(RE_ERROR);                                 
+                                       }       
+                               }
+                               fprintf(stderr, "%s: dump %s.%s (%d lagre obj)\n", prog, 
+                                       ploa->table, ploa->attr, tuples);
+                       }
+
+                       for(t=0; t<tuples; t++) {
+                               val = PQgetvalue(res, t, 0);
+                               if (!val)
+                                       continue;
+                               
+                               sprintf(path, "%s/%s/%s/%s/%s", dir, db, ploa->table, ploa->attr, val);
+                               
+                               if (lo_export(conn, (Oid) atol(val), path) < 0) 
+                                       fprintf(stderr, "%s\n", PQerrorMessage(conn));
+                               else
+                                       fprintf(majorfile, "%s\t%s\t%s\t%s/%s/%s/%s\n", val, 
+                                               ploa->table, ploa->attr, db, ploa->table, ploa->attr, val);
+                       }
+               }
+       }       
+       fclose(majorfile);
+ }
+
+
+/*-----
+ *     LO import
+ *-----
+ */
+ void import_lo(PGconn *conn, char *space, char *db, char *prog)
+ {
+       PGresult        *res;           
+       lo_attr         loa;
+       FILE            *majorfile;
+       long            new_oid;
+       char            *dir,
+                       tab[128], attr[128],
+                       path[BUFSIZ], lo_path[BUFSIZ],
+                       Qbuff[QUERY_BUFSIZ];
+       
+       dir = space ? space : getenv("PWD");
+       sprintf(path, "%s/%s", dir, db);          
+
+       sprintf(path, "%s/lo_dump.index", path);          
+       if ((majorfile = fopen(path, "r")) == NULL) {
+               perror(path);
+               exit(RE_ERROR);
+       } 
+
+       while(fgets(Qbuff, QUERY_BUFSIZ, majorfile)) {
+               
+               if (*Qbuff == '#')
+                       continue;
+
+               fprintf(stdout, Qbuff);
+               
+               sscanf(Qbuff, "%ld\t%s\t%s\t%s\n", &loa.lo_oid, tab, attr, path); 
+               loa.table = tab;
+               loa.attr  = attr;
+
+               sprintf(lo_path, "%s/%s", dir, path); 
+                               
+               /* import large obj */
+               if ((new_oid = lo_import(conn, lo_path)) <= 0) {
+                       fprintf(stderr, "%s\n",PQerrorMessage(conn));
+                       PQexec(conn, "ROLLBACK");
+                       fprintf(stderr, "\nROLLBACK\n");
+                       exit(RE_ERROR);
+               }
+       
+               /* query */
+               sprintf(Qbuff, "UPDATE %s SET %s=%ld WHERE %s=%ld", 
+                       loa.table, loa.attr, new_oid, loa.attr, loa.lo_oid);
+
+               /*fprintf(stderr, Qbuff);*/
+                       
+               res = PQexec(conn, Qbuff);
+       
+               if (!res && PQresultStatus(res) != PGRES_COMMAND_OK) {
+                       fprintf(stderr, "%s\n",PQerrorMessage(conn));
+                       PQclear(res);
+                       PQexec(conn, "ROLLBACK");
+                       fprintf(stderr, "\nROLLBACK\n");
+                       exit(RE_ERROR);
+               }       
+               
+       }       
+       fclose(majorfile);
+ }
+
+/*-----
+ *     The mother of all C functions
+ *-----
+ */
+int main(int argc, char **argv)
+{
+       PGconn          *conn;
+       lo_attr         *loa    =NULL;
+       char            *user   =NULL, 
+                       *pwd    =NULL, 
+                       *db     =NULL,
+                       *host   =NULL,  
+                       *space  =NULL;
+       int             import  =FALSE;
+
+       /* Parse argv */
+       if (argc) {
+               int     arg, l_index=0;
+               extern int optind;
+               typedef enum {
+                       ARG_USER,
+                       ARG_PWD,
+                       ARG_DB,
+                       ARG_HELP,
+                       ARG_IMPORT,
+                       ARG_SPACE,
+                       ARG_HOST
+               } _ARG_;
+               
+               struct option l_opt[] = {
+                       { "help",       0, 0, ARG_HELP          },              
+                       { "user",       1, 0, ARG_USER          },
+                       { "pwd",        1, 0, ARG_PWD           },
+                       { "db",         1, 0, ARG_DB            },
+                       { "host",       1, 0, ARG_HOST          },
+                       { "space",      1, 0, ARG_SPACE         },
+                       { "import",     0, 0, ARG_IMPORT        },
+                       { NULL, 0, 0, 0 }
+               };      
+
+               while((arg = getopt_long(argc, argv, "hu:p:d:l:t:is:", l_opt, &l_index)) != -1) {
+                       switch(arg) {
+                       case ARG_HELP:
+                       case 'h':
+                               usage();
+                               exit(RE_OK);
+                       case ARG_USER:
+                       case 'u':       
+                               user = strdup(optarg);
+                               break;   
+                       case ARG_HOST:
+                       case 't':       
+                               host = strdup(optarg);
+                               break;          
+                       case ARG_PWD:
+                       case 'p':       
+                               pwd = strdup(optarg);
+                               break;                          
+                       case ARG_DB:
+                       case 'd':       
+                               db = strdup(optarg);
+                               break;
+                       case ARG_SPACE:
+                       case 's':       
+                               space = strdup(optarg);
+                               break;  
+                       case ARG_IMPORT:
+                       case 'i':       
+                               import = TRUE;
+                               break;  
+                       case 'l':
+                               loa = init_loa(argv, argc-1, optind-1);
+                               break;                                  
+                       }
+               }       
+       }       
+
+       if (!space && !getenv("PWD")) {
+               fprintf(stderr, "%s: can't set directory (not set '-s' or $PWD).\n", argv[0]);
+               exit(RE_ERROR);
+       }
+
+       /* Make PG connection */
+       conn = PQsetdbLogin(host, NULL, NULL, NULL, db, user, pwd);
+        
+       /* check to see that the backend connection was successfully made */
+        if (PQstatus(conn) == CONNECTION_BAD) {
+                fprintf(stderr, "%s\n",PQerrorMessage(conn));
+                exit(RE_ERROR);
+        }
+
+       PQexec(conn, "BEGIN");
+
+       if (import) {
+               /* import obj */
+               import_lo(conn, space, db, argv[0]);
+       } else if (loa) {
+               /* Dump obj */
+               dump_lo(conn, space, loa, db, argv[0]);
+       } else {
+               fprintf(stderr, "%s: ERROR: bad arg!\n", argv[0]);
+               usage();
+       }       
+
+       PQexec(conn, "COMMIT");
+       
+       /* bye PG */ 
+       PQfinish(conn); 
+       exit(RE_OK);
+}
\ No newline at end of file