This patch can be installed as part of 1.02.1 so people can properly
authorMarc G. Fournier
Wed, 14 Aug 1996 05:33:11 +0000 (05:33 +0000)
committerMarc G. Fournier
Wed, 14 Aug 1996 05:33:11 +0000 (05:33 +0000)
pg_dump and load to 2.0.  I haven't gotten any feedback on whether
people want it, so I am submitting it for others to decide.  I would
recommend an install in 1.02.1.

I had said that the 2.0 pg_dump could dump a 1.02.1 database, but I was
wrong.  The copy is actually performed by the backend, and the 2.0
database will not be able to read 1.02.1 databases because of the new
system columns.

This patch does several things.  It copies nulls out as \N, so they can
be distinguished from '' strings.  It fixes a problem where backslashes
in the input stream were not output as double-backslashes.  Without this
patch, backslashes copied out were deleted upon input, or interpreted as
special characters.  Third, input is now terminated by backslash-period.
This can not be part of a normal input stream.

I tested this by creating a database with all sorts of nulls, backslash,
and period fields and dumped the database and reloaded into a new
database and compared them.

Submitted by: Bruce

src/backend/commands/copy.c
src/bin/pg_dump/pg_dump.c

index f6815a3631f325d380fc303e41cfff4f933554bb..e17100a0fb06ac92611b78c46b7f76e9a6c145aa 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.2 1996/07/23 02:23:15 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.3 1996/08/14 05:33:04 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -107,7 +107,7 @@ DoCopy(char *relname, bool binary, bool from, bool pipe, char *filename,
     if (!pipe) {
    fclose(fp);
     }else if (!from && !binary) {
-   fputs(".\n", fp);
+   fputs("\\.\n", fp);
    if (IsUnderPostmaster) fflush(Pfout);
     }
 }
@@ -169,6 +169,9 @@ CopyTo(Relation rel, bool binary, FILE *fp, char *delim)
            CopyAttributeOut(fp, string, delim);
            pfree(string);
        }
+       else
+           fputs("\\N", fp);   /* null indicator */
+
        if (i == attr_count - 1) {
            fputc('\n', fp);
        }else {
@@ -703,40 +706,22 @@ CopyReadAttribute(int attno, FILE *fp, bool *isnull, char *delim)
     int done = 0;
     int i = 0;
     
-    if (feof(fp)) {
-   *isnull = (bool) false;
+    *isnull = (bool) false;    /* set default */
+    if (feof(fp))
    return(NULL);
-    }
     
     while (!done) {
    c = getc(fp);
        
-   if (feof(fp)) {
-       *isnull = (bool) false;
+   if (feof(fp))
        return(NULL);
-   }else if (reading_from_input && attno == 0 && i == 0 && c == '.') {
-       attribute[0] = c;
-       c = getc(fp);
-       if (c == '\n') {
-       *isnull = (bool) false;
-       return(NULL);
-       }else if (inString(c,delim)) {
-       attribute[1] = 0;
-       *isnull = (bool) false;
-       return(&attribute[0]);
-       }else {
-       attribute[1] = c;
-       i = 2;
-       }
-   }else if (c == '\\') {
+   else if (c == '\\') {
        c = getc(fp);
 #ifdef ESCAPE_PATCH
 #define ISOCTAL(c)    (((c) >= '0') && ((c) <= '7'))
 #define       VALUE(c)        ((c) - '0')
-            if (feof(fp)) {
-                *isnull = (bool) false;
+            if (feof(fp))
                 return(NULL);
-            }
             switch (c) {
               case '0':
               case '1':
@@ -755,21 +740,17 @@ CopyReadAttribute(int attno, FILE *fp, bool *isnull, char *delim)
                     if (ISOCTAL(c)) {
                         val = (val<<3) + VALUE(c);
                     } else {
-                        if (feof(fp)) {
-                            *isnull = (bool) false;
+                        if (feof(fp))
                             return(NULL);
-                        }
                         ungetc(c, fp);
                     }
                 } else {
-                    if (feof(fp)) {
-                        *isnull = (bool) false;
+                    if (feof(fp))
                         return(NULL);
-                    }
                     ungetc(c, fp);
                 }
                 c = val & 0377;
-            }
+              }
                 break;
               case 'b':
                 c = '\b';
@@ -789,6 +770,16 @@ CopyReadAttribute(int attno, FILE *fp, bool *isnull, char *delim)
               case 'v':
                 c = '\v';
                 break;
+              case 'N':
+           attribute[0] = '\0'; /* just to be safe */
+           *isnull = (bool) true;
+           break;
+              case '.':
+                c = getc(fp);
+           if (c != '\n')
+           elog(WARN, "CopyReadAttribute - end of record marker corrupted");
+       return(NULL);
+       break;
             }
 #endif
    }else if (inString(c,delim) || c == '\n') {
@@ -799,13 +790,7 @@ CopyReadAttribute(int attno, FILE *fp, bool *isnull, char *delim)
        elog(WARN, "CopyReadAttribute - attribute length too long");
     }
     attribute[i] = '\0';
