diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c index fdb4198154e..e90907bd380 100644 --- a/src/bin/pg_rewind/libpq_fetch.c +++ b/src/bin/pg_rewind/libpq_fetch.c @@ -195,7 +195,7 @@ libpqProcessFileList(void) for (i = 0; i < PQntuples(res); i++) { char *path = PQgetvalue(res, i, 0); - int filesize = atoi(PQgetvalue(res, i, 1)); + int64 filesize = atol(PQgetvalue(res, i, 1)); bool isdir = (strcmp(PQgetvalue(res, i, 2), "t") == 0); char *link_target = PQgetvalue(res, i, 3); file_type_t type; @@ -221,13 +221,35 @@ libpqProcessFileList(void) PQclear(res); } +/* + * Converts an int64 from network byte order to native format. + */ +static int64 +pg_recvint64(int64 value) +{ + union + { + int64 i64; + uint32 i32[2]; + } swap; + int64 result; + + swap.i64 = value; + + result = (uint32) ntohl(swap.i32[0]); + result <<= 32; + result |= (uint32) ntohl(swap.i32[1]); + + return result; +} + /*---- * Runs a query, which returns pieces of files from the remote source data * directory, and overwrites the corresponding parts of target files with * the received parts. The result set is expected to be of format: * * path text -- path in the data directory, e.g "base/1/123" - * begin int4 -- offset within the file + * begin int8 -- offset within the file * chunk bytea -- file content *---- */ @@ -248,7 +270,7 @@ receiveFileChunks(const char *sql) { char *filename; int filenamelen; - int chunkoff; + int64 chunkoff; int chunksize; char *chunk; @@ -271,7 +293,7 @@ receiveFileChunks(const char *sql) pg_fatal("unexpected result set size while fetching remote files\n"); if (PQftype(res, 0) != TEXTOID || - PQftype(res, 1) != INT4OID || + PQftype(res, 1) != INT8OID || PQftype(res, 2) != BYTEAOID) { pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u\n", @@ -291,12 +313,12 @@ receiveFileChunks(const char *sql) pg_fatal("unexpected null values in result while fetching remote files\n"); } - if (PQgetlength(res, 0, 1) != sizeof(int32)) + if (PQgetlength(res, 0, 1) != sizeof(int64)) pg_fatal("unexpected result length while fetching remote files\n"); /* Read result set to local variables */ - memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int32)); - chunkoff = ntohl(chunkoff); + memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int64)); + chunkoff = pg_recvint64(chunkoff); chunksize = PQgetlength(res, 0, 2); filenamelen = PQgetlength(res, 0, 0); @@ -321,7 +343,7 @@ receiveFileChunks(const char *sql) continue; } - pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %d, size %d\n", + pg_log(PG_DEBUG, "received chunk for file \"%s\", offset " INT64_FORMAT ", size %d\n", filename, chunkoff, chunksize); open_target_file(filename, false); @@ -381,7 +403,7 @@ libpqGetFile(const char *filename, size_t *filesize) * function to actually fetch the data. */ static void -fetch_file_range(const char *path, unsigned int begin, unsigned int end) +fetch_file_range(const char *path, uint64 begin, uint64 end) { char linebuf[MAXPGPATH + 23]; @@ -390,12 +412,13 @@ fetch_file_range(const char *path, unsigned int begin, unsigned int end) { unsigned int len; + /* Fine as long as CHUNKSIZE is not bigger than UINT32_MAX */ if (end - begin > CHUNKSIZE) len = CHUNKSIZE; else - len = end - begin; + len = (unsigned int) (end - begin); - snprintf(linebuf, sizeof(linebuf), "%s\t%u\t%u\n", path, begin, len); + snprintf(linebuf, sizeof(linebuf), "%s\t" UINT64_FORMAT "\t%u\n", path, begin, len); if (PQputCopyData(conn, linebuf, strlen(linebuf)) != 1) pg_fatal("could not send COPY data: %s", @@ -420,7 +443,7 @@ libpq_executeFileMap(filemap_t *map) * First create a temporary table, and load it with the blocks that we * need to fetch. */ - sql = "CREATE TEMPORARY TABLE fetchchunks(path text, begin int4, len int4);"; + sql = "CREATE TEMPORARY TABLE fetchchunks(path text, begin int8, len int4);"; res = PQexec(conn, sql); if (PQresultStatus(res) != PGRES_COMMAND_OK)