Skip to content

Commit 814f40c

Browse files
committed
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.
1 parent 545c669 commit 814f40c

File tree

1 file changed

+79
-51
lines changed

1 file changed

+79
-51
lines changed

src/bin/pg_dump/pg_dump.c

Lines changed: 79 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
*
2424
* IDENTIFICATION
25-
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.226 2001/08/27 01:09:59 tgl Exp $
25+
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.227 2001/08/27 20:33:07 tgl Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -400,77 +400,105 @@ dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
400400

401401
if (fout->remoteVersion >= 70100)
402402
{
403-
appendPQExpBuffer(q, "SELECT * FROM ONLY %s", fmtId(classname, force_quotes));
403+
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM ONLY %s", fmtId(classname, force_quotes));
404404
} else {
405-
appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
405+
appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM %s", fmtId(classname, force_quotes));
406406
}
407407

408408
res = PQexec(g_conn, q->data);
409409
if (!res ||
410-
PQresultStatus(res) != PGRES_TUPLES_OK)
410+
PQresultStatus(res) != PGRES_COMMAND_OK)
411411
{
412412
write_msg(NULL, "dumpClasses(): SQL command failed\n");
413413
write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
414414
write_msg(NULL, "The command was: %s\n", q->data);
415415
exit_nicely();
416416
}
417-
for (tuple = 0; tuple < PQntuples(res); tuple++)
418-
{
419-
archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
420-
if (attrNames == true)
417+
418+
do {
419+
PQclear(res);
420+
421+
res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
422+
if (!res ||
423+
PQresultStatus(res) != PGRES_TUPLES_OK)
421424
{
422-
resetPQExpBuffer(q);
423-
appendPQExpBuffer(q, "(");
424-
for (field = 0; field < PQnfields(res); field++)
425-
{
426-
if (field > 0)
427-
appendPQExpBuffer(q, ",");
428-
appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
429-
}
430-
appendPQExpBuffer(q, ") ");
431-
archprintf(fout, "%s", q->data);
425+
write_msg(NULL, "dumpClasses(): SQL command failed\n");
426+
write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
427+
write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n");
428+
exit_nicely();
432429
}
433-
archprintf(fout, "VALUES (");
434-
for (field = 0; field < PQnfields(res); field++)
430+
431+
for (tuple = 0; tuple < PQntuples(res); tuple++)
435432
{
436-
if (field > 0)
437-
archprintf(fout, ",");
438-
if (PQgetisnull(res, tuple, field))
433+
archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
434+
if (attrNames == true)
439435
{
440-
archprintf(fout, "NULL");
441-
continue;
436+
resetPQExpBuffer(q);
437+
appendPQExpBuffer(q, "(");
438+
for (field = 0; field < PQnfields(res); field++)
439+
{
440+
if (field > 0)
441+
appendPQExpBuffer(q, ",");
442+
appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
443+
}
444+
appendPQExpBuffer(q, ") ");
445+
archprintf(fout, "%s", q->data);
442446
}
443-
switch (PQftype(res, field))
447+
archprintf(fout, "VALUES (");
448+
for (field = 0; field < PQnfields(res); field++)
444449
{
445-
case INT2OID:
446-
case INT4OID:
447-
case OIDOID: /* int types */
448-
case FLOAT4OID:
449-
case FLOAT8OID:/* float types */
450-
/* These types are printed without quotes */
451-
archprintf(fout, "%s",
452-
PQgetvalue(res, tuple, field));
453-
break;
454-
case BITOID:
455-
case VARBITOID:
456-
archprintf(fout, "B'%s'",
457-
PQgetvalue(res, tuple, field));
458-
break;
459-
default:
460-
461-
/*
462-
* All other types are printed as string literals,
463-
* with appropriate escaping of special characters.
464-
*/
465-
resetPQExpBuffer(q);
466-
formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
467-
archprintf(fout, "%s", q->data);
468-
break;
450+
if (field > 0)
451+
archprintf(fout, ",");
452+
if (PQgetisnull(res, tuple, field))
453+
{
454+
archprintf(fout, "NULL");
455+
continue;
456+
}
457+
switch (PQftype(res, field))
458+
{
459+
case INT2OID:
460+
case INT4OID:
461+
case OIDOID: /* int types */
462+
case FLOAT4OID:
463+
case FLOAT8OID:/* float types */
464+
/* These types are printed without quotes */
465+
archprintf(fout, "%s",
466+
PQgetvalue(res, tuple, field));
467+
break;
468+
case BITOID:
469+
case VARBITOID:
470+
archprintf(fout, "B'%s'",
471+
PQgetvalue(res, tuple, field));
472+
break;
473+
default:
474+
475+
/*
476+
* All other types are printed as string literals,
477+
* with appropriate escaping of special characters.
478+
*/
479+
resetPQExpBuffer(q);
480+
formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
481+
archprintf(fout, "%s", q->data);
482+
break;
483+
}
469484
}
485+
archprintf(fout, ");\n");
470486
}
471-
archprintf(fout, ");\n");
487+
488+
} while( PQntuples(res) > 0 );
489+
PQclear(res);
490+
491+
res = PQexec(g_conn, "CLOSE _pg_dump_cursor");
492+
if (!res ||
493+
PQresultStatus(res) != PGRES_COMMAND_OK)
494+
{
495+
write_msg(NULL, "dumpClasses(): SQL command failed\n");
496+
write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
497+
write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n");
498+
exit_nicely();
472499
}
473500
PQclear(res);
501+
474502
destroyPQExpBuffer(q);
475503
return 1;
476504
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy