src/bin/pg_dump/pg_dump.c
static int
dumpTableData_insert(Archive *fout, const void *dcontext)
{
	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
	TableInfo  *tbinfo = tdinfo->tdtable;
	DumpOptions *dopt = fout->dopt;
	PQExpBuffer q = createPQExpBuffer();
	PQExpBuffer insertStmt = NULL;
	char	   *attgenerated;
	PGresult   *res;
	int			nfields,
				i;
	int			rows_per_statement = dopt->dump_inserts;
	int			rows_this_statement = 0;

	/*
	 * If we're going to emit INSERTs with column names, the most efficient
	 * way to deal with generated columns is to exclude them entirely.  For
	 * INSERTs without column names, we have to emit DEFAULT rather than the
	 * actual column value --- but we can save a few cycles by fetching nulls
	 * rather than the uninteresting-to-us value.
	 */
	attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
	appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
	nfields = 0;
	for (i = 0; i < tbinfo->numatts; i++)
	{
		if (tbinfo->attisdropped[i])
			continue;
		if (tbinfo->attgenerated[i] && dopt->column_inserts)
			continue;
		if (nfields > 0)
			appendPQExpBufferStr(q, ", ");
		if (tbinfo->attgenerated[i])
			appendPQExpBufferStr(q, "NULL");
		else
			appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
		attgenerated[nfields] = tbinfo->attgenerated[i];
		nfields++;
	}
	/* Servers before 9.4 will complain about zero-column SELECT */
	if (nfields == 0)
		appendPQExpBufferStr(q, "NULL");
	appendPQExpBuffer(q, " FROM ONLY %s",
					  fmtQualifiedDumpable(tbinfo));
	if (tdinfo->filtercond)
		appendPQExpBuffer(q, " %s", tdinfo->filtercond);

	ExecuteSqlStatement(fout, q->data);

	while (1)
	{
		res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
							  PGRES_TUPLES_OK);

		/* cross-check field count, allowing for dummy NULL if any */
		if (nfields != PQnfields(res) &&
			!(nfields == 0 && PQnfields(res) == 1))
			fatal("wrong number of fields retrieved from table \"%s\"",
				  tbinfo->dobj.name);

		/*
		 * First time through, we build as much of the INSERT statement as
		 * possible in "insertStmt", which we can then just print for each
		 * statement. If the table happens to have zero dumpable columns then
		 * this will be a complete statement, otherwise it will end in
		 * "VALUES" and be ready to have the row's column values printed.
		 */
		if (insertStmt == NULL)
		{
			TableInfo  *targettab;

			insertStmt = createPQExpBuffer();

			/*
			 * When load-via-partition-root is set, get the root table name
			 * for the partition table, so that we can reload data through the
			 * root table.
			 */
			if (dopt->load_via_partition_root && tbinfo->ispartition)
				targettab = getRootTableInfo(tbinfo);
			else
				targettab = tbinfo;

			appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
							  fmtQualifiedDumpable(targettab));

			/* corner case for zero-column table */
			if (nfields == 0)
			{
				appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
			}
			else
			{
				/* append the list of column names if required */
				if (dopt->column_inserts)
				{
					appendPQExpBufferChar(insertStmt, '(');
					for (int field = 0; field < nfields; field++)
					{
						if (field > 0)
							appendPQExpBufferStr(insertStmt, ", ");
						appendPQExpBufferStr(insertStmt,
											 fmtId(PQfname(res, field)));
					}
					appendPQExpBufferStr(insertStmt, ") ");
				}

				if (tbinfo->needs_override)
					appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");

				appendPQExpBufferStr(insertStmt, "VALUES");
			}
		}

		for (int tuple = 0; tuple < PQntuples(res); tuple++)
		{
			/* Write the INSERT if not in the middle of a multi-row INSERT. */
			if (rows_this_statement == 0)
				archputs(insertStmt->data, fout);

			/*
			 * If it is zero-column table then we've already written the
			 * complete statement, which will mean we've disobeyed
			 * --rows-per-insert when it's set greater than 1.  We do support
			 * a way to make this multi-row with: SELECT UNION ALL SELECT
			 * UNION ALL ... but that's non-standard so we should avoid it
			 * given that using INSERTs is mostly only ever needed for
			 * cross-database exports.
			 */
			if (nfields == 0)
				continue;

			/* Emit a row heading */
			if (rows_per_statement == 1)
				archputs(" (", fout);
			else if (rows_this_statement > 0)
				archputs(",\n\t(", fout);
			else
				archputs("\n\t(", fout);

			for (int field = 0; field < nfields; field++)
			{
				if (field > 0)
					archputs(", ", fout);
				if (attgenerated[field])
				{
					archputs("DEFAULT", fout);
					continue;
				}
				if (PQgetisnull(res, tuple, field))
				{
					archputs("NULL", fout);
					continue;
				}

				/* XXX This code is partially duplicated in ruleutils.c */
				switch (PQftype(res, field))
				{
					case INT2OID:
					case INT4OID:
					case INT8OID:
					case OIDOID:
					case FLOAT4OID:
					case FLOAT8OID:
					case NUMERICOID:
						{
							/*
							 * These types are printed without quotes unless
							 * they contain values that aren't accepted by the
							 * scanner unquoted (e.g., 'NaN').  Note that
							 * strtod() and friends might accept NaN, so we
							 * can't use that to test.
							 *
							 * In reality we only need to defend against
							 * infinity and NaN, so we need not get too crazy
							 * about pattern matching here.
							 */
							const char *s = PQgetvalue(res, tuple, field);

							if (strspn(s, "0123456789 +-eE.") == strlen(s))
								archputs(s, fout);
							else
								archprintf(fout, "'%s'", s);
						}
						break;

					case BITOID:
					case VARBITOID:
						archprintf(fout, "B'%s'",
								   PQgetvalue(res, tuple, field));
						break;

					case BOOLOID:
						if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
							archputs("true", fout);
						else
							archputs("false", fout);
						break;

					default:
						/* All other types are printed as string literals. */
						resetPQExpBuffer(q);
						appendStringLiteralAH(q,
											  PQgetvalue(res, tuple, field),
											  fout);
						archputs(q->data, fout);
						break;
				}
			}

			/* Terminate the row ... */
			archputs(")", fout);

			/* ... and the statement, if the target no. of rows is reached */
			if (++rows_this_statement >= rows_per_statement)
			{
				if (dopt->do_nothing)
					archputs(" ON CONFLICT DO NOTHING;\n", fout);
				else
					archputs(";\n", fout);
				/* Reset the row counter */
				rows_this_statement = 0;
			}
		}

		if (PQntuples(res) <= 0)
		{
			PQclear(res);
			break;
		}
		PQclear(res);
	}

	/* Terminate any statements that didn't make the row count. */
	if (rows_this_statement > 0)
	{
		if (dopt->do_nothing)
			archputs(" ON CONFLICT DO NOTHING;\n", fout);
		else
			archputs(";\n", fout);
	}

	archputs("\n\n", fout);

	ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");

	destroyPQExpBuffer(q);
	if (insertStmt != NULL)
		destroyPQExpBuffer(insertStmt);
	free(attgenerated);

	return 1;
}
/*
 * Dump table data using INSERT commands.
 *
 * Caution: when we restore from an archive file direct to database, the
 * INSERT commands emitted by this function have to be parsed by
 * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
 * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
 */
