/* -------------------------------------------------------------------------
  * pg_dumplo
  *
- * $PostgreSQL: pgsql/contrib/pg_dumplo/lo_export.c,v 1.12 2003/11/29 19:51:35 pgsql Exp $
+ * $PostgreSQL: pgsql/contrib/pg_dumplo/lo_export.c,v 1.13 2004/11/28 23:49:49 tgl Exp $
  *
- *                 Karel Zak 1999-2000
+ * Karel Zak 1999-2004
  * -------------------------------------------------------------------------
  */
 
    LOlist     *ll;
    int         i;
    int         n;
-
+   
    /*
     * Now find any candidate tables who have columns of type oid.
     *
     * NOTE: the system oid column is ignored, as it has attnum < 1. This
     * shouldn't matter for correctness, but it saves time.
     */
-   pgLO->res = PQexec(pgLO->conn,
-                      "SELECT c.relname, a.attname "
-                      "FROM pg_class c, pg_attribute a, pg_type t "
+   pgLO->res = PQexec(pgLO->conn,     "SELECT c.relname, a.attname, n.nspname "
+                      "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a, "
+                      "     pg_catalog.pg_type t, pg_catalog.pg_namespace n "
                       "WHERE a.attnum > 0 "
                       "    AND a.attrelid = c.oid "
                       "    AND a.atttypid = t.oid "
                       "    AND t.typname = 'oid' "
                       "    AND c.relkind = 'r' "
-                      "    AND c.relname NOT LIKE 'pg_%'");
+                      "    AND c.relname NOT LIKE 'pg_%' "
+                      "    AND n.oid = c.relnamespace");
 
    if (PQresultStatus(pgLO->res) != PGRES_TUPLES_OK)
    {
    }
 
    pgLO->lolist = (LOlist *) malloc((n + 1) * sizeof(LOlist));
+   memset(pgLO->lolist, 0, (n + 1) * sizeof(LOlist));
 
    if (!pgLO->lolist)
    {
    {
        ll->lo_table = strdup(PQgetvalue(pgLO->res, i, 0));
        ll->lo_attr = strdup(PQgetvalue(pgLO->res, i, 1));
+       ll->lo_schema = strdup(PQgetvalue(pgLO->res, i, 2));
    }
-   ll->lo_table = ll->lo_attr = (char *) NULL;
 
    PQclear(pgLO->res);
 }
        fprintf(pgLO->index, "#\tHost:     %s\n", pgLO->host);
        fprintf(pgLO->index, "#\tDatabase: %s\n", pgLO->db);
        fprintf(pgLO->index, "#\tUser:     %s\n", pgLO->user);
-       fprintf(pgLO->index, "#\n# oid\ttable\tattribut\tinfile\n#\n");
+       fprintf(pgLO->index, "#\n# oid\ttable\tattribut\tinfile\tschema\n#\n");
    }
 
    pgLO->counter = 0;
         * Query: find the LOs referenced by this column
         */
        snprintf(Qbuff, QUERY_BUFSIZ,
-                "SELECT DISTINCT l.loid FROM \"%s\" x, pg_largeobject l WHERE x.\"%s\" = l.loid",
-                ll->lo_table, ll->lo_attr);
+                "SELECT DISTINCT l.loid FROM \"%s\".\"%s\" x, pg_catalog.pg_largeobject l "
+                "WHERE x.\"%s\" = l.loid",
+                ll->lo_schema, ll->lo_table, ll->lo_attr);
 
        /* puts(Qbuff); */
 
        else if ((tuples = PQntuples(pgLO->res)) == 0)
        {
            if (!pgLO->quiet && pgLO->action == ACTION_EXPORT_ATTR)
-               printf("%s: no large objects in \"%s\".\"%s\"\n",
-                      progname, ll->lo_table, ll->lo_attr);
+               printf("%s: no large objects in \"%s\".\"%s\".\"%s\"\n",
+                      progname, ll->lo_schema, ll->lo_table, ll->lo_attr);
        }
        else
        {
            {
 
                snprintf(path, BUFSIZ, "%s/%s/%s", pgLO->space, pgLO->db,
-                        ll->lo_table);
+                        ll->lo_schema);
 
                if (mkdir(path, DIR_UMASK) == -1)
                {
                        exit(RE_ERROR);
                    }
                }
-
+               
                snprintf(path, BUFSIZ, "%s/%s/%s/%s", pgLO->space, pgLO->db,
-                        ll->lo_table, ll->lo_attr);
+                        ll->lo_schema, ll->lo_table);
+
+               if (mkdir(path, DIR_UMASK) == -1)
+               {
+                   if (errno != EEXIST)
+                   {
+                       perror(path);
+                       exit(RE_ERROR);
+                   }
+               }
+
+               snprintf(path, BUFSIZ, "%s/%s/%s/%s/%s", pgLO->space, pgLO->db,
+                        ll->lo_schema, ll->lo_table, ll->lo_attr);
 
                if (mkdir(path, DIR_UMASK) == -1)
                {
                }
 
                if (!pgLO->quiet)
