aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-lobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpq/fe-lobj.c')
-rw-r--r--src/interfaces/libpq/fe-lobj.c239
1 files changed, 238 insertions, 1 deletions
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index f3a6d0341c1..fb17ac8b1e9 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -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
@@ -311,6 +370,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
* the mode is ignored (once upon a time it had a use)
@@ -436,6 +552,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;
+}