Dump table data using INSERT commands.
Caution: when we restore from an archive file direct to database, the
INSERT commands emitted by this function have to be parsed by
pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
E'' strings, or dollar-quoted strings.  So don't emit anything like that.
Dump table data using INSERT commands . Caution : when we restore from an archive file direct to database the INSERT commands emitted by this function have to be parsed by pg_backup_db . c ' s ExecuteSimpleCommands () which will not handle comments E ' ' strings or dollar - quoted strings . So don ' t emit anything like that .
static int
dumpTableData_insert(Archive *fout, const void *dcontext)
{
	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
	TableInfo  *tbinfo = tdinfo->tdtable;
	DumpOptions *dopt = fout->dopt;
	PQExpBuffer q = createPQExpBuffer();
	PQExpBuffer insertStmt = NULL;
	char	   *attgenerated;
	PGresult   *res;
	int			nfields,
				i;
	int			rows_per_statement = dopt->dump_inserts;
	int			rows_this_statement = 0;
	attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
	appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
	nfields = 0;
	for (i = 0; i < tbinfo->numatts; i++)
	{
		if (tbinfo->attisdropped[i])
			continue;
		if (tbinfo->attgenerated[i] && dopt->column_inserts)
			continue;
		if (nfields > 0)
			appendPQExpBufferStr(q, ", ");
		if (tbinfo->attgenerated[i])
			appendPQExpBufferStr(q, "NULL");
		else
			appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
		attgenerated[nfields] = tbinfo->attgenerated[i];
		nfields++;
	}
	if (nfields == 0)
		appendPQExpBufferStr(q, "NULL");
	appendPQExpBuffer(q, " FROM ONLY %s",
					  fmtQualifiedDumpable(tbinfo));
	if (tdinfo->filtercond)
		appendPQExpBuffer(q, " %s", tdinfo->filtercond);
	ExecuteSqlStatement(fout, q->data);
	while (1)
	{
		res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
							  PGRES_TUPLES_OK);
		if (nfields != PQnfields(res) &&
			!(nfields == 0 && PQnfields(res) == 1))
			fatal("wrong number of fields retrieved from table \"%s\"",
				  tbinfo->dobj.name);
		if (insertStmt == NULL)
		{
			TableInfo  *targettab;
			insertStmt = createPQExpBuffer();
			if (dopt->load_via_partition_root && tbinfo->ispartition)
				targettab = getRootTableInfo(tbinfo);
			else
				targettab = tbinfo;
			appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
							  fmtQualifiedDumpable(targettab));
			if (nfields == 0)
			{
				appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
			}
			else
			{
				if (dopt->column_inserts)
				{
					appendPQExpBufferChar(insertStmt, '(');
					for (int field = 0; field < nfields; field++)
					{
						if (field > 0)
							appendPQExpBufferStr(insertStmt, ", ");
						appendPQExpBufferStr(insertStmt,
											 fmtId(PQfname(res, field)));
					}
					appendPQExpBufferStr(insertStmt, ") ");
				}
				if (tbinfo->needs_override)
					appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
				appendPQExpBufferStr(insertStmt, "VALUES");
			}
		}
		for (int tuple = 0; tuple < PQntuples(res); tuple++)
		{
			if (rows_this_statement == 0)
				archputs(insertStmt->data, fout);
			if (nfields == 0)
				continue;
			if (rows_per_statement == 1)
				archputs(" (", fout);
			else if (rows_this_statement > 0)
				archputs(",\n\t(", fout);
			else
				archputs("\n\t(", fout);
			for (int field = 0; field < nfields; field++)
			{
				if (field > 0)
					archputs(", ", fout);
				if (attgenerated[field])
				{
					archputs("DEFAULT", fout);
					continue;
				}
				if (PQgetisnull(res, tuple, field))
				{
					archputs("NULL", fout);
					continue;
				}
				switch (PQftype(res, field))
				{
					case INT2OID:
					case INT4OID:
					case INT8OID:
					case OIDOID:
					case FLOAT4OID:
					case FLOAT8OID:
					case NUMERICOID:
						{
							const char *s = PQgetvalue(res, tuple, field);
							if (strspn(s, "0123456789 +-eE.") == strlen(s))
								archputs(s, fout);
							else
								archprintf(fout, "'%s'", s);
						}
						break;
					case BITOID:
					case VARBITOID:
						archprintf(fout, "B'%s'",
								   PQgetvalue(res, tuple, field));
						break;
					case BOOLOID:
						if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
							archputs("true", fout);
						else
							archputs("false", fout);
						break;
					default:
						resetPQExpBuffer(q);
						appendStringLiteralAH(q,
											  PQgetvalue(res, tuple, field),
											  fout);
						archputs(q->data, fout);
						break;
				}
			}
			archputs(")", fout);
			if (++rows_this_statement >= rows_per_statement)
			{
				if (dopt->do_nothing)
					archputs(" ON CONFLICT DO NOTHING;\n", fout);
				else
					archputs(";\n", fout);
				rows_this_statement = 0;
			}
		}
		if (PQntuples(res) <= 0)
		{
			PQclear(res);
			break;
		}
		PQclear(res);
	}
	if (rows_this_statement > 0)
	{
		if (dopt->do_nothing)
			archputs(" ON CONFLICT DO NOTHING;\n", fout);
		else
			archputs(";\n", fout);
	}
	archputs("\n\n", fout);
	ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
	destroyPQExpBuffer(q);
	if (insertStmt != NULL)
		destroyPQExpBuffer(insertStmt);
	free(attgenerated);
	return 1;
}
static int dumpTableData_insert ( Archive * fout , const void * dcontext ) { TableDataInfo * tdinfo = ( TableDataInfo * ) dcontext ; TableInfo * tbinfo = tdinfo -> tdtable ; DumpOptions * dopt = fout -> dopt ; PQExpBuffer q = createPQExpBuffer ( ) ; PQExpBuffer insertStmt = NULL ; char * attgenerated ; PGresult * res ; int nfields , i ; int rows_per_statement = dopt -> dump_inserts ; int rows_this_statement = 0 ; attgenerated = ( char * ) pg_malloc ( tbinfo -> numatts * sizeof ( char ) ) ; appendPQExpBufferStr ( q , " " ) ; nfields = 0 ; for ( i = 0 ; i < tbinfo -> numatts ; i ++ ) { if ( tbinfo -> attisdropped [ i ] ) continue ; if ( tbinfo -> attgenerated [ i ] && dopt -> column_inserts ) continue ; if ( nfields > 0 ) appendPQExpBufferStr ( q , " " ) ; if ( tbinfo -> attgenerated [ i ] ) appendPQExpBufferStr ( q , " " ) ; else appendPQExpBufferStr ( q , fmtId ( tbinfo -> attnames [ i ] ) ) ; attgenerated [ nfields ] = tbinfo -> attgenerated [ i ] ; nfields ++ ; } if ( nfields == 0 ) appendPQExpBufferStr ( q , " " ) ; appendPQExpBuffer ( q , " " , fmtQualifiedDumpable ( tbinfo ) ) ; if ( tdinfo -> filtercond ) appendPQExpBuffer ( q , " " , tdinfo -> filtercond ) ; ExecuteSqlStatement ( fout , q -> data ) ; while ( 1 ) { res = ExecuteSqlQuery ( fout , " " , PGRES_TUPLES_OK ) ; if ( nfields != PQnfields ( res ) && ! ( nfields == 0 && PQnfields ( res ) == 1 ) ) fatal ( " \" \" " , tbinfo -> dobj . name ) ; if ( insertStmt == NULL ) { TableInfo * targettab ; insertStmt = createPQExpBuffer ( ) ; if ( dopt -> load_via_partition_root && tbinfo -> ispartition ) targettab = getRootTableInfo ( tbinfo ) ; else targettab = tbinfo ; appendPQExpBuffer ( insertStmt , " " , fmtQualifiedDumpable ( targettab ) ) ; if ( nfields == 0 ) { appendPQExpBufferStr ( insertStmt , " \n " ) ; } else { if ( dopt -> column_inserts ) { appendPQExpBufferChar ( insertStmt , ' ' ) ; for ( int field = 0 ; field < nfields ; field ++ ) { if ( field > 0 ) appendPQExpBufferStr ( insertStmt , " " ) ; appendPQExpBufferStr ( insertStmt , fmtId ( PQfname ( res , field ) ) ) ; } appendPQExpBufferStr ( insertStmt , " " ) ; } if ( tbinfo -> needs_override ) appendPQExpBufferStr ( insertStmt , " " ) ; appendPQExpBufferStr ( insertStmt , " " ) ; } } for ( int tuple = 0 ; tuple < PQntuples ( res ) ; tuple ++ ) { if ( rows_this_statement == 0 ) archputs ( insertStmt -> data , fout ) ; if ( nfields == 0 ) continue ; if ( rows_per_statement == 1 ) archputs ( " " , fout ) ; else if ( rows_this_statement > 0 ) archputs ( " \n \t " , fout ) ; else archputs ( " \n \t " , fout ) ; for ( int field = 0 ; field < nfields ; field ++ ) { if ( field > 0 ) archputs ( " " , fout ) ; if ( attgenerated [ field ] ) { archputs ( " " , fout ) ; continue ; } if ( PQgetisnull ( res , tuple , field ) ) { archputs ( " " , fout ) ; continue ; } switch ( PQftype ( res , field ) ) { case INT2OID : case INT4OID : case INT8OID : case OIDOID : case FLOAT4OID : case FLOAT8OID : case NUMERICOID : { const char * s = PQgetvalue ( res , tuple , field ) ; if ( strspn ( s , " " ) == strlen ( s ) ) archputs ( s , fout ) ; else archprintf ( fout , " " , s ) ; } break ; case BITOID : case VARBITOID : archprintf ( fout , " " , PQgetvalue ( res , tuple , field ) ) ; break ; case BOOLOID : if ( strcmp ( PQgetvalue ( res , tuple , field ) , " " ) == 0 ) archputs ( " " , fout ) ; else archputs ( " " , fout ) ; break ; default : resetPQExpBuffer ( q ) ; appendStringLiteralAH ( q , PQgetvalue ( res , tuple , field ) , fout ) ; archputs ( q -> data , fout ) ; break ; } } archputs ( " " , fout ) ; if ( ++ rows_this_statement >= rows_per_statement ) { if ( dopt -> do_nothing ) archputs ( " \n " , fout ) ; else archputs ( " \n " , fout ) ; rows_this_statement = 0 ; } } if ( PQntuples ( res ) <= 0 ) { PQclear ( res ) ; break ; } PQclear ( res ) ; } if ( rows_this_statement > 0 ) { if ( dopt -> do_nothing ) archputs ( " \n " , fout ) ; else archputs ( " \n " , fout ) ; } archputs ( " \n \n " , fout ) ; ExecuteSqlStatement ( fout , " " ) ; destroyPQExpBuffer ( q ) ; if ( insertStmt != NULL ) destroyPQExpBuffer ( insertStmt ) ; free ( attgenerated ) ; return 1 ; }
Dump table data using INSERT commands.
Dump table data using INSERT commands .
/*
	 * If we're going to emit INSERTs with column names, the most efficient
	 * way to deal with generated columns is to exclude them entirely.  For
	 * INSERTs without column names, we have to emit DEFAULT rather than the
	 * actual column value --- but we can save a few cycles by fetching nulls
	 * rather than the uninteresting-to-us value.
	 */ /* Servers before 9.4 will complain about zero-column SELECT */ /* cross-check field count, allowing for dummy NULL if any */ /*
		 * First time through, we build as much of the INSERT statement as
		 * possible in "insertStmt", which we can then just print for each
		 * statement. If the table happens to have zero dumpable columns then
		 * this will be a complete statement, otherwise it will end in
		 * "VALUES" and be ready to have the row's column values printed.
		 */ /*
			 * When load-via-partition-root is set, get the root table name
			 * for the partition table, so that we can reload data through the
			 * root table.
			 */ /* corner case for zero-column table */ /* append the list of column names if required */ /* Write the INSERT if not in the middle of a multi-row INSERT. */ /*
			 * If it is zero-column table then we've already written the
			 * complete statement, which will mean we've disobeyed
			 * --rows-per-insert when it's set greater than 1.  We do support
			 * a way to make this multi-row with: SELECT UNION ALL SELECT
			 * UNION ALL ... but that's non-standard so we should avoid it
			 * given that using INSERTs is mostly only ever needed for
			 * cross-database exports.
			 */ /* Emit a row heading */ /* XXX This code is partially duplicated in ruleutils.c */ /*
							 * These types are printed without quotes unless
							 * they contain values that aren't accepted by the
							 * scanner unquoted (e.g., 'NaN').  Note that
							 * strtod() and friends might accept NaN, so we
							 * can't use that to test.
							 *
							 * In reality we only need to defend against
							 * infinity and NaN, so we need not get too crazy
							 * about pattern matching here.
							 */ /* All other types are printed as string literals. */ /* Terminate the row ... */ /* ... and the statement, if the target no. of rows is reached */ /* Reset the row counter */ /* Terminate any statements that didn't make the row count. */