*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.196 2003/04/24 21:16:42 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.197 2003/04/25 02:28:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* 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);
* 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 = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *));
- constraintexprs = (ExprState **) palloc0(num_phys_attrs * sizeof(ExprState *));
+ 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 = (ExprState **) palloc((num_phys_attrs + 1) * sizeof(ExprState *));
+ constraintexprs = (ExprState **) palloc0((num_phys_attrs + 1) * sizeof(ExprState *));
for (i = 0; i < num_phys_attrs; i++)
{
}
}
- 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));
/* Make room for a PARAM_EXEC value for domain constraint checks */
if (hasConstraints)
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(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,
* by PostgreSQL
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.326 2003/04/04 20:42:12 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.327 2003/04/25 02:28:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* possibility of retrieving data in the wrong column order. (The
* default column ordering of COPY will not be what we want in certain
* corner cases involving ADD COLUMN and inheritance.)
- *
- * NB: caller should have already determined that there are dumpable
- * columns, so that fmtCopyColumnList will return something.
*/
if (g_fout->remoteVersion >= 70300)
column_list = fmtCopyColumnList(tbinfo);
PQExpBuffer q = createPQExpBuffer();
PGresult *res;
int tuple;
+ int nfields;
int field;
/*
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, ", ");
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, ", ");
if (tblinfo[i].dump)
{
- const char *column_list;
-
if (g_verbose)
write_msg(NULL, "preparing to dump the contents of table %s\n",
classname);
- /* Get column list first to check for zero-column table */
- column_list = fmtCopyColumnList(&(tblinfo[i]));
- if (column_list)
- {
- dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
- dumpCtx->tblinfo = (TableInfo *) tblinfo;
- dumpCtx->tblidx = i;
- dumpCtx->oids = oids;
+ dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
+ dumpCtx->tblinfo = (TableInfo *) tblinfo;
+ dumpCtx->tblidx = i;
+ dumpCtx->oids = oids;
- if (!dumpData)
- {
- /* Dump/restore using COPY */
- dumpFn = dumpClasses_nodumpData;
- resetPQExpBuffer(copyBuf);
- appendPQExpBuffer(copyBuf, "COPY %s %s %sFROM stdin;\n",
- fmtId(tblinfo[i].relname),
- column_list,
+ if (!dumpData)
+ {
+ /* Dump/restore using COPY */
+ dumpFn = dumpClasses_nodumpData;
+ resetPQExpBuffer(copyBuf);
+ appendPQExpBuffer(copyBuf, "COPY %s %s %sFROM stdin;\n",
+ fmtId(tblinfo[i].relname),
+ fmtCopyColumnList(&(tblinfo[i])),
(oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
- copyStmt = copyBuf->data;
- }
- else
- {
- /* Restore using INSERT */
- dumpFn = dumpClasses_dumpData;
- copyStmt = NULL;
- }
-
- ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
- tblinfo[i].relnamespace->nspname,
- tblinfo[i].usename,
- "TABLE DATA", NULL, "", "", copyStmt,
- dumpFn, dumpCtx);
+ copyStmt = copyBuf->data;
}
+ else
+ {
+ /* Restore using INSERT */
+ dumpFn = dumpClasses_dumpData;
+ copyStmt = NULL;
+ }
+
+ ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
+ tblinfo[i].relnamespace->nspname,
+ tblinfo[i].usename,
+ "TABLE DATA", NULL, "", "", copyStmt,
+ dumpFn, dumpCtx);
}
}
* Return a column list clause for the given relation.
*
* Special case: if there are no undropped columns in the relation, return
- * NULL, not an invalid "()" column list.
+ * "", not an invalid "()" column list.
*/
static const char *
fmtCopyColumnList(const TableInfo *ti)
}
if (!needComma)
- return NULL; /* no undropped columns */
+ return ""; /* no undropped columns */
appendPQExpBuffer(q, ")");
return q->data;