mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Add API for 64-bit large object access. Now users can access up to
4TB large objects (standard 8KB BLCKSZ case). For this purpose new libpq API lo_lseek64, lo_tell64 and lo_truncate64 are added. Also corresponding new backend functions lo_lseek64, lo_tell64 and lo_truncate64 are added. inv_api.c is changed to handle 64-bit offsets. Patch contributed by Nozomi Anzai (backend side) and Yugo Nagata (frontend side, docs, regression tests and example program). Reviewed by Kohei Kaigai. Committed by Tatsuo Ishii with minor editings.
This commit is contained in:
@ -161,3 +161,6 @@ PQping 158
|
||||
PQpingParams 159
|
||||
PQlibVersion 160
|
||||
PQsetSingleRowMode 161
|
||||
lo_lseek64 162
|
||||
lo_tell64 163
|
||||
lo_truncate64 164
|
||||
|
@ -37,10 +37,16 @@
|
||||
#include "libpq-int.h"
|
||||
#include "libpq/libpq-fs.h" /* must come after sys/stat.h */
|
||||
|
||||
/* for ntohl/htonl */
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define LO_BUFSIZE 8192
|
||||
|
||||
static int lo_initialize(PGconn *conn);
|
||||
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
|
||||
static pg_int64 lo_hton64(pg_int64 host64);
|
||||
static pg_int64 lo_ntoh64(pg_int64 net64);
|
||||
|
||||
/*
|
||||
* lo_open
|
||||
@ -174,6 +180,59 @@ lo_truncate(PGconn *conn, int fd, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_truncate64
|
||||
* truncates an existing large object to the given size
|
||||
*
|
||||
* returns 0 upon success
|
||||
* returns -1 upon failure
|
||||
*/
|
||||
#ifdef HAVE_PG_INT64
|
||||
int
|
||||
lo_truncate64(PGconn *conn, int fd, pg_int64 len)
|
||||
{
|
||||
PQArgBlock argv[2];
|
||||
PGresult *res;
|
||||
int retval;
|
||||
int result_len;
|
||||
|
||||
if (conn == NULL || conn->lobjfuncs == NULL)
|
||||
{
|
||||
if (lo_initialize(conn) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->lobjfuncs->fn_lo_truncate64 == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_truncate64\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
argv[0].isint = 1;
|
||||
argv[0].len = 4;
|
||||
argv[0].u.integer = fd;
|
||||
|
||||
len = lo_hton64(len);
|
||||
argv[1].isint = 0;
|
||||
argv[1].len = 8;
|
||||
argv[1].u.ptr = (int *) &len;
|
||||
|
||||
res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,
|
||||
&retval, &result_len, 1, argv, 2);
|
||||
|
||||
if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
PQclear(res);
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
PQclear(res);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lo_read
|
||||
@ -310,6 +369,63 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_lseek64
|
||||
* change the current read or write location on a large object
|
||||
* currently, only L_SET is a legal value for whence
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_PG_INT64
|
||||
pg_int64
|
||||
lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
|
||||
{
|
||||
PQArgBlock argv[3];
|
||||
PGresult *res;
|
||||
pg_int64 retval;
|
||||
int result_len;
|
||||
|
||||
if (conn == NULL || conn->lobjfuncs == NULL)
|
||||
{
|
||||
if (lo_initialize(conn) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->lobjfuncs->fn_lo_lseek64 == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_lseek64\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
argv[0].isint = 1;
|
||||
argv[0].len = 4;
|
||||
argv[0].u.integer = fd;
|
||||
|
||||
offset = lo_hton64(offset);
|
||||
argv[1].isint = 0;
|
||||
argv[1].len = 8;
|
||||
argv[1].u.ptr = (int *) &offset;
|
||||
|
||||
argv[2].isint = 1;
|
||||
argv[2].len = 4;
|
||||
argv[2].u.integer = whence;
|
||||
|
||||
res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
|
||||
(int *)&retval, &result_len, 0, argv, 3);
|
||||
if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
PQclear(res);
|
||||
return lo_ntoh64((pg_int64)retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
PQclear(res);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lo_creat
|
||||
* create a new large object
|
||||
@ -435,6 +551,52 @@ lo_tell(PGconn *conn, int fd)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_tell64
|
||||
* returns the current seek location of the large object
|
||||
*
|
||||
*/
|
||||
#ifdef HAVE_PG_INT64
|
||||
pg_int64
|
||||
lo_tell64(PGconn *conn, int fd)
|
||||
{
|
||||
pg_int64 retval;
|
||||
PQArgBlock argv[1];
|
||||
PGresult *res;
|
||||
int result_len;
|
||||
|
||||
if (conn == NULL || conn->lobjfuncs == NULL)
|
||||
{
|
||||
if (lo_initialize(conn) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->lobjfuncs->fn_lo_tell64 == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_tell64\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
argv[0].isint = 1;
|
||||
argv[0].len = 4;
|
||||
argv[0].u.integer = fd;
|
||||
|
||||
res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64,
|
||||
(int *) &retval, &result_len, 0, argv, 1);
|
||||
if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
PQclear(res);
|
||||
return lo_ntoh64((pg_int64) retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
PQclear(res);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lo_unlink
|
||||
* delete a file
|
||||
@ -713,8 +875,11 @@ lo_initialize(PGconn *conn)
|
||||
"'lo_create', "
|
||||
"'lo_unlink', "
|
||||
"'lo_lseek', "
|
||||
"'lo_lseek64', "
|
||||
"'lo_tell', "
|
||||
"'lo_tell64', "
|
||||
"'lo_truncate', "
|
||||
"'lo_truncate64', "
|
||||
"'loread', "
|
||||
"'lowrite') "
|
||||
"and pronamespace = (select oid from pg_catalog.pg_namespace "
|
||||
@ -765,10 +930,16 @@ lo_initialize(PGconn *conn)
|
||||
lobjfuncs->fn_lo_unlink = foid;
|
||||
else if (strcmp(fname, "lo_lseek") == 0)
|
||||
lobjfuncs->fn_lo_lseek = foid;
|
||||
else if (strcmp(fname, "lo_lseek64") == 0)
|
||||
lobjfuncs->fn_lo_lseek64 = foid;
|
||||
else if (strcmp(fname, "lo_tell") == 0)
|
||||
lobjfuncs->fn_lo_tell = foid;
|
||||
else if (strcmp(fname, "lo_tell64") == 0)
|
||||
lobjfuncs->fn_lo_tell64 = foid;
|
||||
else if (strcmp(fname, "lo_truncate") == 0)
|
||||
lobjfuncs->fn_lo_truncate = foid;
|
||||
else if (strcmp(fname, "lo_truncate64") == 0)
|
||||
lobjfuncs->fn_lo_truncate64 = foid;
|
||||
else if (strcmp(fname, "loread") == 0)
|
||||
lobjfuncs->fn_lo_read = foid;
|
||||
else if (strcmp(fname, "lowrite") == 0)
|
||||
@ -836,10 +1007,76 @@ lo_initialize(PGconn *conn)
|
||||
free(lobjfuncs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->sversion >= 90300)
|
||||
{
|
||||
if (lobjfuncs->fn_lo_lseek64 == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_lseek64\n"));
|
||||
free(lobjfuncs);
|
||||
return -1;
|
||||
}
|
||||
if (lobjfuncs->fn_lo_tell64 == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_tell64\n"));
|
||||
free(lobjfuncs);
|
||||
return -1;
|
||||
}
|
||||
if (lobjfuncs->fn_lo_truncate64 == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_truncate64\n"));
|
||||
free(lobjfuncs);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Put the structure into the connection control
|
||||
*/
|
||||
conn->lobjfuncs = lobjfuncs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_hton64
|
||||
* converts an 64-bit integer from host byte order to network byte order
|
||||
*/
|
||||
static pg_int64
|
||||
lo_hton64(pg_int64 host64)
|
||||
{
|
||||
pg_int64 result;
|
||||
uint32_t h32, l32;
|
||||
|
||||
/* High order half first, since we're doing MSB-first */
|
||||
h32 = (uint32_t) (host64 >> 32);
|
||||
|
||||
/* Now the low order half */
|
||||
l32 = (uint32_t) (host64 & 0xffffffff);
|
||||
|
||||
result = htonl(l32);
|
||||
result <<= 32;
|
||||
result |= htonl(h32);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_ntoh64
|
||||
* converts an 64-bit integer from network byte order to host byte order
|
||||
*/
|
||||
static pg_int64
|
||||
lo_ntoh64(pg_int64 net64)
|
||||
{
|
||||
pg_int64 result;
|
||||
uint32_t h32, l32;
|
||||
|
||||
l32 = (uint32_t) (net64 >> 32);
|
||||
h32 = (uint32_t) (net64 & 0xffffffff);
|
||||
|
||||
result = ntohl(h32);
|
||||
result <<= 32;
|
||||
result |= ntohl(l32);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -548,6 +548,12 @@ extern Oid lo_import(PGconn *conn, const char *filename);
|
||||
extern Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId);
|
||||
extern int lo_export(PGconn *conn, Oid lobjId, const char *filename);
|
||||
|
||||
#ifdef HAVE_PG_INT64
|
||||
extern pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence);
|
||||
extern pg_int64 lo_tell64(PGconn *conn, int fd);
|
||||
extern int lo_truncate64(PGconn *conn, int fd, pg_int64 len);
|
||||
#endif
|
||||
|
||||
/* === in fe-misc.c === */
|
||||
|
||||
/* Get the version of the libpq library in use */
|
||||
|
@ -271,8 +271,11 @@ typedef struct pgLobjfuncs
|
||||
Oid fn_lo_create; /* OID of backend function lo_create */
|
||||
Oid fn_lo_unlink; /* OID of backend function lo_unlink */
|
||||
Oid fn_lo_lseek; /* OID of backend function lo_lseek */
|
||||
Oid fn_lo_lseek64; /* OID of backend function lo_lseek64 */
|
||||
Oid fn_lo_tell; /* OID of backend function lo_tell */
|
||||
Oid fn_lo_tell64; /* OID of backend function lo_tell64 */
|
||||
Oid fn_lo_truncate; /* OID of backend function lo_truncate */
|
||||
Oid fn_lo_truncate64; /* OID of backend function lo_truncate64 */
|
||||
Oid fn_lo_read; /* OID of backend function LOread */
|
||||
Oid fn_lo_write; /* OID of backend function LOwrite */
|
||||
} PGlobjfuncs;
|
||||
|
Reference in New Issue
Block a user