- Check ntuples == 1 for various SELECT statements.
authorPhilip Warner <pjw@rhyme.com.au>
Fri, 12 Jan 2001 04:32:07 +0000 (04:32 +0000)
committerPhilip Warner <pjw@rhyme.com.au>
Fri, 12 Jan 2001 04:32:07 +0000 (04:32 +0000)
- Fix handling of --tables=* (multiple tables never worked properly, AFAICT)
- strdup() the current user in DB routines
- Check results of IO routines more carefully.
- Check results of PQ routines more carefully.

Have not fixed index output yet.

src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_backup_archiver.h
src/bin/pg_dump/pg_backup_custom.c
src/bin/pg_dump/pg_backup_db.c
src/bin/pg_dump/pg_backup_files.c
src/bin/pg_dump/pg_backup_null.c
src/bin/pg_dump/pg_backup_tar.c
src/bin/pg_dump/pg_dump.c

index 7f2bfe3261c9ab7654dd1d08d96acbe2ca87edcb..afbdcadb0a2e458835bb65229d641797df3401aa 100644 (file)
  * Modifications - 30-Oct-2000 - pjw@rhyme.com.au
  *     Added {Start,End}RestoreBlobs to allow extended TX during BLOB restore.
  *
+ * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
+ *   - strdup() the current user just in case it's deallocated from it's TOC
+ *      entry. Should *never* happen, but that's what they said about the 
+ *      Titanic...
+ *
+ *   - Check results of IO routines more carefully.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -99,14 +106,18 @@ Archive* OpenArchive(const char* FileSpec, const ArchiveFormat fmt)
 /* Public */
 void   CloseArchive(Archive* AHX)
 {
+   int                 res = 0;
     ArchiveHandle*      AH = (ArchiveHandle*)AHX;
     (*AH->ClosePtr)(AH);
 
     /* Close the output */
     if (AH->gzOut)
-       GZCLOSE(AH->OF);
+       res = GZCLOSE(AH->OF);
     else if (AH->OF != stdout)
-       fclose(AH->OF);
+       res = fclose(AH->OF);
+
+   if (res != 0)
+       die_horribly(AH, "%s: could not close the output file in CloseArchive\n", progname);
 }
 
 /* Public */
@@ -791,8 +802,8 @@ void SortTocFromFile(Archive* AHX, RestoreOptions *ropt)
 
     /* Setup the file */
     fh = fopen(ropt->tocFile, PG_BINARY_R);
-    if (!fh)
-   die_horribly(AH, "%s: could not open TOC file\n", progname);
+   if (!fh)
+       die_horribly(AH, "%s: could not open TOC file\n", progname);
 
     while (fgets(buf, 1024, fh) != NULL)
     {
@@ -828,7 +839,8 @@ void SortTocFromFile(Archive* AHX, RestoreOptions *ropt)
    tePrev = te;
     }
 
-    fclose(fh);
+    if (fclose(fh) != 0)
+       die_horribly(AH, "%s: could not close TOC file\n", progname);
 }
 
 /**********************
@@ -906,34 +918,42 @@ OutputContext SetOutput(ArchiveHandle* AH, char *filename, int compression)
 #ifdef HAVE_LIBZ
     if (compression != 0)
     {
-   sprintf(fmode, "wb%d", compression);
-   if (fn) {
-       AH->OF = gzdopen(dup(fn), fmode); /* Don't use PG_BINARY_x since this is zlib */
-   } else {
-       AH->OF = gzopen(filename, fmode);
-   }
-   AH->gzOut = 1;
+       sprintf(fmode, "wb%d", compression);
+       if (fn) {
+           AH->OF = gzdopen(dup(fn), fmode); /* Don't use PG_BINARY_x since this is zlib */
+       } else {
+           AH->OF = gzopen(filename, fmode);
+       }
+       AH->gzOut = 1;
     } else { /* Use fopen */
 #endif
-   if (fn) {
-       AH->OF = fdopen(dup(fn), PG_BINARY_W);
-   } else {
-       AH->OF = fopen(filename, PG_BINARY_W);
-   }
-   AH->gzOut = 0;
+       if (fn) {
+           AH->OF = fdopen(dup(fn), PG_BINARY_W);
+       } else {
+           AH->OF = fopen(filename, PG_BINARY_W);
+       }
+       AH->gzOut = 0;
 #ifdef HAVE_LIBZ
     }
 #endif
 
