aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2000-06-12 04:01:52 +0000
committerBruce Momjian <bruce@momjian.us>2000-06-12 04:01:52 +0000
commitaaf19c0e25715c2b46164798ff017d688487763b (patch)
tree4cdedb464a2960939ebe3bf21399a8b43f314002
parent36c926875aeaf13490672cc91b2e328735fb3812 (diff)
downloadpostgresql-aaf19c0e25715c2b46164798ff017d688487763b.tar.gz
postgresql-aaf19c0e25715c2b46164798ff017d688487763b.zip
Well, pg_dumplo is in attache. It is really simple program and now is not
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
-rw-r--r--contrib/README3
-rw-r--r--contrib/pg_dumplo/Makefile26
-rw-r--r--contrib/pg_dumplo/README18
-rw-r--r--contrib/pg_dumplo/VERSION1
-rw-r--r--contrib/pg_dumplo/pg_dumplo.c379
5 files changed, 427 insertions, 0 deletions
diff --git a/contrib/README b/contrib/README
index 773b0e30c3b..7dcd1ca1fe9 100644
--- a/contrib/README
+++ b/contrib/README
@@ -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
index 00000000000..0d4fb834243
--- /dev/null
+++ b/contrib/pg_dumplo/Makefile
@@ -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
index 00000000000..b36cdd01d0b
--- /dev/null
+++ b/contrib/pg_dumplo/README
@@ -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
index 00000000000..05b19b1f76e
--- /dev/null
+++ b/contrib/pg_dumplo/VERSION
@@ -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
index 00000000000..6e6a20bef55
--- /dev/null
+++ b/contrib/pg_dumplo/pg_dumplo.c
@@ -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