Hi, When exporting data with psql -c "..." >file or select ... \g file inside psql, post-creation output errors are silently ignored. The problem can be seen easily by creating a small ramdisk and filling it over capacity:
$ sudo mount -t tmpfs -o rw,size =1M tmpfs /mnt/ramdisk $ psql -d postgres -At \ -c "select repeat('abc', 1000000)" > /mnt/ramdisk/file $ echo $? 0 $ ls -l /mnt/ramdisk/file -rw-r--r-- 1 daniel daniel 1048576 Dec 16 15:57 /mnt/ramdisk/file $ df -h /mnt/ramdisk/ Filesystem Size Used Avail Use% Mounted on tmpfs 1.0M 1.0M 0 100% /mnt/ramdisk The output that should be 3M byte long is truncated as expected, but we got no error message and no error code from psql, which is obviously not nice. The reason is that PrintQuery() and the code below it in fe_utils/print.c call puts(), putc(), fprintf(),... without checking their return values or the result of ferror() on the output stream. If we made them do that and had the printing bail out at the first error, that would be a painful change, since there are a lot of such calls: $ egrep -w '(fprintf|fputs|fputc)' fe_utils/print.c | wc -l 326 and the call sites are in functions that have no error reporting paths anyway. To start the discussion, here's a minimal patch that checks ferror() in PrintQueryTuples() to raise an error when the printing is done (better late than never). The error message is generic as opposed to using errno, as I don't know whether errno has been clobbered at this point. OTOH, I think that the error indicator on the output stream is not cleared by successful writes after some other previous writes have failed. Are there opinions on whether this should be addressed simply like in the attached, or a large refactoring of print.c to bail out at the first error would be better, or other ideas on how to proceed? Best regards, -- Daniel Vérité PostgreSQL-powered mailer: http://www.manitou-mail.org Twitter: @DanielVerite
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 9c0d53689e..993484d092 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -718,6 +718,7 @@ static bool PrintQueryTuples(const PGresult *results) { printQueryOpt my_popt = pset.popt; + bool result = true; /* one-shot expanded output requested via \gx */ if (pset.g_expanded) @@ -736,6 +737,12 @@ PrintQueryTuples(const PGresult *results) printQuery(results, &my_popt, fout, false, pset.logfile); + if (ferror(fout)) + { + pg_log_error("Error printing tuples"); + result = false; + } + if (is_pipe) { pclose(fout); @@ -745,9 +752,16 @@ PrintQueryTuples(const PGresult *results) fclose(fout); } else + { printQuery(results, &my_popt, pset.queryFout, false, pset.logfile); + if (ferror(pset.queryFout)) + { + pg_log_error("Error printing tuples"); + result = false; + } + } - return true; + return result; }