+   if (!AH->OF)
+       die_horribly(AH, "%s: could not set output\n", progname);
+
     return sav;
 }
 
 void ResetOutput(ArchiveHandle* AH, OutputContext sav)
 {
+   int             res;
+
     if (AH->gzOut)
-   GZCLOSE(AH->OF);
+       res = GZCLOSE(AH->OF);
     else
-   fclose(AH->OF);
+       res = fclose(AH->OF);
+
+   if (res != 0)
+       die_horribly(AH, "%s: could not reset the output file\n", progname);
 
     AH->gzOut = sav.gzOut;
     AH->OF = sav.OF;
@@ -1012,9 +1032,19 @@ int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle* AH)
        return res;
    }
     else if (AH->gzOut)
-       return GZWRITE((void*)ptr, size, nmemb, AH->OF);
+   {
+       res = GZWRITE((void*)ptr, size, nmemb, AH->OF);
+       if (res != (nmemb * size))
+           die_horribly(AH, "%s: could not write to archive\n", progname);
+       return res;
+   }
     else if (AH->CustomOutPtr)
-       return AH->CustomOutPtr(AH, ptr, size * nmemb);
+   {
+       res = AH->CustomOutPtr(AH, ptr, size * nmemb);
+       if (res != (nmemb * size))
+           die_horribly(AH, "%s: could not write to custom output routine\n", progname);
+       return res;
+   }
    else
    {
        /*
@@ -1022,9 +1052,14 @@ int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle* AH)
         * then send it to the DB.
         */ 
        if (RestoringToDB(AH))
-           return ExecuteSqlCommandBuf(AH, (void*)ptr, size*nmemb);
+           return ExecuteSqlCommandBuf(AH, (void*)ptr, size*nmemb); /* Always 1, currently */
        else
-           return fwrite((void*)ptr, size, nmemb, AH->OF);
+       {
+           res = fwrite((void*)ptr, size, nmemb, AH->OF);
+           if (res != nmemb)
+               die_horribly(AH, "%s: could not write to output file (%d != %d)\n", progname, res, nmemb);
+           return res;
+       }
    }
 }      
 
@@ -1299,7 +1334,8 @@ _discoverArchiveFormat(ArchiveHandle* AH)
 
     /* Close the file */
     if (wantClose)
-       fclose(fh);
+       if (fclose(fh) != 0)
+           die_horribly(AH, "%s: could not close the input file after reading header\n", progname);
 
     return AH->format;
 }
@@ -1342,7 +1378,7 @@ static ArchiveHandle* _allocAH(const char* FileSpec, const ArchiveFormat fmt,
        AH->fSpec = NULL;
     } 
 
-    AH->currUser = "";
+    AH->currUser = strdup(""); /* So it's valid, but we can free() it later if necessary */ 
 
     AH->toc = (TocEntry*)calloc(1, sizeof(TocEntry));
     if (!AH->toc)
@@ -1455,7 +1491,7 @@ void WriteToc(ArchiveHandle* AH)
    if (AH->WriteExtraTocPtr) {
        (*AH->WriteExtraTocPtr)(AH, te);
    }
-   te = te->next;
+       te = te->next;
     }
 }
 
@@ -1585,7 +1621,12 @@ static void _reconnectAsUser(ArchiveHandle* AH, const char *dbname, char *user)
        {
            ahprintf(AH, "\\connect %s %s\n", dbname, user);
        }
-       AH->currUser = user;
+       if (AH->currUser) 
+       {
+           free(AH->currUser);
+       }
+
+       AH->currUser = strdup(user);
     } 
 }
 
