]> granicus.if.org Git - postgresql/commitdiff
Back-patch fixes for zero-column tables in COPY, pg_dump.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 25 Apr 2003 22:14:33 +0000 (22:14 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 25 Apr 2003 22:14:33 +0000 (22:14 +0000)
src/backend/commands/copy.c
src/bin/pg_dump/pg_dump.c

index 906dd277eaf5f269de15b7f621864137a75e03e7..dd551659d5aca855c1aca7ef7a6f73be93cc746b 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.177.2.1 2002/12/01 17:33:33 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.177.2.2 2003/04/25 22:14:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -542,10 +542,11 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
         * Get info about the columns we need to process.
         *
         * For binary copy we really only need isvarlena, but compute it all...
+        * +1's here are to avoid palloc(0) in a zero-column table.
         */
-       out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
-       elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
-       isvarlena = (bool *) palloc(num_phys_attrs * sizeof(bool));
+       out_functions = (FmgrInfo *) palloc((num_phys_attrs + 1) * sizeof(FmgrInfo));
+       elements = (Oid *) palloc((num_phys_attrs + 1) * sizeof(Oid));
+       isvarlena = (bool *) palloc((num_phys_attrs + 1) * sizeof(bool));
        foreach(cur, attnumlist)
        {
                int                     attnum = lfirsti(cur);
@@ -799,13 +800,14 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
         * relation, including the input function, the element type (to pass
         * to the input function), and info about defaults and constraints.
         * (We don't actually use the input function if it's a binary copy.)
+        * +1's here are to avoid palloc(0) in a zero-column table.
         */
-       in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
-       elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
-       defmap = (int *) palloc(num_phys_attrs * sizeof(int));
-       defexprs = (Node **) palloc(num_phys_attrs * sizeof(Node *));
-       constraintexprs = (Node **) palloc(num_phys_attrs * sizeof(Node *));
-       constraintconsts = (Const **) palloc(num_phys_attrs * sizeof(Const *));
+       in_functions = (FmgrInfo *) palloc((num_phys_attrs + 1) * sizeof(FmgrInfo));
+       elements = (Oid *) palloc((num_phys_attrs + 1) * sizeof(Oid));
+       defmap = (int *) palloc((num_phys_attrs + 1) * sizeof(int));
+       defexprs = (Node **) palloc((num_phys_attrs + 1) * sizeof(Node *));
+       constraintexprs = (Node **) palloc((num_phys_attrs + 1) * sizeof(Node *));
+       constraintconsts = (Const **) palloc((num_phys_attrs + 1) * sizeof(Const *));
        MemSet(constraintexprs, 0, num_phys_attrs * sizeof(Node *));
 
        for (i = 0; i < num_phys_attrs; i++)
@@ -917,8 +919,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
                }
        }
 
-       values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
-       nulls = (char *) palloc(num_phys_attrs * sizeof(char));
+       values = (Datum *) palloc((num_phys_attrs + 1) * sizeof(Datum));
+       nulls = (char *) palloc((num_phys_attrs + 1) * sizeof(char));
 
        copy_lineno = 0;
        fe_eof = false;
@@ -1015,9 +1017,31 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
                        if (done)
                                break;                  /* out of per-row loop */
 
-                       /* Complain if there are more fields on the input line */
+                       /*
+                        * Complain if there are more fields on the input line.
+                        *
+                        * Special case: if we're reading a zero-column table, we
+                        * won't yet have called CopyReadAttribute() at all; so do that
+                        * and check we have an empty line.  Fortunately we can keep that
+                        * silly corner case out of the main line of execution.
+                        */
                        if (result == NORMAL_ATTR)
-                               elog(ERROR, "Extra data after last expected column");
+                       {
+                               if (attnumlist == NIL && !file_has_oids)
+                               {
+                                       string = CopyReadAttribute(fp, delim, &result);
+                                       if (result == NORMAL_ATTR || *string != '\0')
+                                               elog(ERROR, "Extra data after last expected column");
+                                       if (result == END_OF_FILE)
+                                       {
+                                               /* EOF at start of line: all is well */
+                                               done = true;
+                                               break;
+                                       }
+                               }
+                               else
+                                       elog(ERROR, "Extra data after last expected column");
+                       }
 
                        /*
                         * If we got some data on the line, but it was ended by EOF,
index 4b7e41cf06343dd8b0858c808736a0e644c372b2..4b77c016512f642332d5b1229d7a8aca17a79d46 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.305.2.3 2003/02/13 22:56:59 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.305.2.4 2003/04/25 22:14:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -960,6 +960,7 @@ dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
        PQExpBuffer q = createPQExpBuffer();
        PGresult   *res;
        int                     tuple;
+       int                     nfields;
        int                     field;
 
        /*
@@ -1009,14 +1010,21 @@ dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
                        exit_nicely();
                }
 
+               nfields = PQnfields(res);
                for (tuple = 0; tuple < PQntuples(res); tuple++)
                {
                        archprintf(fout, "INSERT INTO %s ", fmtId(classname));
+                       if (nfields == 0)
+                       {
+                               /* corner case for zero-column table */
+                               archprintf(fout, "DEFAULT VALUES;\n");
+                               continue;
+                       }
                        if (attrNames == true)
                        {
                                resetPQExpBuffer(q);
                                appendPQExpBuffer(q, "(");
-                               for (field = 0; field < PQnfields(res); field++)
+                               for (field = 0; field < nfields; field++)
                                {
                                        if (field > 0)
                                                appendPQExpBuffer(q, ", ");
@@ -1026,7 +1034,7 @@ dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
                                archprintf(fout, "%s", q->data);
                        }
                        archprintf(fout, "VALUES (");
-                       for (field = 0; field < PQnfields(res); field++)
+                       for (field = 0; field < nfields; field++)
                        {
                                if (field > 0)
                                        archprintf(fout, ", ");
@@ -6702,7 +6710,10 @@ fmtQualifiedId(const char *schema, const char *id)
 }
 
 /*
- * return a column list clause for the given relation.
+ * Return a column list clause for the given relation.
+ *
+ * Special case: if there are no undropped columns in the relation, return
+ * "", not an invalid "()" column list.
  */
 static const char *
 fmtCopyColumnList(const TableInfo *ti)
@@ -6730,6 +6741,10 @@ fmtCopyColumnList(const TableInfo *ti)
                appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
                needComma = true;
        }
+
+       if (!needComma)
+               return "";                              /* no undropped columns */
+
        appendPQExpBuffer(q, ")");
        return q->data;
 }