Use a cursor for fetching data in -d or -D mode, so that pg_dump doesn't
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 27 Aug 2001 20:33:07 +0000 (20:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 27 Aug 2001 20:33:07 +0000 (20:33 +0000)
run out of memory with large tables in these modes.  Patch from
Martijn van Oosterhout.

src/bin/pg_dump/pg_dump.c

index 6085c241f4035b8d0148056ee9b830d474541447..abed81cf825add76ce71a0de521299ef314c7dc0 100644 (file)
@@ -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;
 }