index 2c7291e6c6917f678c6711c2ecac34c532546412..9a9c2e78a84a42b000a0ab37bb8e34ddf23b0ae7 100644 (file)
@@ -44,7 +44,7 @@
 #define GZREAD(p, s, n, fh) gzread(fh, p, n * s)
 #else
 #define GZCLOSE(fh) fclose(fh)
-#define GZWRITE(p, s, n, fh) fwrite(p, s, n, fh)
+#define GZWRITE(p, s, n, fh) (fwrite(p, s, n, fh) * s)
 #define GZREAD(p, s, n, fh) fread(p, s, n, fh)
 #define Z_DEFAULT_COMPRESSION -1
 
@@ -62,7 +62,7 @@ typedef z_stream *z_streamp;
 
 #define K_VERS_MAJOR 1
 #define K_VERS_MINOR 4 
-#define K_VERS_REV 22 
+#define K_VERS_REV 23 
 
 /* Data block types */
 #define BLK_DATA 1
index e44f02259c00e572ddbc5da2dd66d83779075e04..62562577817f7668256ce56e8b812874716582fb 100644 (file)
  *
  * Initial version. 
  *
+ * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
+ *
+ *    - Check results of IO routines more carefully.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -164,7 +168,7 @@ void InitArchiveFmt_Custom(ArchiveHandle* AH)
            AH->FH = stdout;
        }
 
-       if (!AH)
+       if (!AH->FH)
            die_horribly(AH, "%s: unable to open archive file %s",progname, AH->fSpec);
 
        ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
@@ -176,7 +180,7 @@ void InitArchiveFmt_Custom(ArchiveHandle* AH)
        } else {
            AH->FH = stdin;
        }
-       if (!AH)
+       if (!AH->FH)
            die_horribly(AH, "%s: unable to open archive file %s",progname, AH->fSpec);
 
        ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
@@ -666,6 +670,8 @@ static int  _WriteByte(ArchiveHandle* AH, const int i)
     res = fputc(i, AH->FH);
     if (res != EOF) {
        ctx->filePos += 1;
+   } else {
+       die_horribly(AH, "%s: could not write byte./n",progname);
     }
     return res;
 }
@@ -705,6 +711,10 @@ static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len)
     lclContext*        ctx = (lclContext*)AH->formatData;
     int            res;
     res = fwrite(buf, 1, len, AH->FH);
+
+   if (res != len)
+       die_horribly(AH, "%s: write error in _WriteBuf (%d != %d)\n", progname, res, len);
+
     ctx->filePos += res;
     return res;
 }
@@ -764,7 +774,9 @@ static void _CloseArchive(ArchiveHandle* AH)
        }
     }
 
-    fclose(AH->FH);
+    if (fclose(AH->FH) != 0)
+       die_horribly(AH, "%s: could not close archive file\n",progname);
+
     AH->FH = NULL; 
 }
 
@@ -873,7 +885,8 @@ static int  _DoDeflate(ArchiveHandle* AH, lclContext* ctx, int flush)
            if (zp->avail_out < zlibOutSize) {
                /* printf("Wrote %d byte deflated chunk\n", zlibOutSize - zp->avail_out); */
                WriteInt(AH, zlibOutSize - zp->avail_out);
-               fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH);
+               if (fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH) != (zlibOutSize - zp->avail_out))
+                   die_horribly(AH, "%s: could write compressed chunk\n",progname);
                ctx->filePos += zlibOutSize - zp->avail_out;
            }
            zp->next_out = out;
