src/bin/pg_dump/pg_dump.c
static int
dumpTableData_copy(Archive *fout, const void *dcontext)
{
	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
	TableInfo  *tbinfo = tdinfo->tdtable;
	const char *classname = tbinfo->dobj.name;
	PQExpBuffer q = createPQExpBuffer();

	/*
	 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
	 * which uses it already.
	 */
	PQExpBuffer clistBuf = createPQExpBuffer();
	PGconn	   *conn = GetConnection(fout);
	PGresult   *res;
	int			ret;
	char	   *copybuf;
	const char *column_list;

	pg_log_info("dumping contents of table \"%s.%s\"",
				tbinfo->dobj.namespace->dobj.name, classname);

	/*
	 * Specify the column list explicitly so that we have no 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.)
	 */
	column_list = fmtCopyColumnList(tbinfo, clistBuf);

	/*
	 * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
	 * a filter condition was specified.  For other cases a simple COPY
	 * suffices.
	 */
	if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
	{
		appendPQExpBufferStr(q, "COPY (SELECT ");
		/* klugery to get rid of parens in column list */
		if (strlen(column_list) > 2)
		{
			appendPQExpBufferStr(q, column_list + 1);
			q->data[q->len - 1] = ' ';
		}
		else
			appendPQExpBufferStr(q, "* ");

		appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
						  fmtQualifiedDumpable(tbinfo),
						  tdinfo->filtercond ? tdinfo->filtercond : "");
	}
	else
	{
		appendPQExpBuffer(q, "COPY %s %s TO stdout;",
						  fmtQualifiedDumpable(tbinfo),
						  column_list);
	}
	res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
	PQclear(res);
	destroyPQExpBuffer(clistBuf);

	for (;;)
	{
		ret = PQgetCopyData(conn, &copybuf, 0);

		if (ret < 0)
			break;				/* done or error */

		if (copybuf)
		{
			WriteData(fout, copybuf, ret);
			PQfreemem(copybuf);
		}

		/* ----------
		 * THROTTLE:
		 *
		 * There was considerable discussion in late July, 2000 regarding
		 * slowing down pg_dump when backing up large tables. Users with both
		 * slow & fast (multi-processor) machines experienced performance
		 * degradation when doing a backup.
		 *
		 * Initial attempts based on sleeping for a number of ms for each ms
		 * of work were deemed too complex, then a simple 'sleep in each loop'
		 * implementation was suggested. The latter failed because the loop
		 * was too tight. Finally, the following was implemented:
		 *
		 * If throttle is non-zero, then
		 *		See how long since the last sleep.
		 *		Work out how long to sleep (based on ratio).
		 *		If sleep is more than 100ms, then
		 *			sleep
		 *			reset timer
		 *		EndIf
		 * EndIf
		 *
		 * where the throttle value was the number of ms to sleep per ms of
		 * work. The calculation was done in each loop.
		 *
		 * Most of the hard work is done in the backend, and this solution
		 * still did not work particularly well: on slow machines, the ratio
		 * was 50:1, and on medium paced machines, 1:1, and on fast
		 * multi-processor machines, it had little or no effect, for reasons
		 * that were unclear.
		 *
		 * Further discussion ensued, and the proposal was dropped.
		 *
		 * For those people who want this feature, it can be implemented using
		 * gettimeofday in each loop, calculating the time since last sleep,
		 * multiplying that by the sleep ratio, then if the result is more
		 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
		 * function to sleep for a subsecond period ie.
		 *
		 * select(0, NULL, NULL, NULL, &tvi);
		 *
		 * This will return after the interval specified in the structure tvi.
		 * Finally, call gettimeofday again to save the 'last sleep time'.
		 * ----------
		 */
	}
	archprintf(fout, "\\.\n\n\n");

	if (ret == -2)
	{
		/* copy data transfer failed */
		pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
		pg_log_error("Error message from server: %s", PQerrorMessage(conn));
		pg_log_error("The command was: %s", q->data);
		exit_nicely(1);
	}

	/* Check command status and return to normal libpq state */
	res = PQgetResult(conn);
	if (PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
		pg_log_error("Error message from server: %s", PQerrorMessage(conn));
		pg_log_error("The command was: %s", q->data);
		exit_nicely(1);
	}
	PQclear(res);

	/* Do this to ensure we've pumped libpq back to idle state */
	if (PQgetResult(conn) != NULL)
		pg_log_warning("unexpected extra results during COPY of table \"%s\"",
					   classname);

	destroyPQExpBuffer(q);
	return 1;
}
/*
 *	Dump a table's contents for loading using the COPY command
 *	- this routine is called by the Archiver when it wants the table
 *	  to be dumped.
 */
