diff options
Diffstat (limited to 'src/backend/utils/adt/genfile.c')
-rw-r--r-- | src/backend/utils/adt/genfile.c | 128 |
1 files changed, 105 insertions, 23 deletions
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index e8a36edcd4d..e9212500c23 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -80,15 +80,14 @@ convert_and_check_filename(text *arg) /* - * Read a section of a file, returning it as text + * Read a section of a file, returning it as bytea + * + * We read the whole of the file when bytes_to_read is nagative. */ -Datum -pg_read_file(PG_FUNCTION_ARGS) +static bytea * +read_binary_file(text *filename_t, int64 seek_offset, int64 bytes_to_read) { - text *filename_t = PG_GETARG_TEXT_P(0); - int64 seek_offset = PG_GETARG_INT64(1); - int64 bytes_to_read = PG_GETARG_INT64(2); - char *buf; + bytea *buf; size_t nbytes; FILE *file; char *filename; @@ -100,6 +99,29 @@ pg_read_file(PG_FUNCTION_ARGS) filename = convert_and_check_filename(filename_t); + if (bytes_to_read < 0) + { + if (seek_offset < 0) + bytes_to_read = -seek_offset; + else + { + struct stat fst; + + if (stat(filename, &fst) < 0) + 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"))); + if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) ereport(ERROR, (errcode_for_file_access(), @@ -112,18 +134,7 @@ pg_read_file(PG_FUNCTION_ARGS) (errcode_for_file_access(), errmsg("could not seek in file \"%s\": %m", filename))); - if (bytes_to_read < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("requested length cannot be negative"))); - - /* 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"))); - - buf = palloc((Size) bytes_to_read + VARHDRSZ); + buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ); nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file); @@ -132,15 +143,86 @@ pg_read_file(PG_FUNCTION_ARGS) (errcode_for_file_access(), errmsg("could not read file \"%s\": %m", filename))); - /* Make sure the input is valid */ - pg_verifymbstr(VARDATA(buf), nbytes, false); - SET_VARSIZE(buf, nbytes + VARHDRSZ); FreeFile(file); pfree(filename); - PG_RETURN_TEXT_P(buf); + return buf; +} + +/* + * In addition to read_binary_file, verify whether the contents are encoded + * in the database encoding. + */ +static text * +read_text_file(text *filename, int64 seek_offset, int64 bytes_to_read) +{ + bytea *buf = read_binary_file(filename, seek_offset, bytes_to_read); + + /* Make sure the input is valid */ + pg_verifymbstr(VARDATA(buf), VARSIZE(buf) - VARHDRSZ, false); + + /* OK, we can cast it as text safely */ + return (text *) buf; +} + +/* + * Read a section of a file, returning it as text + */ +Datum +pg_read_file(PG_FUNCTION_ARGS) +{ + text *filename_t = PG_GETARG_TEXT_P(0); + int64 seek_offset = PG_GETARG_INT64(1); + int64 bytes_to_read = PG_GETARG_INT64(2); + + if (bytes_to_read < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("requested length cannot be negative"))); + + PG_RETURN_TEXT_P(read_text_file(filename_t, seek_offset, bytes_to_read)); +} + +/* + * Read the whole of a file, returning it as text + */ +Datum +pg_read_file_all(PG_FUNCTION_ARGS) +{ + text *filename_t = PG_GETARG_TEXT_P(0); + + PG_RETURN_TEXT_P(read_text_file(filename_t, 0, -1)); +} + +/* + * Read a section of a file, returning it as bytea + */ +Datum +pg_read_binary_file(PG_FUNCTION_ARGS) +{ + text *filename_t = PG_GETARG_TEXT_P(0); + int64 seek_offset = PG_GETARG_INT64(1); + int64 bytes_to_read = PG_GETARG_INT64(2); + + if (bytes_to_read < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("requested length cannot be negative"))); + + PG_RETURN_BYTEA_P(read_binary_file(filename_t, seek_offset, bytes_to_read)); +} + +/* + * Read the whole of a file, returning it as bytea + */ +Datum +pg_read_binary_file_all(PG_FUNCTION_ARGS) +{ + text *filename_t = PG_GETARG_TEXT_P(0); + + PG_RETURN_BYTEA_P(read_binary_file(filename_t, 0, -1)); } /* |