@@ -884,7 +897,8 @@ static int  _DoDeflate(ArchiveHandle* AH, lclContext* ctx, int flush)
        if (zp->avail_in > 0)
        {
            WriteInt(AH, zp->avail_in);
-           fwrite(zp->next_in, 1, zp->avail_in, AH->FH);
+           if (fwrite(zp->next_in, 1, zp->avail_in, AH->FH) != zp->avail_in)
+               die_horribly(AH, "%s: could write uncompressed chunk\n", progname);
            ctx->filePos += zp->avail_in;
            zp->avail_in = 0;
        } else {
index d84e25e30949b66fab018442c7b72d4facc229b4..763d94fa80a4c3d1e158b57dc3a829aa2fe6a2d4 100644 (file)
@@ -1,5 +1,14 @@
 /*-------------------------------------------------------------------------
  *
+ * pg_backup_db.c
+ *
+ *  Implements the basic DB functions used by the archiver.
+ *
+ * IDENTIFICATION
+ *
+ * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
+ *
+ *    - Check results of PQ routines more carefully.
  *
  *-------------------------------------------------------------------------
  */
@@ -449,14 +458,17 @@ int ExecuteSqlCommandBuf(ArchiveHandle* AH, void *qryv, int bufLen)
 
                /* fprintf(stderr, "Sending '%s' via COPY (at end = %d)\n\n", AH->pgCopyBuf->data, isEnd); */ 
                
-               PQputline(AH->connection, AH->pgCopyBuf->data);
+               if (PQputline(AH->connection, AH->pgCopyBuf->data) != 0)
+                   die_horribly(AH, "%s: error returned by PQputline\n", progname);
 
                resetPQExpBuffer(AH->pgCopyBuf);
 
                /* fprintf(stderr, "Buffer is '%s'\n", AH->pgCopyBuf->data); */
 
                if(isEnd) {
-                   PQendcopy(AH->connection);
+                   if (PQendcopy(AH->connection) != 0)
+                       die_horribly(AH, "%s: error returned by PQendcopy\n", progname);
+
                    AH->pgCopyIn = 0;
                    break;
                }
index 1624bf14355a791fa02a53c57e13caff09df5c60..22c5d17dc4d753c30f306c674ebdc8e571d655ca 100644 (file)
  *
  * Initial version. 
  *
+ * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
+ *
+ *    - Check results of IO routines more carefully.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -123,6 +127,10 @@ void InitArchiveFmt_Files(ArchiveHandle* AH)
        } else {
            AH->FH = stdout;
        }
+
+       if (AH->FH == NULL)
+           die_horribly(NULL, "%s: Could not open output file\n", progname);
+
        ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
 
        if (AH->compression < 0 || AH->compression > 9) {
@@ -137,6 +145,10 @@ void InitArchiveFmt_Files(ArchiveHandle* AH)
        } else {
            AH->FH = stdin;
        }
+
+       if (AH->FH == NULL)
+           die_horribly(NULL, "%s: Could not open input file\n", progname);
+
        ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
 
        ReadHead(AH);
@@ -221,6 +233,10 @@ static void    _StartData(ArchiveHandle* AH, TocEntry* te)
 #else
     tctx->FH = fopen(tctx->filename, PG_BINARY_W);
 #endif
+
+   if (tctx->FH == NULL)
+       die_horribly(AH, "%s: Could not open data file for output\n", progname);
+
 }
 
 static int _WriteData(ArchiveHandle* AH, const void* data, int dLen)