Dump a table's contents for loading using the COPY command
- this routine is called by the Archiver when it wants the table
to be dumped.
Dump a table ' s contents for loading using the COPY command - this routine is called by the Archiver when it wants the table to be dumped .
static int
dumpTableData_copy(Archive *fout, const void *dcontext)
{
	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
	TableInfo  *tbinfo = tdinfo->tdtable;
	const char *classname = tbinfo->dobj.name;
	PQExpBuffer q = createPQExpBuffer();
	PQExpBuffer clistBuf = createPQExpBuffer();
	PGconn	   *conn = GetConnection(fout);
	PGresult   *res;
	int			ret;
	char	   *copybuf;
	const char *column_list;
	pg_log_info("dumping contents of table \"%s.%s\"",
				tbinfo->dobj.namespace->dobj.name, classname);
	column_list = fmtCopyColumnList(tbinfo, clistBuf);
	if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
	{
		appendPQExpBufferStr(q, "COPY (SELECT ");
		if (strlen(column_list) > 2)
		{
			appendPQExpBufferStr(q, column_list + 1);
			q->data[q->len - 1] = ' ';
		}
		else
			appendPQExpBufferStr(q, "* ");
		appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
						  fmtQualifiedDumpable(tbinfo),
						  tdinfo->filtercond ? tdinfo->filtercond : "");
	}
	else
	{
		appendPQExpBuffer(q, "COPY %s %s TO stdout;",
						  fmtQualifiedDumpable(tbinfo),
						  column_list);
	}
	res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
	PQclear(res);
	destroyPQExpBuffer(clistBuf);
	for (;;)
	{
		ret = PQgetCopyData(conn, &copybuf, 0);
		if (ret < 0)
			break;				
		if (copybuf)
		{
			WriteData(fout, copybuf, ret);
			PQfreemem(copybuf);
		}
	}
	archprintf(fout, "\\.\n\n\n");
	if (ret == -2)
	{
		pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
		pg_log_error("Error message from server: %s", PQerrorMessage(conn));
		pg_log_error("The command was: %s", q->data);
		exit_nicely(1);
	}
	res = PQgetResult(conn);
	if (PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
		pg_log_error("Error message from server: %s", PQerrorMessage(conn));
		pg_log_error("The command was: %s", q->data);
		exit_nicely(1);
	}
	PQclear(res);
	if (PQgetResult(conn) != NULL)
		pg_log_warning("unexpected extra results during COPY of table \"%s\"",
					   classname);
	destroyPQExpBuffer(q);
	return 1;
}
static int dumpTableData_copy ( Archive * fout , const void * dcontext ) { TableDataInfo * tdinfo = ( TableDataInfo * ) dcontext ; TableInfo * tbinfo = tdinfo -> tdtable ; const char * classname = tbinfo -> dobj . name ; PQExpBuffer q = createPQExpBuffer ( ) ; PQExpBuffer clistBuf = createPQExpBuffer ( ) ; PGconn * conn = GetConnection ( fout ) ; PGresult * res ; int ret ; char * copybuf ; const char * column_list ; pg_log_info ( " \" \" " , tbinfo -> dobj . namespace -> dobj . name , classname ) ; column_list = fmtCopyColumnList ( tbinfo , clistBuf ) ; if ( tdinfo -> filtercond || tbinfo -> relkind == RELKIND_FOREIGN_TABLE ) { appendPQExpBufferStr ( q , " " ) ; if ( strlen ( column_list ) > 2 ) { appendPQExpBufferStr ( q , column_list + 1 ) ; q -> data [ q -> len - 1 ] = ' ' ; } else appendPQExpBufferStr ( q , " " ) ; appendPQExpBuffer ( q , " " , fmtQualifiedDumpable ( tbinfo ) , tdinfo -> filtercond ? tdinfo -> filtercond : " " ) ; } else { appendPQExpBuffer ( q , " " , fmtQualifiedDumpable ( tbinfo ) , column_list ) ; } res = ExecuteSqlQuery ( fout , q -> data , PGRES_COPY_OUT ) ; PQclear ( res ) ; destroyPQExpBuffer ( clistBuf ) ; for ( ; ; ) { ret = PQgetCopyData ( conn , & copybuf , 0 ) ; if ( ret < 0 ) break ; if ( copybuf ) { WriteData ( fout , copybuf , ret ) ; PQfreemem ( copybuf ) ; } } archprintf ( fout , " \\ \n \n \n " ) ; if ( ret == -2 ) { pg_log_error ( " \" \" " , classname ) ; pg_log_error ( " " , PQerrorMessage ( conn ) ) ; pg_log_error ( " " , q -> data ) ; exit_nicely ( 1 ) ; } res = PQgetResult ( conn ) ; if ( PQresultStatus ( res ) != PGRES_COMMAND_OK ) { pg_log_error ( " \" \" " , classname ) ; pg_log_error ( " " , PQerrorMessage ( conn ) ) ; pg_log_error ( " " , q -> data ) ; exit_nicely ( 1 ) ; } PQclear ( res ) ; if ( PQgetResult ( conn ) != NULL ) pg_log_warning ( " \" \" " , classname ) ; destroyPQExpBuffer ( q ) ; return 1 ; }
Dump a table's contents for loading using the COPY command
      - this routine is called by the Archiver when it wants the table
        to be dumped.
