Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/interfaces/libpq/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 21 kB image not shown  

Quelle  fe-lobj.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * fe-lobj.c
 *   Front-end large object interface
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/interfaces/libpq/fe-lobj.c
 *
 *-------------------------------------------------------------------------
 */


#ifdef WIN32
/*
 * As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h
 * must be included first on MS C.  Might as well do it for all WIN32's
 * here.
 */

#include <io.h>
#endif

#include "postgres_fe.h"

#ifdef WIN32
#include "win32.h"
#else
#include <unistd.h>
#endif

#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>

#include "libpq-fe.h"
#include "libpq-int.h"
#include "libpq/libpq-fs.h"  /* must come after sys/stat.h */
#include "port/pg_bswap.h"

#define LO_BUFSIZE    8192

static int lo_initialize(PGconn *conn);
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
static int64_t lo_hton64(int64_t host64);
static int64_t lo_ntoh64(int64_t net64);

/*
 * lo_open
 *   opens an existing large object
 *
 * returns the file descriptor for use in later lo_* calls
 * return -1 upon failure.
 */

int
lo_open(PGconn *conn, Oid lobjId, int mode)
{
 int   fd;
 int   result_len;
 PQArgBlock argv[2];
 PGresult   *res;

 if (lo_initialize(conn) < 0)
  return -1;

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = lobjId;

 argv[1].isint = 1;
 argv[1].len = 4;
 argv[1].u.integer = mode;

 res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return fd;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_close
 *   closes an existing large object
 *
 * returns 0 upon success
 * returns -1 upon failure.
 */

int
lo_close(PGconn *conn, int fd)
{
 PQArgBlock argv[1];
 PGresult   *res;
 int   retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;
 res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
      &retval, &result_len, 1, argv, 1);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return retval;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_truncate
 *   truncates an existing large object to the given size
 *
 * returns 0 upon success
 * returns -1 upon failure
 */

int
lo_truncate(PGconn *conn, int fd, size_t len)
{
 PQArgBlock argv[2];
 PGresult   *res;
 int   retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 /* Must check this on-the-fly because it's not there pre-8.3 */
 if (conn->lobjfuncs->fn_lo_truncate == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_truncate");
  return -1;
 }

 /*
  * Long ago, somebody thought it'd be a good idea to declare this function
  * as taking size_t ... but the underlying backend function only accepts a
  * signed int32 length.  So throw error if the given value overflows
  * int32.  (A possible alternative is to automatically redirect the call
  * to lo_truncate64; but if the caller wanted to rely on that backend
  * function being available, he could have called lo_truncate64 for
  * himself.)
 */

 if (len > (size_t) INT_MAX)
 {
  libpq_append_conn_error(conn, "argument of lo_truncate exceeds integer range");
  return -1;
 }

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;

 argv[1].isint = 1;
 argv[1].len = 4;
 argv[1].u.integer = (int) len;

 res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,
      &retval, &result_len, 1, argv, 2);

 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return retval;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_truncate64
 *   truncates an existing large object to the given size
 *
 * returns 0 upon success
 * returns -1 upon failure
 */

int
lo_truncate64(PGconn *conn, int fd, int64_t len)
{
 PQArgBlock argv[2];
 PGresult   *res;
 int   retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 if (conn->lobjfuncs->fn_lo_truncate64 == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_truncate64");
  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;
 }
}

/*
 * lo_read
 *   read len bytes of the large object into buf
 *
 * returns the number of bytes read, or -1 on failure.
 * the CALLER must have allocated enough space to hold the result returned
 */


int
lo_read(PGconn *conn, int fd, char *buf, size_t len)
{
 PQArgBlock argv[2];
 PGresult   *res;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 /*
  * Long ago, somebody thought it'd be a good idea to declare this function
  * as taking size_t ... but the underlying backend function only accepts a
  * signed int32 length.  So throw error if the given value overflows
  * int32.
 */

 if (len > (size_t) INT_MAX)
 {
  libpq_append_conn_error(conn, "argument of lo_read exceeds integer range");
  return -1;
 }

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;

 argv[1].isint = 1;
 argv[1].len = 4;
 argv[1].u.integer = (int) len;

 res = PQnfn(conn, conn->lobjfuncs->fn_lo_read,
    (void *) buf, len, &result_len, 0, argv, 2);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return result_len;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_write
 *   write len bytes of buf into the large object fd
 *
 * returns the number of bytes written, or -1 on failure.
 */

int
lo_write(PGconn *conn, int fd, const char *buf, size_t len)
{
 PQArgBlock argv[2];
 PGresult   *res;
 int   result_len;
 int   retval;

 if (lo_initialize(conn) < 0)
  return -1;

 /*
  * Long ago, somebody thought it'd be a good idea to declare this function
  * as taking size_t ... but the underlying backend function only accepts a
  * signed int32 length.  So throw error if the given value overflows
  * int32.
 */

 if (len > (size_t) INT_MAX)
 {
  libpq_append_conn_error(conn, "argument of lo_write exceeds integer range");
  return -1;
 }

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;

 argv[1].isint = 0;
 argv[1].len = (int) len;
 argv[1].u.ptr = (int *) unconstify(char *, buf);

 res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
      &retval, &result_len, 1, argv, 2);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return retval;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_lseek
 *   change the current read or write location on a large object
 */

int
lo_lseek(PGconn *conn, int fd, int offset, int whence)
{
 PQArgBlock argv[3];
 PGresult   *res;
 int   retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;

 argv[1].isint = 1;
 argv[1].len = 4;
 argv[1].u.integer = offset;

 argv[2].isint = 1;
 argv[2].len = 4;
 argv[2].u.integer = whence;

 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
      &retval, &result_len, 1, argv, 3);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return retval;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_lseek64
 *   change the current read or write location on a large object
 */

int64_t
lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
{
 PQArgBlock argv[3];
 PGresult   *res;
 int64  retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 if (conn->lobjfuncs->fn_lo_lseek64 == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_lseek64");
  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 = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek64,
    (void *) &retval, sizeof(retval), &result_len, 0, argv, 3);
 if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
 {
  PQclear(res);
  return lo_ntoh64(retval);
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_creat
 *   create a new large object
 * the mode is ignored (once upon a time it had a use)
 *
 * returns the oid of the large object created or
 * InvalidOid upon failure
 */

Oid
lo_creat(PGconn *conn, int mode)
{
 PQArgBlock argv[1];
 PGresult   *res;
 int   retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return InvalidOid;

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = mode;
 res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
      &retval, &result_len, 1, argv, 1);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return (Oid) retval;
 }
 else
 {
  PQclear(res);
  return InvalidOid;
 }
}

/*
 * lo_create
 *   create a new large object
 * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create
 *
 * returns the oid of the large object created or
 * InvalidOid upon failure
 */

Oid
lo_create(PGconn *conn, Oid lobjId)
{
 PQArgBlock argv[1];
 PGresult   *res;
 int   retval;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return InvalidOid;

 /* Must check this on-the-fly because it's not there pre-8.1 */
 if (conn->lobjfuncs->fn_lo_create == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_create");
  return InvalidOid;
 }

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = lobjId;
 res = PQfn(conn, conn->lobjfuncs->fn_lo_create,
      &retval, &result_len, 1, argv, 1);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return (Oid) retval;
 }
 else
 {
  PQclear(res);
  return InvalidOid;
 }
}


/*
 * lo_tell
 *   returns the current seek location of the large object
 */

int
lo_tell(PGconn *conn, int fd)
{
 int   retval;
 PQArgBlock argv[1];
 PGresult   *res;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;

 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
      &retval, &result_len, 1, argv, 1);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return retval;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_tell64
 *   returns the current seek location of the large object
 */

int64_t
lo_tell64(PGconn *conn, int fd)
{
 int64  retval;
 PQArgBlock argv[1];
 PGresult   *res;
 int   result_len;

 if (lo_initialize(conn) < 0)
  return -1;

 if (conn->lobjfuncs->fn_lo_tell64 == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_tell64");
  return -1;
 }

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = fd;

 res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell64,
    (void *) &retval, sizeof(retval), &result_len, 0, argv, 1);
 if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
 {
  PQclear(res);
  return lo_ntoh64(retval);
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_unlink
 *   delete a file
 */


int
lo_unlink(PGconn *conn, Oid lobjId)
{
 PQArgBlock argv[1];
 PGresult   *res;
 int   result_len;
 int   retval;

 if (lo_initialize(conn) < 0)
  return -1;

 argv[0].isint = 1;
 argv[0].len = 4;
 argv[0].u.integer = lobjId;

 res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
      &retval, &result_len, 1, argv, 1);
 if (PQresultStatus(res) == PGRES_COMMAND_OK)
 {
  PQclear(res);
  return retval;
 }
 else
 {
  PQclear(res);
  return -1;
 }
}

/*
 * lo_import -
 *   imports a file as an (inversion) large object.
 *
 * returns the oid of that object upon success,
 * returns InvalidOid upon failure
 */


Oid
lo_import(PGconn *conn, const char *filename)
{
 return lo_import_internal(conn, filename, InvalidOid);
}

/*
 * lo_import_with_oid -
 *   imports a file as an (inversion) large object.
 *   large object id can be specified.
 *
 * returns the oid of that object upon success,
 * returns InvalidOid upon failure
 */


Oid
lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId)
{
 return lo_import_internal(conn, filename, lobjId);
}