@@ -258,6 +274,9 @@ static void _PrintFileData(ArchiveHandle* AH, char *filename, RestoreOptions *ro
     AH->FH = fopen(filename,PG_BINARY_R);
 #endif
 
+   if (AH->FH == NULL)
+       die_horribly(AH, "%s: Could not open data file for input\n", progname);
+
     while ( (cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0) {
        buf[cnt] = '\0';
        ahwrite(buf, 1, cnt, AH);
@@ -322,6 +341,9 @@ static void _LoadBlobs(ArchiveHandle* AH, RestoreOptions *ropt)
 
    ctx->blobToc = fopen("blobs.toc", PG_BINARY_R);
 
+   if (ctx->blobToc == NULL) 
+       die_horribly(AH, "%s: Could not open BLOB TOC for input\n", progname);
+
    _getBlobTocEntry(AH, &oid, fname);
 
     while(oid != 0)
@@ -341,13 +363,13 @@ static void   _LoadBlobs(ArchiveHandle* AH, RestoreOptions *ropt)
 static int _WriteByte(ArchiveHandle* AH, const int i)
 {
     lclContext*        ctx = (lclContext*)AH->formatData;
-    int            res;
 
-    res = fputc(i, AH->FH);
-    if (res != EOF) {
-       ctx->filePos += 1;
-    }
-    return res;
+    if (fputc(i, AH->FH) == EOF)
+       die_horribly(AH, "%s: could not write byte\n", progname);
+
+   ctx->filePos += 1;
+
+    return 1;
 }
 
 static int     _ReadByte(ArchiveHandle* AH)
@@ -367,6 +389,9 @@ static int  _WriteBuf(ArchiveHandle* AH, const void* buf, int len)
     lclContext*        ctx = (lclContext*)AH->formatData;
     int            res;
     res = fwrite(buf, 1, len, AH->FH);
+   if (res != len)
+       die_horribly(AH, "%s: write error in _WriteBuf (%d != %d)\n", progname, res, len);
+
     ctx->filePos += res;
     return res;
 }
@@ -416,7 +441,10 @@ static void    _StartBlobs(ArchiveHandle* AH, TocEntry* te)
 
    sprintf(fname, "blobs.toc");
    ctx->blobToc = fopen(fname, PG_BINARY_W);
+
+   if (ctx->blobToc == NULL)
+       die_horribly(AH, "%s: could not open BLOB TOC for output\n", progname);
+
 }
 
 /*
@@ -453,6 +481,8 @@ static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid)
     tctx->FH = fopen(fname, PG_BINARY_W);
 #endif
 
+   if (tctx->FH == NULL)
+       die_horribly(AH, "%s: Could not open BLOB file\n", progname);
 }
 
 /*
index e6f81bb31f259361eff2de156e2e7ddd63e71455..26c30bd8ec8c29e0933bd3558666fe76778022a3 100644 (file)
  *
  * Initial version. 
  *
+ * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
+ *
+ *    - Check results of IO routines more carefully.
+ *
+ *
  *-------------------------------------------------------------------------
  */
 
index 8e16899b9a7d359152228a2369027e846465ee03..d9adffb17337dc6cf9fbda7e05f124c17b9b4d7e 100644 (file)
  *
  * Initial version. 
  *
+ * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
+ *
+ *    - Check results of IO routines more carefully.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -156,6 +160,10 @@ void InitArchiveFmt_Tar(ArchiveHandle* AH)
        } else {
            ctx->tarFH = stdout;
        }
+
+       if (ctx->tarFH == NULL) 
+           die_horribly(NULL, "%s: Could not open TOC file for output.\n", progname);
+
        ctx->tarFHpos = 0;
 
        /* Make unbuffered since we will dup() it, and the buffers screw each other */
@@ -185,6 +193,9 @@ void InitArchiveFmt_Tar(ArchiveHandle* AH)
            ctx->tarFH = stdin;
        }
 
+       if (ctx->tarFH == NULL)
+           die_horribly(NULL, "%s: Could not open TOC file for input\n", progname);
+
        /* Make unbuffered since we will dup() it, and the buffers screw each other */
        /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
 
@@ -311,12 +322,18 @@ static TAR_MEMBER* tarOpen(ArchiveHandle *AH, const char *filename, char mode)
 
        tm->tmpFH = tmpfile();
 
+       if (tm->tmpFH == NULL) 
+           die_horribly(AH, "%s: could not generate temp file name.\n", progname);
+
 #ifdef HAVE_LIBZ
 
        if (AH->compression != 0)
        {
            sprintf(fmode, "wb%d", AH->compression);
            tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
+           if (tm->zFH == NULL)
+               die_horribly(AH, "%s: could not gzdopen temp file.\n", progname);
+
        } else 
            tm->nFH = tm->tmpFH;
 
@@ -343,7 +360,8 @@ static void tarClose(ArchiveHandle *AH, TAR_MEMBER* th)
     * Close the GZ file since we dup'd. This will flush the buffers.
     */
    if (AH->compression != 0)
-       GZCLOSE(th->zFH);
+       if (GZCLOSE(th->zFH) != 0)
+           die_horribly(AH, "%s: could not close tar member\n", progname);
 
    if (th->mode == 'w')
        _tarAddFile(AH, th); /* This will close the temp file */