Dump a table ' s contents for loading using the COPY command - this routine is called by the Archiver when it wants the table to be dumped .
/*
	 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
	 * which uses it already.
	 */ /*
	 * Specify the column list explicitly so that we have no 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.)
	 */ /*
	 * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
	 * a filter condition was specified.  For other cases a simple COPY
	 * suffices.
	 */ /* klugery to get rid of parens in column list */ /* done or error */ /* ----------
		 * THROTTLE:
		 *
		 * There was considerable discussion in late July, 2000 regarding
		 * slowing down pg_dump when backing up large tables. Users with both
		 * slow & fast (multi-processor) machines experienced performance
		 * degradation when doing a backup.
		 *
		 * Initial attempts based on sleeping for a number of ms for each ms
		 * of work were deemed too complex, then a simple 'sleep in each loop'
		 * implementation was suggested. The latter failed because the loop
		 * was too tight. Finally, the following was implemented:
		 *
		 * If throttle is non-zero, then
		 *		See how long since the last sleep.
		 *		Work out how long to sleep (based on ratio).
		 *		If sleep is more than 100ms, then
		 *			sleep
		 *			reset timer
		 *		EndIf
		 * EndIf
		 *
		 * where the throttle value was the number of ms to sleep per ms of
		 * work. The calculation was done in each loop.
		 *
		 * Most of the hard work is done in the backend, and this solution
		 * still did not work particularly well: on slow machines, the ratio
		 * was 50:1, and on medium paced machines, 1:1, and on fast
		 * multi-processor machines, it had little or no effect, for reasons
		 * that were unclear.
		 *
		 * Further discussion ensued, and the proposal was dropped.
		 *
		 * For those people who want this feature, it can be implemented using
		 * gettimeofday in each loop, calculating the time since last sleep,
		 * multiplying that by the sleep ratio, then if the result is more
		 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
		 * function to sleep for a subsecond period ie.
		 *
		 * select(0, NULL, NULL, NULL, &tvi);
		 *
		 * This will return after the interval specified in the structure tvi.
		 * Finally, call gettimeofday again to save the 'last sleep time'.
		 * ----------
		 */ /* copy data transfer failed */ /* Check command status and return to normal libpq state */ /* Do this to ensure we've pumped libpq back to idle state */