From: Tom Lane Date: Fri, 25 Apr 2003 22:14:33 +0000 (+0000) Subject: Back-patch fixes for zero-column tables in COPY, pg_dump. X-Git-Tag: REL7_3_3~23 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=66e0ea47a002183901d2053ed980a78f464dea36;p=postgresql Back-patch fixes for zero-column tables in COPY, pg_dump. --- diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 906dd277ea..dd551659d5 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -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, diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 4b7e41cf06..4b77c01651 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -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; }