-                   printf("dump %s.%s (%d large obj)\n",
-                          ll->lo_table, ll->lo_attr, tuples);
+                   printf("dump %s.%s.%s (%d large obj)\n",
+                          ll->lo_schema, ll->lo_table, ll->lo_attr, tuples);
            }
 
            pgLO->counter += tuples;
 
                if (pgLO->action == ACTION_SHOW)
                {
-                   printf("%s.%s: %u\n", ll->lo_table, ll->lo_attr, lo);
+                   printf("%s.%s.%s: %u\n", ll->lo_schema, ll->lo_table, ll->lo_attr, lo);
                    continue;
                }
 
-               snprintf(path, BUFSIZ, "%s/%s/%s/%s/%s", pgLO->space,
-                        pgLO->db, ll->lo_table, ll->lo_attr, val);
+               snprintf(path, BUFSIZ, "%s/%s/%s/%s/%s/%s", pgLO->space,
+                        pgLO->db, ll->lo_schema, ll->lo_table, ll->lo_attr, val);
 
                if (lo_export(pgLO->conn, lo, path) < 0)
                    fprintf(stderr, "%s: lo_export failed:\n%s", progname,
                            PQerrorMessage(pgLO->conn));
 
                else
-                   fprintf(pgLO->index, "%s\t%s\t%s\t%s/%s/%s/%s\n", val,
-                           ll->lo_table, ll->lo_attr, pgLO->db, ll->lo_table, ll->lo_attr, val);
+                   fprintf(pgLO->index, "%s\t%s\t%s\t%s/%s/%s/%s/%s\t%s\n", 
+                           val, ll->lo_table, ll->lo_attr, pgLO->db, 
+                           ll->lo_schema, ll->lo_table, ll->lo_attr, 
+                           val, ll->lo_schema);
            }
        }
 
 
 /* -------------------------------------------------------------------------
  * pg_dumplo
  *
- * $PostgreSQL: pgsql/contrib/pg_dumplo/lo_import.c,v 1.10 2003/11/29 19:51:35 pgsql Exp $
+ * $PostgreSQL: pgsql/contrib/pg_dumplo/lo_import.c,v 1.11 2004/11/28 23:49:49 tgl Exp $
  *
- *                 Karel Zak 1999-2000
+ * Karel Zak 1999-2004
  * -------------------------------------------------------------------------
  */
 
 {
    LOlist      loa;
    Oid         new_oid;
+   int     ret, line=0;
    char        tab[MAX_TABLE_NAME],
                attr[MAX_ATTR_NAME],
+               sch[MAX_SCHEMA_NAME],
                path[BUFSIZ],
                lo_path[BUFSIZ],
                Qbuff[QUERY_BUFSIZ];
 
    while (fgets(Qbuff, QUERY_BUFSIZ, pgLO->index))
    {
-
+       line++;
+       
        if (*Qbuff == '#')
            continue;
 
        if (!pgLO->remove && !pgLO->quiet)
            printf(Qbuff);
 
-       sscanf(Qbuff, "%u\t%s\t%s\t%s\n", &loa.lo_oid, tab, attr, path);
+       if ((ret=sscanf(Qbuff, "%u\t%s\t%s\t%s\t%s\n", &loa.lo_oid, tab, attr, path, sch)) < 5)
+       {
+           /* backward compatible mode */
+           ret = sscanf(Qbuff, "%u\t%s\t%s\t%s\n", &loa.lo_oid, tab, attr, path);
+           strcpy(sch, "public");
+       }
+       if (ret < 4)
+       {
+           fprintf(stderr, "%s: index file reading failed at line %d\n", progname, line);
+           PQexec(pgLO->conn, "ROLLBACK");
+           fprintf(stderr, "\n%s: ROLLBACK\n", progname);
+           exit(RE_ERROR);
+       }
+       
+       loa.lo_schema = sch;
        loa.lo_table = tab;
        loa.lo_attr = attr;
 
-       snprintf(lo_path, BUFSIZ, "%s/%s", pgLO->space, path);
+       if (path && *path=='/')
+           /* absolute path */
+           snprintf(lo_path, BUFSIZ, "%s", path);
+       else
+           snprintf(lo_path, BUFSIZ, "%s/%s", pgLO->space, path);
 
        /*
         * Import LO
         * UPDATE oid in tab
         */
        snprintf(Qbuff, QUERY_BUFSIZ,
-                "UPDATE \"%s\" SET \"%s\"=%u WHERE \"%s\"=%u",
-           loa.lo_table, loa.lo_attr, new_oid, loa.lo_attr, loa.lo_oid);
+                "UPDATE \"%s\".\"%s\" SET \"%s\"=%u WHERE \"%s\"=%u",
+           loa.lo_schema, loa.lo_table, loa.lo_attr, new_oid, loa.lo_attr, loa.lo_oid);
 
-       /* fprintf(stderr, Qbuff); */
+       /*fprintf(stderr, Qbuff);*/
 
        pgLO->res = PQexec(pgLO->conn, Qbuff);
 
 
 /* -------------------------------------------------------------------------
  * pg_dumplo
  *
- * $PostgreSQL: pgsql/contrib/pg_dumplo/main.c,v 1.21 2004/11/27 18:51:04 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pg_dumplo/main.c,v 1.22 2004/11/28 23:49:49 tgl Exp $
  *
  *                 Karel Zak 1999-2000
  * -------------------------------------------------------------------------
    /*
     * Check space
     */
-   if (!pgLO->space && !pgLO->action == ACTION_SHOW)
+   if (pgLO->space==NULL && pgLO->action != ACTION_SHOW)
    {
        if (!(pgLO->space = getenv("PWD")))
-       {
-           fprintf(stderr, "%s: not set space for dump-tree (option '-s' or $PWD).\n", progname);
-           exit(RE_ERROR);
-       }
+           pgLO->space = ".";
    }
 
    if (!pgLO->action)
 parse_lolist(LODumpMaster * pgLO)
 {
    LOlist     *ll;
-   char      **d,
-              *loc,
-               buff[MAX_TABLE_NAME + MAX_ATTR_NAME + 1];
+   char      **d, *loc, *loc2, 
+         buff[MAX_SCHEMA_NAME + MAX_TABLE_NAME + MAX_ATTR_NAME + 3];
 
    pgLO->lolist = (LOlist *) malloc(pgLO->argc * sizeof(LOlist));
 
         d++, ll++)
    {
 
-       strncpy(buff, *d, MAX_TABLE_NAME + MAX_ATTR_NAME);
+       strncpy(buff, *d, MAX_SCHEMA_NAME + MAX_TABLE_NAME + MAX_ATTR_NAME + 2);
 
-       if ((loc = strchr(buff, '.')) == NULL)
+       if ((loc = strchr(buff, '.')) == NULL || *(loc+1)=='\0')
        {
-           fprintf(stderr, "%s: '%s' is bad 'table.attr'\n", progname, buff);
+           fprintf(stderr, "%s: '%s' is bad 'table.attr' or 'schema.table.attr'\n", progname, buff);
            exit(RE_ERROR);
        }
+       loc2 = strchr(loc+1, '.');
        *loc = '\0';
-       ll->lo_table = strdup(buff);
-       ll->lo_attr = strdup(++loc);
+       
+       if (loc2)
+       {
+           /* "schema.table.attr" 
+            */
+           *loc2 = '\0';
+           ll->lo_schema = strdup(buff);
+           ll->lo_table = strdup(loc+1);
+           ll->lo_attr = strdup(loc2+1);
+       }
+       else
+       {
+           ll->lo_schema = strdup("public");
+           ll->lo_table = strdup(buff);
+           ll->lo_attr = strdup(loc+1);
+       }
    }
    ll++;
    ll->lo_table = ll->lo_attr = (char *) NULL;
         "-s --space=<dir>             directory with dump tree (for export/import)\n"
         "-i --import                  import large obj dump tree to DB\n"
    "-e --export                  export (dump) large obj to dump tree\n"
-        "-l <table.attr ...>          dump attribute (columns) with LO to dump tree\n"
+       "-l <schema.table.attr ...>   dump attribute (columns) with LO to dump tree\n"
         "-a --all                     dump all LO in DB (default)\n"
         "-r --remove                  if is set '-i' try remove old LO\n"
         "-q --quiet                   run quietly\n"
         "Example (import): pg_dumplo -i -d my_db -s /my_dump/dir\n"
         "Example (show):   pg_dumplo -w -d my_db\n\n"
         "Note:  * option '-l' must be last option!\n"
-   "       * option '-i' without option '-r' make new large obj in DB\n"
+        "       * default schema is \"public\"\n"
+        "       * option '-i' without option '-r' make new large obj in DB\n"
         "         not rewrite old, the '-i' UPDATE oid numbers in table.attr only!\n"
-        "       * if option -s is not set, pg_dumplo uses $PWD\n"
+        "       * if option -s is not set, pg_dumplo uses $PWD or \".\"\n"
        );                      /* puts() */
 }