static Oid
lo_import_internal(PGconn *conn, const char *filename, Oid oid)
{
 int   fd;
 int   nbytes,
    tmp;
 char  buf[LO_BUFSIZE];
 Oid   lobjOid;
 int   lobj;
 char  sebuf[PG_STRERROR_R_BUFLEN];

 if (conn == NULL)
  return InvalidOid;

 /* Since this is the beginning of a query cycle, reset the error state */
 pqClearConnErrorState(conn);

 /*
  * open the file to be read in
 */

 fd = open(filename, O_RDONLY | PG_BINARY, 0666);
 if (fd < 0)
 {       /* error */
  libpq_append_conn_error(conn, "could not open file \"%s\": %s",
        filename, strerror_r(errno, sebuf, sizeof(sebuf)));
  return InvalidOid;
 }

 /*
  * create an inversion object
 */

 if (oid == InvalidOid)
  lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
 else
  lobjOid = lo_create(conn, oid);

 if (lobjOid == InvalidOid)
 {
  /* we assume lo_create() already set a suitable error message */
  (void) close(fd);
  return InvalidOid;
 }

 lobj = lo_open(conn, lobjOid, INV_WRITE);
 if (lobj == -1)
 {
  /* we assume lo_open() already set a suitable error message */
  (void) close(fd);
  return InvalidOid;
 }

 /*
  * read in from the file and write to the large object
 */

 while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
 {
  tmp = lo_write(conn, lobj, buf, nbytes);
  if (tmp != nbytes)
  {
   /*
    * If lo_write() failed, we are now in an aborted transaction so
    * there's no need for lo_close(); furthermore, if we tried it
    * we'd overwrite the useful error result with a useless one. So
    * just nail the doors shut and get out of town.
 */

   (void) close(fd);
   return InvalidOid;
  }
 }

 if (nbytes < 0)
 {
  /* We must do lo_close before setting the errorMessage */
  int   save_errno = errno;

  (void) lo_close(conn, lobj);
  (void) close(fd);
  /* deliberately overwrite any error from lo_close */
  pqClearConnErrorState(conn);
  libpq_append_conn_error(conn, "could not read from file \"%s\": %s",
        filename,
        strerror_r(save_errno, sebuf, sizeof(sebuf)));
  return InvalidOid;
 }

 (void) close(fd);

 if (lo_close(conn, lobj) != 0)
 {
  /* we assume lo_close() already set a suitable error message */
  return InvalidOid;
 }

 return lobjOid;
}

