From 814f40cf43fc899e854b2c09219c5285da3eda04 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Mon, 27 Aug 2001 20:33:07 +0000 Subject: [PATCH] Use a cursor for fetching data in -d or -D mode, so that pg_dump doesn't run out of memory with large tables in these modes. Patch from Martijn van Oosterhout. --- src/bin/pg_dump/pg_dump.c | 130 +++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 51 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 6085c241f40..abed81cf825 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.226 2001/08/27 01:09:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.227 2001/08/27 20:33:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -400,77 +400,105 @@ dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv) if (fout->remoteVersion >= 70100) { - appendPQExpBuffer(q, "SELECT * FROM ONLY %s", fmtId(classname, force_quotes)); + appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM ONLY %s", fmtId(classname, force_quotes)); } else { - appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes)); + appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM %s", fmtId(classname, force_quotes)); } res = PQexec(g_conn, q->data); if (!res || - PQresultStatus(res) != PGRES_TUPLES_OK) + PQresultStatus(res) != PGRES_COMMAND_OK) { write_msg(NULL, "dumpClasses(): SQL command failed\n"); write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn)); write_msg(NULL, "The command was: %s\n", q->data); exit_nicely(); } - for (tuple = 0; tuple < PQntuples(res); tuple++) - { - archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes)); - if (attrNames == true) + + do { + PQclear(res); + + res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor"); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { - resetPQExpBuffer(q); - appendPQExpBuffer(q, "("); - for (field = 0; field < PQnfields(res); field++) - { - if (field > 0) - appendPQExpBuffer(q, ","); - appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes)); - } - appendPQExpBuffer(q, ") "); - archprintf(fout, "%s", q->data); + write_msg(NULL, "dumpClasses(): SQL command failed\n"); + write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn)); + write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n"); + exit_nicely(); } - archprintf(fout, "VALUES ("); - for (field = 0; field < PQnfields(res); field++) + + for (tuple = 0; tuple < PQntuples(res); tuple++) { - if (field > 0) - archprintf(fout, ","); - if (PQgetisnull(res, tuple, field)) + archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes)); + if (attrNames == true) { - archprintf(fout, "NULL"); - continue; + resetPQExpBuffer(q); + appendPQExpBuffer(q, "("); + for (field = 0; field < PQnfields(res); field++) + { + if (field > 0) + appendPQExpBuffer(q, ","); + appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes)); + } + appendPQExpBuffer(q, ") "); + archprintf(fout, "%s", q->data); } - switch (PQftype(res, field)) + archprintf(fout, "VALUES ("); + for (field = 0; field < PQnfields(res); field++) { - case INT2OID: - case INT4OID: - case OIDOID: /* int types */ - case FLOAT4OID: - case FLOAT8OID:/* float types */ - /* These types are printed without quotes */ - archprintf(fout, "%s", - PQgetvalue(res, tuple, field)); - break; - case BITOID: - case VARBITOID: - archprintf(fout, "B'%s'", - PQgetvalue(res, tuple, field)); - break; - default: - - /* - * All other types are printed as string literals, - * with appropriate escaping of special characters. - */ - resetPQExpBuffer(q); - formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL); - archprintf(fout, "%s", q->data); - break; + if (field > 0) + archprintf(fout, ","); + if (PQgetisnull(res, tuple, field)) + { + archprintf(fout, "NULL"); + continue; + } + switch (PQftype(res, field)) + { + case INT2OID: + case INT4OID: + case OIDOID: /* int types */ + case FLOAT4OID: + case FLOAT8OID:/* float types */ + /* These types are printed without quotes */ + archprintf(fout, "%s", + PQgetvalue(res, tuple, field)); + break; + case BITOID: + case VARBITOID: + archprintf(fout, "B'%s'", + PQgetvalue(res, tuple, field)); + break; + default: + + /* + * All other types are printed as string literals, + * with appropriate escaping of special characters. + */ + resetPQExpBuffer(q); + formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL); + archprintf(fout, "%s", q->data); + break; + } } + archprintf(fout, ");\n"); } - archprintf(fout, ");\n"); + + } while( PQntuples(res) > 0 ); + PQclear(res); + + res = PQexec(g_conn, "CLOSE _pg_dump_cursor"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) + { + write_msg(NULL, "dumpClasses(): SQL command failed\n"); + write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn)); + write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n"); + exit_nicely(); } PQclear(res); + destroyPQExpBuffer(q); return 1; } -- GitLab