On 7/2/20 5:37 PM, Tom Lane wrote: > Joe Conway <[email protected]> writes: >> In fact, in principle there is no reason we can't get to max - 4 with this >> code >> except that when the filesize is exactly 1073741819, we need to try to read >> one >> more byte to find the EOF that way I did in my patch. I.e.: > > Ah, right, *that* is where the extra byte is lost: we need a buffer > workspace one byte more than the file size, or we won't ever actually > see the EOF indication. > > I still can't get excited about contorting the code to remove that > issue.
It doesn't seem much worse than the oom test that was there before -- see attached. In any case I will give you the last word and then quit bugging you about it ;-) Are we in agreement that whatever gets pushed should be backpatched through pg11 (see start of thread)? Joe -- Crunchy Data - http://crunchydata.com PostgreSQL Support for Secure Enterprises Consulting, Training, & Open Source Development
diff --git a/contrib/adminpack/expected/adminpack.out b/contrib/adminpack/expected/adminpack.out
index 5738b0f..edf3ebf 100644
*** a/contrib/adminpack/expected/adminpack.out
--- b/contrib/adminpack/expected/adminpack.out
*************** SELECT pg_file_rename('test_file1', 'tes
*** 79,85 ****
(1 row)
SELECT pg_read_file('test_file1'); -- not there
! ERROR: could not stat file "test_file1": No such file or directory
SELECT pg_read_file('test_file2');
pg_read_file
--------------
--- 79,85 ----
(1 row)
SELECT pg_read_file('test_file1'); -- not there
! ERROR: could not open file "test_file1" for reading: No such file or directory
SELECT pg_read_file('test_file2');
pg_read_file
--------------
*************** SELECT pg_file_rename('test_file2', 'tes
*** 108,114 ****
(1 row)
SELECT pg_read_file('test_file2'); -- not there
! ERROR: could not stat file "test_file2": No such file or directory
SELECT pg_read_file('test_file3');
pg_read_file
--------------
--- 108,114 ----
(1 row)
SELECT pg_read_file('test_file2'); -- not there
! ERROR: could not open file "test_file2" for reading: No such file or directory
SELECT pg_read_file('test_file3');
pg_read_file
--------------
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index ceaa618..32a5eab 100644
*** a/src/backend/utils/adt/genfile.c
--- b/src/backend/utils/adt/genfile.c
*************** read_binary_file(const char *filename, i
*** 106,138 ****
bool missing_ok)
{
bytea *buf;
! size_t nbytes;
FILE *file;
! if (bytes_to_read < 0)
! {
! if (seek_offset < 0)
! bytes_to_read = -seek_offset;
! else
! {
! struct stat fst;
!
! if (stat(filename, &fst) < 0)
! {
! if (missing_ok && errno == ENOENT)
! return NULL;
! else
! ereport(ERROR,
! (errcode_for_file_access(),
! errmsg("could not stat file \"%s\": %m", filename)));
! }
!
! bytes_to_read = fst.st_size - seek_offset;
! }
! }
!
! /* not sure why anyone thought that int64 length was a good idea */
! if (bytes_to_read > (MaxAllocSize - VARHDRSZ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("requested length too large")));
--- 106,116 ----
bool missing_ok)
{
bytea *buf;
! size_t nbytes = 0;
FILE *file;
! /* clamp request size to what we can actually deliver */
! if (bytes_to_read > (int64) (MaxAllocSize - VARHDRSZ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("requested length too large")));
*************** read_binary_file(const char *filename, i
*** 154,162 ****
(errcode_for_file_access(),
errmsg("could not seek in file \"%s\": %m", filename)));
! buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);
! nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
if (ferror(file))
ereport(ERROR,
--- 132,199 ----
(errcode_for_file_access(),
errmsg("could not seek in file \"%s\": %m", filename)));
! if (bytes_to_read >= 0)
! {
! /* If passed explicit read size just do it */
! buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);
! nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
! }
! else
! {
! /* Negative read size, read rest of file */
! StringInfoData sbuf;
!
! initStringInfo(&sbuf);
! /* Leave room in the buffer for the varlena length word */
! sbuf.len += VARHDRSZ;
! Assert(sbuf.len < sbuf.maxlen);
!
! while (!(feof(file) || ferror(file)))
! {
! size_t rbytes;
!
! /* Minimum amount to read at a time */
! #define MIN_READ_SIZE 4096
!
! /*
! * If not at end of file, and sbuf.len is equal to
! * MaxAllocSize - 1, then either the file is too large, or
! * there is nothing left to read. Attempt to read one more
! * byte to see if the end of file has been reached. If not,
! * the file is too large; we'd rather give the error message
! * for that ourselves.
! */
! if (sbuf.len == MaxAllocSize - 1)
! {
! char rbuf[1];
!
! fread(rbuf, 1, 1, file);
! if (!feof(file))
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! errmsg("requested length too large")));
! else
! break;
! }
!
! /* OK, ensure that we can read at least MIN_READ_SIZE */
! enlargeStringInfo(&sbuf, MIN_READ_SIZE);
!
! /*
! * stringinfo.c likes to allocate in powers of 2, so it's likely
! * that much more space is available than we asked for. Use all
! * of it, rather than making more fread calls than necessary.
! */
! rbytes = fread(sbuf.data + sbuf.len, 1,
! (size_t) (sbuf.maxlen - sbuf.len - 1), file);
! sbuf.len += rbytes;
! nbytes += rbytes;
! }
!
! /* Now we can commandeer the stringinfo's buffer as the result */
! buf = (bytea *) sbuf.data;
! }
if (ferror(file))
ereport(ERROR,
signature.asc
Description: OpenPGP digital signature