/*
 * lo_export -
 *   exports an (inversion) large object.
 * returns -1 upon failure, 1 if OK
 */

int
lo_export(PGconn *conn, Oid lobjId, const char *filename)
{
 int   result = 1;
 int   fd;
 int   nbytes,
    tmp;
 char  buf[LO_BUFSIZE];
 int   lobj;
 char  sebuf[PG_STRERROR_R_BUFLEN];

 /*
  * open the large object.
 */

 lobj = lo_open(conn, lobjId, INV_READ);
 if (lobj == -1)
 {
  /* we assume lo_open() already set a suitable error message */
  return -1;
 }

 /*
  * create the file to be written to
 */

 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
 if (fd < 0)
 {
  /* We must do lo_close before setting the errorMessage */
  int   save_errno = errno;

  (void) lo_close(conn, lobj);
  /* deliberately overwrite any error from lo_close */
  pqClearConnErrorState(conn);
  libpq_append_conn_error(conn, "could not open file \"%s\": %s",
        filename,
        strerror_r(save_errno, sebuf, sizeof(sebuf)));
  return -1;
 }

 /*
  * read in from the large object and write to the file
 */

 while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
 {
  tmp = write(fd, buf, nbytes);
  if (tmp != nbytes)
  {
   /* We must do lo_close before setting the errorMessage */
   int   save_errno = errno;

   (void) lo_close(conn, lobj);
   (void) close(fd);
   /* deliberately overwrite any error from lo_close */
   pqClearConnErrorState(conn);
   libpq_append_conn_error(conn, "could not write to file \"%s\": %s",
         filename,
         strerror_r(save_errno, sebuf, sizeof(sebuf)));
   return -1;
  }
 }

 /*
  * If lo_read() failed, we are now in an aborted transaction so there's no
  * need for lo_close(); furthermore, if we tried it we'd overwrite the
  * useful error result with a useless one. So skip lo_close() if we got a
  * failure result.
 */

 if (nbytes < 0 ||
  lo_close(conn, lobj) != 0)
 {
  /* assume lo_read() or lo_close() left a suitable error message */
  result = -1;
 }

 /* if we already failed, don't overwrite that msg with a close error */
 if (close(fd) != 0 && result >= 0)
 {
  libpq_append_conn_error(conn, "could not write to file \"%s\": %s",
        filename, strerror_r(errno, sebuf, sizeof(sebuf)));
  result = -1;
 }

 return result;
}