@@ -477,6 +495,9 @@ static int tarWrite(const void *buf, int len, TAR_MEMBER *th)
    else
        res = fwrite(buf, 1, len, th->nFH);
 
+   if (res != len)
+       die_horribly(th->AH, "%s: could not write to tar member (%d != %d)\n", progname, res, len);
+
    th->pos += res;
    return res;
 }
@@ -485,9 +506,7 @@ static int  _WriteData(ArchiveHandle* AH, const void* data, int dLen)
 {
     lclTocEntry*   tctx = (lclTocEntry*)AH->currToc->formatData;
 
-   tarWrite((void*)data, dLen, tctx->TH);
-
-    /* GZWRITE((void*)data, 1, dLen, tctx->TH->FH); */
+   dLen = tarWrite((void*)data, dLen, tctx->TH);
 
     return dLen;
 }
@@ -767,7 +786,8 @@ static void _CloseArchive(ArchiveHandle* AH)
        /* Add a block of NULLs since it's de-rigeur. */
        for(i=0; i<512; i++) 
        {
-           fputc(0, ctx->tarFH);
+           if (fputc(0, ctx->tarFH) == EOF)
+               die_horribly(AH, "%s: could not write null block at end of TAR archive.\n", progname);
        }
 
     }
@@ -928,6 +948,7 @@ static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER* th)
    char        buf[32768];
    int         cnt;
    int         len = 0;
+   int         res;
    int         i, pad;
 
    /*
@@ -941,19 +962,25 @@ static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER* th)
 
    while ( (cnt = fread(&buf[0], 1, 32767, tmp)) > 0)
    {
-       fwrite(&buf[0], 1, cnt, th->tarFH);
-       len += cnt;
+       res = fwrite(&buf[0], 1, cnt, th->tarFH);
+       if (res != cnt) 
+           die_horribly(AH, "%s: write error appending to TAR archive (%d != %d).\n", progname, res, cnt);
+       len += res;
    }
 
-   fclose(tmp); /* This *should* delete it... */
+   if (fclose(tmp) != 0) /* This *should* delete it... */
+       die_horribly(AH, "%s: Could not close tar member (fclose failed).\n", progname);
 
    if (len != th->fileLen)
-       die_horribly(AH, "%s: Actual file length does not match expected (%d vs. %d)\n",
+       die_horribly(AH, "%s: Actual file length does not match expected (%d vs. %d).\n",
                        progname, len, th->pos);
 
    pad = ((len + 511) & ~511) - len;
     for (i=0 ; i < pad ; i++)
-       fputc('\0',th->tarFH);  
+   {
+       if (fputc('\0',th->tarFH) == EOF) 
+           die_horribly(AH, "%s: Could not output padding at end of tar member.\n", progname);
+   }   
 
    ctx->tarFHpos += len + pad;
 }
@@ -1131,5 +1158,8 @@ static void _tarWriteHeader(TAR_MEMBER* th)
        lastSum = sum;
    }
 
-   fwrite(h, 1, 512, th->tarFH);
+   if (fwrite(h, 1, 512, th->tarFH) != 512) {
+       die_horribly(th->AH, "%s: unable to write tar header\n", progname);
+   }
+
 }
index 69bd866eff736d46efbafaf3f97322c38d2bca15..ba10354b6d656d5ad0c9a1f2e642622e69beb41b 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.185 2001/01/06 20:57:26 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.186 2001/01/12 04:32:07 pjw Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
  *     table with the currently implementation, and (b) it's not clear how to restore
  *     a partial BLOB backup (given the current OID-based BLOB implementation).
  *
+ * Modifications - 04-Jan-2000 - pjw@rhyme.com.au
+ *
+ *   - Check ntuples == 1 for various SELECT statements.
+ *   - Fix handling of --tables=* (multiple tables never worked properly, AFAICT)
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -213,7 +218,7 @@ help(const char *progname)
        "  -s, --schema-only        dump out only the schema, no data\n"
        "  -S, --superuser=NAME     specify the superuser user name to use in plain\n"
        "                           text format\n"
