diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c index c4afe4d368a..1d1efcd139b 100644 --- a/src/backend/storage/file/buffile.c +++ b/src/backend/storage/file/buffile.c @@ -419,8 +419,10 @@ BufFileClose(BufFile *file) /* close and delete the underlying file(s) */ for (i = 0; i < file->numFiles; i++) FileClose(file->files[i]); - /* release the buffer space */ + /* release the buffer space and other metadata */ pfree(file->files); + if (file->name) + pfree((void *) file->name); pfree(file); } @@ -883,10 +885,10 @@ BufFileSize(BufFile *file) /* * Append the contents of the source file to the end of the target file. * - * Note that operation subsumes ownership of underlying resources from - * "source". Caller should never call BufFileClose against source having - * called here first. Resource owners for source and target must match, - * too. + * Note that this operation subsumes ownership of underlying resources from + * "source", and frees the source wrapper and metadata before returning. + * Callers must not reference source after this call. Resource owners for + * source and target must match, too. * * This operation works by manipulating lists of segment files, so the * file content is always appended at a MAX_PHYSICAL_FILESIZE-aligned @@ -907,6 +909,7 @@ BufFileAppend(BufFile *target, BufFile *source) Assert(source->readOnly); Assert(!source->dirty); + Assert(target != source); if (target->resowner != source->resowner) elog(ERROR, "could not append BufFile with non-matching resource owner"); @@ -917,6 +920,15 @@ BufFileAppend(BufFile *target, BufFile *source) target->files[i] = source->files[i - target->numFiles]; target->numFiles = newNumFiles; + /* + * The underlying files now belong to target. Free only source's wrapper + * and metadata, leaving the transferred file handles open. + */ + if (source->name) + pfree((void *) source->name); + pfree(source->files); + pfree(source); + return startBlock; }