/*
 * lo_initialize
 *
 * Initialize for a new large-object operation on an existing connection.
 * Return 0 if OK, -1 on failure.
 *
 * If we haven't previously done so, we collect the function OIDs from
 * pg_proc for all functions that are required for large object operations.
 */

static int
lo_initialize(PGconn *conn)
{
 PGresult   *res;
 PGlobjfuncs *lobjfuncs;
 int   n;
 const char *query;
 const char *fname;
 Oid   foid;

 /* Nothing we can do with no connection */
 if (conn == NULL)
  return -1;

 /* Since this is the beginning of a query cycle, reset the error state */
 pqClearConnErrorState(conn);

 /* Nothing else to do if we already collected info */
 if (conn->lobjfuncs != NULL)
  return 0;

 /*
  * Allocate the structure to hold the function OIDs.  We don't store it
  * into the PGconn until it's successfully filled.
 */

 lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
 if (lobjfuncs == NULL)
 {
  libpq_append_conn_error(conn, "out of memory");
  return -1;
 }
 MemSet(lobjfuncs, 0sizeof(PGlobjfuncs));

 /*
  * Execute the query to get all the functions at once.  (Not all of them
  * may exist in older server versions.)
 */

 query = "select proname, oid from pg_catalog.pg_proc "
  "where proname in ("
  "'lo_open', "
  "'lo_close', "
  "'lo_creat', "
  "'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 "
  "where nspname = 'pg_catalog')";

 res = PQexec(conn, query);
 if (res == NULL)
 {
  free(lobjfuncs);
  return -1;
 }

 if (res->resultStatus != PGRES_TUPLES_OK)
 {
  free(lobjfuncs);
  PQclear(res);
  libpq_append_conn_error(conn, "query to initialize large object functions did not return data");
  return -1;
 }

 /*
  * Examine the result and put the OID's into the struct
 */

 for (n = 0; n < PQntuples(res); n++)
 {
  fname = PQgetvalue(res, n, 0);
  foid = (Oid) atoi(PQgetvalue(res, n, 1));
  if (strcmp(fname, "lo_open") == 0)
   lobjfuncs->fn_lo_open = foid;
  else if (strcmp(fname, "lo_close") == 0)
   lobjfuncs->fn_lo_close = foid;
  else if (strcmp(fname, "lo_creat") == 0)
   lobjfuncs->fn_lo_creat = foid;
  else if (strcmp(fname, "lo_create") == 0)
   lobjfuncs->fn_lo_create = foid;
  else if (strcmp(fname, "lo_unlink") == 0)
   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)
   lobjfuncs->fn_lo_write = foid;
 }

 PQclear(res);

 /*
  * Finally check that we got all required large object interface functions
  * (ones that have been added later than the stone age are instead checked
  * only if used)
 */

 if (lobjfuncs->fn_lo_open == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_open");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_close == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_close");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_creat == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_creat");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_unlink == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_unlink");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_lseek == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_lseek");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_tell == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lo_tell");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_read == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "loread");
  free(lobjfuncs);
  return -1;
 }
 if (lobjfuncs->fn_lo_write == 0)
 {
  libpq_append_conn_error(conn, "cannot determine OID of function %s",
        "lowrite");
  free(lobjfuncs);
  return -1;
 }

 /*
  * Put the structure into the connection control
 */

 conn->lobjfuncs = lobjfuncs;
 return 0;
}

/*
 * lo_hton64
 *   converts a 64-bit integer from host byte order to network byte order
 */

static int64_t
lo_hton64(int64_t host64)
{
 union
 {
  int64  i64;
  uint32  i32[2];
 }   swap;
 uint32  t;

 /* High order half first, since we're doing MSB-first */
 t = (uint32) (host64 >> 32);
 swap.i32[0] = pg_hton32(t);

 /* Now the low order half */
 t = (uint32) host64;
 swap.i32[1] = pg_hton32(t);

 return swap.i64;
}

/*
 * lo_ntoh64
 *   converts a 64-bit integer from network byte order to host byte order
 */

static int64_t
lo_ntoh64(int64_t net64)
{
 union
 {
  int64  i64;
  uint32  i32[2];
 }   swap;
 int64  result;

 swap.i64 = net64;

 result = (uint32) pg_ntoh32(swap.i32[0]);
 result <<= 32;
 result |= (uint32) pg_ntoh32(swap.i32[1]);

 return result;
}

Messung V0.5 in Prozent
C=95 H=98 G=96

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-08-06) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.