-       "  -t, --table=TABLE        dump for this table only\n"
+       "  -t, --table=TABLE        dump for this table only (* for all)\n"
        "  -u, --password           use password authentication\n"
        "  -v, --verbose            verbose\n"
        "  -x, --no-acl             do not dump ACL's (grant/revoke)\n"
@@ -242,7 +247,7 @@ help(const char *progname)
        "  -s                       dump out only the schema, no data\n"
        "  -S NAME                  specify the superuser user name to use in plain\n"
        "                           text format\n"
-       "  -t TABLE                 dump for this table only\n"
+       "  -t TABLE                 dump for this table only (* for all)\n"
        "  -u                       use password authentication\n"
        "  -v                       verbose\n"
        "  -x                       do not dump ACL's (grant/revoke)\n"
@@ -562,7 +567,7 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
    char            copyBuf[512];
    char            *copyStmt;
 
-   if (onlytable == NULL)
+   if (onlytable == NULL || (strlen(onlytable) == 0) )
        all_only = "all";
    else
        all_only = "only";
@@ -576,8 +581,9 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
    if (g_verbose)
        fprintf(stderr, "%s preparing to dump out the contents of %s %d table%s/sequence%s %s\n",
                g_comment_start, all_only,
-               (onlytable == NULL) ? numTables : 1,
-         (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
+               (onlytable == NULL || (strlen(onlytable) == 0)) ? numTables : 1,
+               (onlytable == NULL || (strlen(onlytable) == 0)) ? "s" : "", 
+               (onlytable == NULL || (strlen(onlytable) == 0)) ? "s" : "",
                g_comment_end);
 
    /* Dump SEQUENCEs first (if dataOnly) */
@@ -587,7 +593,7 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
        {
            if (!(tblinfo[i].sequence))
                continue;
-           if (!onlytable || (!strcmp(tblinfo[i].relname, onlytable)))
+           if (!onlytable || (strcmp(tblinfo[i].relname, onlytable) == 0) || (strlen(onlytable) == 0) )
            {
                if (g_verbose)
                    fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
@@ -609,7 +615,7 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
        if (tblinfo[i].sequence)/* already dumped */
            continue;
 
-       if (!onlytable || (!strcmp(classname, onlytable)))
+       if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
        {
            if (g_verbose)
                fprintf(stderr, "%s preparing to dump out the contents of Table '%s' %s\n",
@@ -847,6 +853,11 @@ main(int argc, char **argv)
                        for (i = 0; tablename[i]; i++)
                            if (isupper((unsigned char) tablename[i]))
                                tablename[i] = tolower((unsigned char) tablename[i]);
+
+                       /* '*' is a special case meaning ALL tables, but only if unquoted */
+                       if (strcmp(tablename,"*") == 0)
+                           tablename[0] = '\0';
+
                    }
                }
                break;
@@ -901,10 +912,10 @@ main(int argc, char **argv)
        exit(1);
    }
 
-   if (outputBlobs && (tablename != NULL) )
+   if (outputBlobs && tablename != NULL && strlen(tablename) > 0 )
    {
        fprintf(stderr,
-               "%s: BLOB output is not supported for a single table. Use a full dump instead.\n",
+               "%s: BLOB output is not supported for a single table. Use all tables or a full dump instead.\n",
                progname);
        exit(1);
    }
@@ -2301,6 +2312,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                if (findx == numFuncs)
                {
                    PGresult   *r;
+                   int         numFuncs;
 
                    /*
                     * the funcname is an oid which we use to find the
@@ -2318,9 +2330,19 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                    r = PQexec(g_conn, query->data);
                    if (!r || PQresultStatus(r) != PGRES_TUPLES_OK)
                    {
-                       fprintf(stderr, "getTables(): SELECT (funcname) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
+                       fprintf(stderr, "getTables(): SELECT (funcname) failed for trigger %s.  Explanation from backend: '%s'.\n", 
+                                   PQgetvalue(res2, i2, i_tgname), PQerrorMessage(g_conn));
+                       exit_nicely(g_conn);
+                   }
+
+                   /* Sanity: Check we got only one tuple */
+                   numFuncs = PQntuples(r);
+                   if (numFuncs != 1) {
+                       fprintf(stderr, "getTables(): SELECT (funcname) for trigger %s returned %d tuples. Expected 1.\n", 
+                                   PQgetvalue(res2, i2, i_tgname), numFuncs);
                        exit_nicely(g_conn);
                    }
+
                    tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
                    PQclear(r);
                }
@@ -2607,6 +2629,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
            if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
            {
                PGresult   *res2;
+               int         numAttr;
 
                if (g_verbose)
                    fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
@@ -2626,6 +2649,15 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                            "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
                    exit_nicely(g_conn);
                }
+
+               /* Sanity: Check we got only one tuple */
+               numAttr = PQntuples(res2);
+               if (numAttr != 1) {
+                   fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) for attr %s returned %d tuples. Expected 1.\n", 
+                                       tblinfo[i].attnames[j], numAttr);
+                   exit_nicely(g_conn);
+               }
+
                tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
                PQclear(res2);
            }
@@ -3539,7 +3571,7 @@ dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
    char       *reltypename;
 
    /* First - dump SEQUENCEs */
-   if (tablename)
+   if (tablename && strlen(tablename) > 0)
    {
        serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
        strcpy(serialSeq, tablename);
@@ -3566,7 +3598,7 @@ dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
        if (tblinfo[i].sequence)/* already dumped */
            continue;
 
-       if (!tablename || (!strcmp(tblinfo[i].relname, tablename)))
+       if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
        {
 
            resetPQExpBuffer(delq);
@@ -3727,6 +3759,7 @@ dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
            funcname = NULL;
        else
        {
+           int     numFuncs;
 
            /*
             * the funcname is an oid which we use to find the name of the
@@ -3746,6 +3779,15 @@ dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
                        "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
                exit_nicely(g_conn);
            }
+
+           /* Sanity: Check we got only one tuple */
+           numFuncs = PQntuples(res);
+           if (numFuncs != 1) {
+               fprintf(stderr, "dumpIndices(): SELECT (funcname) for index %s returned %d tuples. Expected 1.\n", 
+                               indinfo[i].indrelname, numFuncs);
+               exit_nicely(g_conn);
+           }
+
            funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
            PQclear(res);
        }
@@ -3753,6 +3795,8 @@ dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
        /* convert opclass oid(s) into names */
        for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
        {
+           int     numRows;
+
            indclass = atoi(indinfo[i].indclass[nclass]);
            if (indclass == 0)
                break;
@@ -3768,6 +3812,15 @@ dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
                                    "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
                exit_nicely(g_conn);
            }
+
+           /* Sanity: Check we got only one tuple */
+           numRows = PQntuples(res);
+           if (numRows != 1) {
+               fprintf(stderr, "dumpIndices(): SELECT (classname) for index %s returned %d tuples. Expected 1.\n", 
+                                   indinfo[i].indrelname, numRows);
+               exit_nicely(g_conn);
+           }
+
            classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
            PQclear(res);
        }
@@ -3815,7 +3868,7 @@ dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
            }
        }
 
-       if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
+       if (!tablename || (strcmp(indinfo[i].indrelname, tablename) == 0) || (strlen(tablename) == 0) )
        {
 
            /*
@@ -4140,8 +4193,9 @@ dumpTriggers(Archive *fout, const char *tablename,
 
    for (i = 0; i < numTables; i++)
    {
-       if (tablename && strcmp(tblinfo[i].relname, tablename))
+       if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0) )
            continue;
+
        for (j = 0; j < tblinfo[i].ntrig; j++)
        {
            ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
@@ -4177,7 +4231,7 @@ dumpRules(Archive *fout, const char *tablename,
     */
    for (t = 0; t < numTables; t++)
    {
-       if (tablename && strcmp(tblinfo[t].relname, tablename))
+       if (tablename && (strcmp(tblinfo[t].relname, tablename) != 0) && (strlen(tablename) > 0) )
            continue;
 
        /*