-    if (i == 0) {
-   *isnull = (bool) true;
-   return(NULL);
-    }else {
-   *isnull = (bool) false;
-   return(&attribute[0]);
-    }
+    return(&attribute[0]);
 }
 
 #ifdef ESCAPE_PATCH
@@ -817,26 +802,26 @@ CopyAttributeOut(FILE *fp, char *string, char *delim)
     int len = strlen(string);
 
     /* XXX - This is a kludge, we should check the data type */
-    if (len && (string[0] == '{') && (string[len-1] == '}')) {
+    if (len && (string[0] == '{') && (string[len-1] == '}'))
       is_array = true;
-    }
 
     for ( ; c = *string; string++) {
-      if ((c == delim[0]) || (c == '\n')) {
+      if (c == delim[0] || c == '\n' ||
+          (c == '\\' && !is_array))
           fputc('\\', fp);
-      } else if ((c == '\\') && is_array) {
-          if (*(string+1) == '\\') {
-              /* translate \\ to \\\\ */
-              fputc('\\', fp);
-              fputc('\\', fp);
-              fputc('\\', fp);
-              string++;
-          } else if (*(string+1) == '"') {
-              /* translate \" to \\\" */
-              fputc('\\', fp);
-              fputc('\\', fp);
-          }
-      }
+      else
+          if (c == '\\' && is_array)
+              if (*(string+1) == '\\') {
+                  /* translate \\ to \\\\ */
+                  fputc('\\', fp);
+                  fputc('\\', fp);
+                  fputc('\\', fp);
+                  string++;
+              } else if (*(string+1) == '"') {
+                  /* translate \" to \\\" */
+                  fputc('\\', fp);
+                  fputc('\\', fp);
+              }
       fputc(*string, fp);
     }
 }
index 85943a88b1f8f473da77b61c08387a38f3f9d949..98e2fa3fd8a9e21f245aed10085d7535ff553042 100644 (file)
@@ -20,7 +20,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.5 1996/07/31 06:09:46 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.6 1996/08/14 05:33:11 scrappy Exp $
  *
  * Modifications - 6/10/96 - [email protected] - version 1.13.dhb
  *
@@ -1394,7 +1394,9 @@ dumpClasses(TableInfo *tblinfo, int numTables, FILE *fout, char *onlytable)
            while (!copydone) {
                ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
    
-               if (copybuf[0] == '.' && copybuf[1] =='\0') {
+               if (copybuf[0] == '\\' &&
+           copybuf[1] == '.' &&
+           copybuf[2] == '\0') {
                copydone = true;    /* don't print this... */
                } else {
                    fputs(copybuf, stdout);
@@ -1410,7 +1412,7 @@ dumpClasses(TableInfo *tblinfo, int numTables, FILE *fout, char *onlytable)
                    }
                }
            }
-           fprintf(fout, ".\n");
+           fprintf(fout, "\\.\n");
            PQclear(res);
            PQendcopy(res->conn);
             } else {