LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-lobj.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 153 394 38.8 %
Date: 2021-12-04 22:09:09 Functions: 10 20 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * fe-lobj.c
       4             :  *    Front-end large object interface
       5             :  *
       6             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/interfaces/libpq/fe-lobj.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #ifdef WIN32
      17             : /*
      18             :  *  As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h
      19             :  *  must be included first on MS C.  Might as well do it for all WIN32's
      20             :  *  here.
      21             :  */
      22             : #include <io.h>
      23             : #endif
      24             : 
      25             : #include "postgres_fe.h"
      26             : 
      27             : #ifdef WIN32
      28             : #include "win32.h"
      29             : #else
      30             : #include <unistd.h>
      31             : #endif
      32             : 
      33             : #include <fcntl.h>
      34             : #include <limits.h>
      35             : #include <sys/stat.h>
      36             : 
      37             : #include "libpq-fe.h"
      38             : #include "libpq-int.h"
      39             : #include "libpq/libpq-fs.h"       /* must come after sys/stat.h */
      40             : #include "port/pg_bswap.h"
      41             : 
      42             : #define LO_BUFSIZE        8192
      43             : 
      44             : static int  lo_initialize(PGconn *conn);
      45             : static Oid  lo_import_internal(PGconn *conn, const char *filename, Oid oid);
      46             : static pg_int64 lo_hton64(pg_int64 host64);
      47             : static pg_int64 lo_ntoh64(pg_int64 net64);
      48             : 
      49             : /*
      50             :  * lo_open
      51             :  *    opens an existing large object
      52             :  *
      53             :  * returns the file descriptor for use in later lo_* calls
      54             :  * return -1 upon failure.
      55             :  */
      56             : int
      57          68 : lo_open(PGconn *conn, Oid lobjId, int mode)
      58             : {
      59             :     int         fd;
      60             :     int         result_len;
      61             :     PQArgBlock  argv[2];
      62             :     PGresult   *res;
      63             : 
      64          68 :     if (lo_initialize(conn) < 0)
      65           0 :         return -1;
      66             : 
      67          68 :     argv[0].isint = 1;
      68          68 :     argv[0].len = 4;
      69          68 :     argv[0].u.integer = lobjId;
      70             : 
      71          68 :     argv[1].isint = 1;
      72          68 :     argv[1].len = 4;
      73          68 :     argv[1].u.integer = mode;
      74             : 
      75          68 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
      76          68 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
      77             :     {
      78          68 :         PQclear(res);
      79          68 :         return fd;
      80             :     }
      81             :     else
      82             :     {
      83           0 :         PQclear(res);
      84           0 :         return -1;
      85             :     }
      86             : }
      87             : 
      88             : /*
      89             :  * lo_close
      90             :  *    closes an existing large object
      91             :  *
      92             :  * returns 0 upon success
      93             :  * returns -1 upon failure.
      94             :  */
      95             : int
      96          68 : lo_close(PGconn *conn, int fd)
      97             : {
      98             :     PQArgBlock  argv[1];
      99             :     PGresult   *res;
     100             :     int         retval;
     101             :     int         result_len;
     102             : 
     103          68 :     if (lo_initialize(conn) < 0)
     104           0 :         return -1;
     105             : 
     106          68 :     argv[0].isint = 1;
     107          68 :     argv[0].len = 4;
     108          68 :     argv[0].u.integer = fd;
     109          68 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
     110             :                &retval, &result_len, 1, argv, 1);
     111          68 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     112             :     {
     113          68 :         PQclear(res);
     114          68 :         return retval;
     115             :     }
     116             :     else
     117             :     {
     118           0 :         PQclear(res);
     119           0 :         return -1;
     120             :     }
     121             : }
     122             : 
     123             : /*
     124             :  * lo_truncate
     125             :  *    truncates an existing large object to the given size
     126             :  *
     127             :  * returns 0 upon success
     128             :  * returns -1 upon failure
     129             :  */
     130             : int
     131           0 : lo_truncate(PGconn *conn, int fd, size_t len)
     132             : {
     133             :     PQArgBlock  argv[2];
     134             :     PGresult   *res;
     135             :     int         retval;
     136             :     int         result_len;
     137             : 
     138           0 :     if (lo_initialize(conn) < 0)
     139           0 :         return -1;
     140             : 
     141             :     /* Must check this on-the-fly because it's not there pre-8.3 */
     142           0 :     if (conn->lobjfuncs->fn_lo_truncate == 0)
     143             :     {
     144           0 :         appendPQExpBuffer(&conn->errorMessage,
     145           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     146             :                           "lo_truncate");
     147           0 :         return -1;
     148             :     }
     149             : 
     150             :     /*
     151             :      * Long ago, somebody thought it'd be a good idea to declare this function
     152             :      * as taking size_t ... but the underlying backend function only accepts a
     153             :      * signed int32 length.  So throw error if the given value overflows
     154             :      * int32.  (A possible alternative is to automatically redirect the call
     155             :      * to lo_truncate64; but if the caller wanted to rely on that backend
     156             :      * function being available, he could have called lo_truncate64 for
     157             :      * himself.)
     158             :      */
     159           0 :     if (len > (size_t) INT_MAX)
     160             :     {
     161           0 :         appendPQExpBufferStr(&conn->errorMessage,
     162           0 :                              libpq_gettext("argument of lo_truncate exceeds integer range\n"));
     163           0 :         return -1;
     164             :     }
     165             : 
     166           0 :     argv[0].isint = 1;
     167           0 :     argv[0].len = 4;
     168           0 :     argv[0].u.integer = fd;
     169             : 
     170           0 :     argv[1].isint = 1;
     171           0 :     argv[1].len = 4;
     172           0 :     argv[1].u.integer = (int) len;
     173             : 
     174           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,
     175             :                &retval, &result_len, 1, argv, 2);
     176             : 
     177           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     178             :     {
     179           0 :         PQclear(res);
     180           0 :         return retval;
     181             :     }
     182             :     else
     183             :     {
     184           0 :         PQclear(res);
     185           0 :         return -1;
     186             :     }
     187             : }
     188             : 
     189             : /*
     190             :  * lo_truncate64
     191             :  *    truncates an existing large object to the given size
     192             :  *
     193             :  * returns 0 upon success
     194             :  * returns -1 upon failure
     195             :  */
     196             : int
     197           0 : lo_truncate64(PGconn *conn, int fd, pg_int64 len)
     198             : {
     199             :     PQArgBlock  argv[2];
     200             :     PGresult   *res;
     201             :     int         retval;
     202             :     int         result_len;
     203             : 
     204           0 :     if (lo_initialize(conn) < 0)
     205           0 :         return -1;
     206             : 
     207           0 :     if (conn->lobjfuncs->fn_lo_truncate64 == 0)
     208             :     {
     209           0 :         appendPQExpBuffer(&conn->errorMessage,
     210           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     211             :                           "lo_truncate64");
     212           0 :         return -1;
     213             :     }
     214             : 
     215           0 :     argv[0].isint = 1;
     216           0 :     argv[0].len = 4;
     217           0 :     argv[0].u.integer = fd;
     218             : 
     219           0 :     len = lo_hton64(len);
     220           0 :     argv[1].isint = 0;
     221           0 :     argv[1].len = 8;
     222           0 :     argv[1].u.ptr = (int *) &len;
     223             : 
     224           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,
     225             :                &retval, &result_len, 1, argv, 2);
     226             : 
     227           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     228             :     {
     229           0 :         PQclear(res);
     230           0 :         return retval;
     231             :     }
     232             :     else
     233             :     {
     234           0 :         PQclear(res);
     235           0 :         return -1;
     236             :     }
     237             : }
     238             : 
     239             : /*
     240             :  * lo_read
     241             :  *    read len bytes of the large object into buf
     242             :  *
     243             :  * returns the number of bytes read, or -1 on failure.
     244             :  * the CALLER must have allocated enough space to hold the result returned
     245             :  */
     246             : 
     247             : int
     248         436 : lo_read(PGconn *conn, int fd, char *buf, size_t len)
     249             : {
     250             :     PQArgBlock  argv[2];
     251             :     PGresult   *res;
     252             :     int         result_len;
     253             : 
     254         436 :     if (lo_initialize(conn) < 0)
     255           0 :         return -1;
     256             : 
     257             :     /*
     258             :      * Long ago, somebody thought it'd be a good idea to declare this function
     259             :      * as taking size_t ... but the underlying backend function only accepts a
     260             :      * signed int32 length.  So throw error if the given value overflows
     261             :      * int32.
     262             :      */
     263         436 :     if (len > (size_t) INT_MAX)
     264             :     {
     265           0 :         appendPQExpBufferStr(&conn->errorMessage,
     266           0 :                              libpq_gettext("argument of lo_read exceeds integer range\n"));
     267           0 :         return -1;
     268             :     }
     269             : 
     270         436 :     argv[0].isint = 1;
     271         436 :     argv[0].len = 4;
     272         436 :     argv[0].u.integer = fd;
     273             : 
     274         436 :     argv[1].isint = 1;
     275         436 :     argv[1].len = 4;
     276         436 :     argv[1].u.integer = (int) len;
     277             : 
     278         436 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
     279             :                (void *) buf, &result_len, 0, argv, 2);
     280         436 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     281             :     {
     282         436 :         PQclear(res);
     283         436 :         return result_len;
     284             :     }
     285             :     else
     286             :     {
     287           0 :         PQclear(res);
     288           0 :         return -1;
     289             :     }
     290             : }
     291             : 
     292             : /*
     293             :  * lo_write
     294             :  *    write len bytes of buf into the large object fd
     295             :  *
     296             :  * returns the number of bytes written, or -1 on failure.
     297             :  */
     298             : int
     299         658 : lo_write(PGconn *conn, int fd, const char *buf, size_t len)
     300             : {
     301             :     PQArgBlock  argv[2];
     302             :     PGresult   *res;
     303             :     int         result_len;
     304             :     int         retval;
     305             : 
     306         658 :     if (lo_initialize(conn) < 0)
     307           0 :         return -1;
     308             : 
     309             :     /*
     310             :      * Long ago, somebody thought it'd be a good idea to declare this function
     311             :      * as taking size_t ... but the underlying backend function only accepts a
     312             :      * signed int32 length.  So throw error if the given value overflows
     313             :      * int32.
     314             :      */
     315         658 :     if (len > (size_t) INT_MAX)
     316             :     {
     317           0 :         appendPQExpBufferStr(&conn->errorMessage,
     318           0 :                              libpq_gettext("argument of lo_write exceeds integer range\n"));
     319           0 :         return -1;
     320             :     }
     321             : 
     322         658 :     argv[0].isint = 1;
     323         658 :     argv[0].len = 4;
     324         658 :     argv[0].u.integer = fd;
     325             : 
     326         658 :     argv[1].isint = 0;
     327         658 :     argv[1].len = (int) len;
     328         658 :     argv[1].u.ptr = (int *) unconstify(char *, buf);
     329             : 
     330         658 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
     331             :                &retval, &result_len, 1, argv, 2);
     332         658 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     333             :     {
     334         658 :         PQclear(res);
     335         658 :         return retval;
     336             :     }
     337             :     else
     338             :     {
     339           0 :         PQclear(res);
     340           0 :         return -1;
     341             :     }
     342             : }
     343             : 
     344             : /*
     345             :  * lo_lseek
     346             :  *    change the current read or write location on a large object
     347             :  */
     348             : int
     349           0 : lo_lseek(PGconn *conn, int fd, int offset, int whence)
     350             : {
     351             :     PQArgBlock  argv[3];
     352             :     PGresult   *res;
     353             :     int         retval;
     354             :     int         result_len;
     355             : 
     356           0 :     if (lo_initialize(conn) < 0)
     357           0 :         return -1;
     358             : 
     359           0 :     argv[0].isint = 1;
     360           0 :     argv[0].len = 4;
     361           0 :     argv[0].u.integer = fd;
     362             : 
     363           0 :     argv[1].isint = 1;
     364           0 :     argv[1].len = 4;
     365           0 :     argv[1].u.integer = offset;
     366             : 
     367           0 :     argv[2].isint = 1;
     368           0 :     argv[2].len = 4;
     369           0 :     argv[2].u.integer = whence;
     370             : 
     371           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
     372             :                &retval, &result_len, 1, argv, 3);
     373           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     374             :     {
     375           0 :         PQclear(res);
     376           0 :         return retval;
     377             :     }
     378             :     else
     379             :     {
     380           0 :         PQclear(res);
     381           0 :         return -1;
     382             :     }
     383             : }
     384             : 
     385             : /*
     386             :  * lo_lseek64
     387             :  *    change the current read or write location on a large object
     388             :  */
     389             : pg_int64
     390           0 : lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
     391             : {
     392             :     PQArgBlock  argv[3];
     393             :     PGresult   *res;
     394             :     pg_int64    retval;
     395             :     int         result_len;
     396             : 
     397           0 :     if (lo_initialize(conn) < 0)
     398           0 :         return -1;
     399             : 
     400           0 :     if (conn->lobjfuncs->fn_lo_lseek64 == 0)
     401             :     {
     402           0 :         appendPQExpBuffer(&conn->errorMessage,
     403           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     404             :                           "lo_lseek64");
     405           0 :         return -1;
     406             :     }
     407             : 
     408           0 :     argv[0].isint = 1;
     409           0 :     argv[0].len = 4;
     410           0 :     argv[0].u.integer = fd;
     411             : 
     412           0 :     offset = lo_hton64(offset);
     413           0 :     argv[1].isint = 0;
     414           0 :     argv[1].len = 8;
     415           0 :     argv[1].u.ptr = (int *) &offset;
     416             : 
     417           0 :     argv[2].isint = 1;
     418           0 :     argv[2].len = 4;
     419           0 :     argv[2].u.integer = whence;
     420             : 
     421           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
     422             :                (void *) &retval, &result_len, 0, argv, 3);
     423           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
     424             :     {
     425           0 :         PQclear(res);
     426           0 :         return lo_ntoh64(retval);
     427             :     }
     428             :     else
     429             :     {
     430           0 :         PQclear(res);
     431           0 :         return -1;
     432             :     }
     433             : }
     434             : 
     435             : /*
     436             :  * lo_creat
     437             :  *    create a new large object
     438             :  * the mode is ignored (once upon a time it had a use)
     439             :  *
     440             :  * returns the oid of the large object created or
     441             :  * InvalidOid upon failure
     442             :  */
     443             : Oid
     444          10 : lo_creat(PGconn *conn, int mode)
     445             : {
     446             :     PQArgBlock  argv[1];
     447             :     PGresult   *res;
     448             :     int         retval;
     449             :     int         result_len;
     450             : 
     451          10 :     if (lo_initialize(conn) < 0)
     452           0 :         return InvalidOid;
     453             : 
     454          10 :     argv[0].isint = 1;
     455          10 :     argv[0].len = 4;
     456          10 :     argv[0].u.integer = mode;
     457          10 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
     458             :                &retval, &result_len, 1, argv, 1);
     459          10 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     460             :     {
     461          10 :         PQclear(res);
     462          10 :         return (Oid) retval;
     463             :     }
     464             :     else
     465             :     {
     466           0 :         PQclear(res);
     467           0 :         return InvalidOid;
     468             :     }
     469             : }
     470             : 
     471             : /*
     472             :  * lo_create
     473             :  *    create a new large object
     474             :  * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create
     475             :  *
     476             :  * returns the oid of the large object created or
     477             :  * InvalidOid upon failure
     478             :  */
     479             : Oid
     480           0 : lo_create(PGconn *conn, Oid lobjId)
     481             : {
     482             :     PQArgBlock  argv[1];
     483             :     PGresult   *res;
     484             :     int         retval;
     485             :     int         result_len;
     486             : 
     487           0 :     if (lo_initialize(conn) < 0)
     488           0 :         return InvalidOid;
     489             : 
     490             :     /* Must check this on-the-fly because it's not there pre-8.1 */
     491           0 :     if (conn->lobjfuncs->fn_lo_create == 0)
     492             :     {
     493           0 :         appendPQExpBuffer(&conn->errorMessage,
     494           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     495             :                           "lo_create");
     496           0 :         return InvalidOid;
     497             :     }
     498             : 
     499           0 :     argv[0].isint = 1;
     500           0 :     argv[0].len = 4;
     501           0 :     argv[0].u.integer = lobjId;
     502           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_create,
     503             :                &retval, &result_len, 1, argv, 1);
     504           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     505             :     {
     506           0 :         PQclear(res);
     507           0 :         return (Oid) retval;
     508             :     }
     509             :     else
     510             :     {
     511           0 :         PQclear(res);
     512           0 :         return InvalidOid;
     513             :     }
     514             : }
     515             : 
     516             : 
     517             : /*
     518             :  * lo_tell
     519             :  *    returns the current seek location of the large object
     520             :  */
     521             : int
     522           0 : lo_tell(PGconn *conn, int fd)
     523             : {
     524             :     int         retval;
     525             :     PQArgBlock  argv[1];
     526             :     PGresult   *res;
     527             :     int         result_len;
     528             : 
     529           0 :     if (lo_initialize(conn) < 0)
     530           0 :         return -1;
     531             : 
     532           0 :     argv[0].isint = 1;
     533           0 :     argv[0].len = 4;
     534           0 :     argv[0].u.integer = fd;
     535             : 
     536           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
     537             :                &retval, &result_len, 1, argv, 1);
     538           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     539             :     {
     540           0 :         PQclear(res);
     541           0 :         return retval;
     542             :     }
     543             :     else
     544             :     {
     545           0 :         PQclear(res);
     546           0 :         return -1;
     547             :     }
     548             : }
     549             : 
     550             : /*
     551             :  * lo_tell64
     552             :  *    returns the current seek location of the large object
     553             :  */
     554             : pg_int64
     555           0 : lo_tell64(PGconn *conn, int fd)
     556             : {
     557             :     pg_int64    retval;
     558             :     PQArgBlock  argv[1];
     559             :     PGresult   *res;
     560             :     int         result_len;
     561             : 
     562           0 :     if (lo_initialize(conn) < 0)
     563           0 :         return -1;
     564             : 
     565           0 :     if (conn->lobjfuncs->fn_lo_tell64 == 0)
     566             :     {
     567           0 :         appendPQExpBuffer(&conn->errorMessage,
     568           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     569             :                           "lo_tell64");
     570           0 :         return -1;
     571             :     }
     572             : 
     573           0 :     argv[0].isint = 1;
     574           0 :     argv[0].len = 4;
     575           0 :     argv[0].u.integer = fd;
     576             : 
     577           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64,
     578             :                (void *) &retval, &result_len, 0, argv, 1);
     579           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
     580             :     {
     581           0 :         PQclear(res);
     582           0 :         return lo_ntoh64(retval);
     583             :     }
     584             :     else
     585             :     {
     586           0 :         PQclear(res);
     587           0 :         return -1;
     588             :     }
     589             : }
     590             : 
     591             : /*
     592             :  * lo_unlink
     593             :  *    delete a file
     594             :  */
     595             : 
     596             : int
     597          12 : lo_unlink(PGconn *conn, Oid lobjId)
     598             : {
     599             :     PQArgBlock  argv[1];
     600             :     PGresult   *res;
     601             :     int         result_len;
     602             :     int         retval;
     603             : 
     604          12 :     if (lo_initialize(conn) < 0)
     605           0 :         return -1;
     606             : 
     607          12 :     argv[0].isint = 1;
     608          12 :     argv[0].len = 4;
     609          12 :     argv[0].u.integer = lobjId;
     610             : 
     611          12 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
     612             :                &retval, &result_len, 1, argv, 1);
     613          12 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     614             :     {
     615          12 :         PQclear(res);
     616          12 :         return retval;
     617             :     }
     618             :     else
     619             :     {
     620           0 :         PQclear(res);
     621           0 :         return -1;
     622             :     }
     623             : }
     624             : 
     625             : /*
     626             :  * lo_import -
     627             :  *    imports a file as an (inversion) large object.
     628             :  *
     629             :  * returns the oid of that object upon success,
     630             :  * returns InvalidOid upon failure
     631             :  */
     632             : 
     633             : Oid
     634          12 : lo_import(PGconn *conn, const char *filename)
     635             : {
     636          12 :     return lo_import_internal(conn, filename, InvalidOid);
     637             : }
     638             : 
     639             : /*
     640             :  * lo_import_with_oid -
     641             :  *    imports a file as an (inversion) large object.
     642             :  *    large object id can be specified.
     643             :  *
     644             :  * returns the oid of that object upon success,
     645             :  * returns InvalidOid upon failure
     646             :  */
     647             : 
     648             : Oid
     649           0 : lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId)
     650             : {
     651           0 :     return lo_import_internal(conn, filename, lobjId);
     652             : }
     653             : 
     654             : static Oid
     655          12 : lo_import_internal(PGconn *conn, const char *filename, Oid oid)
     656             : {
     657             :     int         fd;
     658             :     int         nbytes,
     659             :                 tmp;
     660             :     char        buf[LO_BUFSIZE];
     661             :     Oid         lobjOid;
     662             :     int         lobj;
     663             :     char        sebuf[PG_STRERROR_R_BUFLEN];
     664             : 
     665          12 :     if (conn == NULL)
     666           0 :         return InvalidOid;
     667             : 
     668             :     /* Since this is the beginning of a query cycle, reset the error buffer */
     669          12 :     resetPQExpBuffer(&conn->errorMessage);
     670             : 
     671             :     /*
     672             :      * open the file to be read in
     673             :      */
     674          12 :     fd = open(filename, O_RDONLY | PG_BINARY, 0666);
     675          12 :     if (fd < 0)
     676             :     {                           /* error */
     677           2 :         appendPQExpBuffer(&conn->errorMessage,
     678           2 :                           libpq_gettext("could not open file \"%s\": %s\n"),
     679           2 :                           filename, strerror_r(errno, sebuf, sizeof(sebuf)));
     680           2 :         return InvalidOid;
     681             :     }
     682             : 
     683             :     /*
     684             :      * create an inversion object
     685             :      */
     686          10 :     if (oid == InvalidOid)
     687          10 :         lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
     688             :     else
     689           0 :         lobjOid = lo_create(conn, oid);
     690             : 
     691          10 :     if (lobjOid == InvalidOid)
     692             :     {
     693             :         /* we assume lo_create() already set a suitable error message */
     694           0 :         (void) close(fd);
     695           0 :         return InvalidOid;
     696             :     }
     697             : 
     698          10 :     lobj = lo_open(conn, lobjOid, INV_WRITE);
     699          10 :     if (lobj == -1)
     700             :     {
     701             :         /* we assume lo_open() already set a suitable error message */
     702           0 :         (void) close(fd);
     703           0 :         return InvalidOid;
     704             :     }
     705             : 
     706             :     /*
     707             :      * read in from the file and write to the large object
     708             :      */
     709         668 :     while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
     710             :     {
     711         658 :         tmp = lo_write(conn, lobj, buf, nbytes);
     712         658 :         if (tmp != nbytes)
     713             :         {
     714             :             /*
     715             :              * If lo_write() failed, we are now in an aborted transaction so
     716             :              * there's no need for lo_close(); furthermore, if we tried it
     717             :              * we'd overwrite the useful error result with a useless one. So
     718             :              * just nail the doors shut and get out of town.
     719             :              */
     720           0 :             (void) close(fd);
     721           0 :             return InvalidOid;
     722             :         }
     723             :     }
     724             : 
     725          10 :     if (nbytes < 0)
     726             :     {
     727             :         /* We must do lo_close before setting the errorMessage */
     728           0 :         int         save_errno = errno;
     729             : 
     730           0 :         (void) lo_close(conn, lobj);
     731           0 :         (void) close(fd);
     732             :         /* deliberately overwrite any error from lo_close */
     733           0 :         printfPQExpBuffer(&conn->errorMessage,
     734           0 :                           libpq_gettext("could not read from file \"%s\": %s\n"),
     735             :                           filename,
     736             :                           strerror_r(save_errno, sebuf, sizeof(sebuf)));
     737           0 :         return InvalidOid;
     738             :     }
     739             : 
     740          10 :     (void) close(fd);
     741             : 
     742          10 :     if (lo_close(conn, lobj) != 0)
     743             :     {
     744             :         /* we assume lo_close() already set a suitable error message */
     745           0 :         return InvalidOid;
     746             :     }
     747             : 
     748          10 :     return lobjOid;
     749             : }
     750             : 
     751             : /*
     752             :  * lo_export -
     753             :  *    exports an (inversion) large object.
     754             :  * returns -1 upon failure, 1 if OK
     755             :  */
     756             : int
     757           4 : lo_export(PGconn *conn, Oid lobjId, const char *filename)
     758             : {
     759           4 :     int         result = 1;
     760             :     int         fd;
     761             :     int         nbytes,
     762             :                 tmp;
     763             :     char        buf[LO_BUFSIZE];
     764             :     int         lobj;
     765             :     char        sebuf[PG_STRERROR_R_BUFLEN];
     766             : 
     767             :     /*
     768             :      * open the large object.
     769             :      */
     770           4 :     lobj = lo_open(conn, lobjId, INV_READ);
     771           4 :     if (lobj == -1)
     772             :     {
     773             :         /* we assume lo_open() already set a suitable error message */
     774           0 :         return -1;
     775             :     }
     776             : 
     777             :     /*
     778             :      * create the file to be written to
     779             :      */
     780           4 :     fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
     781           4 :     if (fd < 0)
     782             :     {
     783             :         /* We must do lo_close before setting the errorMessage */
     784           0 :         int         save_errno = errno;
     785             : 
     786           0 :         (void) lo_close(conn, lobj);
     787             :         /* deliberately overwrite any error from lo_close */
     788           0 :         printfPQExpBuffer(&conn->errorMessage,
     789           0 :                           libpq_gettext("could not open file \"%s\": %s\n"),
     790             :                           filename,
     791             :                           strerror_r(save_errno, sebuf, sizeof(sebuf)));
     792           0 :         return -1;
     793             :     }
     794             : 
     795             :     /*
     796             :      * read in from the large object and write to the file
     797             :      */
     798         332 :     while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
     799             :     {
     800         328 :         tmp = write(fd, buf, nbytes);
     801         328 :         if (tmp != nbytes)
     802             :         {
     803             :             /* We must do lo_close before setting the errorMessage */
     804           0 :             int         save_errno = errno;
     805             : 
     806           0 :             (void) lo_close(conn, lobj);
     807           0 :             (void) close(fd);
     808             :             /* deliberately overwrite any error from lo_close */
     809           0 :             printfPQExpBuffer(&conn->errorMessage,
     810           0 :                               libpq_gettext("could not write to file \"%s\": %s\n"),
     811             :                               filename,
     812             :                               strerror_r(save_errno, sebuf, sizeof(sebuf)));
     813           0 :             return -1;
     814             :         }
     815             :     }
     816             : 
     817             :     /*
     818             :      * If lo_read() failed, we are now in an aborted transaction so there's no
     819             :      * need for lo_close(); furthermore, if we tried it we'd overwrite the
     820             :      * useful error result with a useless one. So skip lo_close() if we got a
     821             :      * failure result.
     822             :      */
     823           8 :     if (nbytes < 0 ||
     824           4 :         lo_close(conn, lobj) != 0)
     825             :     {
     826             :         /* assume lo_read() or lo_close() left a suitable error message */
     827           0 :         result = -1;
     828             :     }
     829             : 
     830             :     /* if we already failed, don't overwrite that msg with a close error */
     831           4 :     if (close(fd) != 0 && result >= 0)
     832             :     {
     833           0 :         appendPQExpBuffer(&conn->errorMessage,
     834           0 :                           libpq_gettext("could not write to file \"%s\": %s\n"),
     835           0 :                           filename, strerror_r(errno, sebuf, sizeof(sebuf)));
     836           0 :         result = -1;
     837             :     }
     838             : 
     839           4 :     return result;
     840             : }
     841             : 
     842             : 
     843             : /*
     844             :  * lo_initialize
     845             :  *
     846             :  * Initialize for a new large-object operation on an existing connection.
     847             :  * Return 0 if OK, -1 on failure.
     848             :  *
     849             :  * If we haven't previously done so, we collect the function OIDs from
     850             :  * pg_proc for all functions that are required for large object operations.
     851             :  */
     852             : static int
     853        1252 : lo_initialize(PGconn *conn)
     854             : {
     855             :     PGresult   *res;
     856             :     PGlobjfuncs *lobjfuncs;
     857             :     int         n;
     858             :     const char *query;
     859             :     const char *fname;
     860             :     Oid         foid;
     861             : 
     862             :     /* Nothing we can do with no connection */
     863        1252 :     if (conn == NULL)
     864           0 :         return -1;
     865             : 
     866             :     /* Since this is the beginning of a query cycle, reset the error buffer */
     867        1252 :     resetPQExpBuffer(&conn->errorMessage);
     868             : 
     869             :     /* Nothing else to do if we already collected info */
     870        1252 :     if (conn->lobjfuncs != NULL)
     871        1200 :         return 0;
     872             : 
     873             :     /*
     874             :      * Allocate the structure to hold the function OIDs.  We don't store it
     875             :      * into the PGconn until it's successfully filled.
     876             :      */
     877          52 :     lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
     878          52 :     if (lobjfuncs == NULL)
     879             :     {
     880           0 :         appendPQExpBufferStr(&conn->errorMessage,
     881           0 :                              libpq_gettext("out of memory\n"));
     882           0 :         return -1;
     883             :     }
     884          52 :     MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
     885             : 
     886             :     /*
     887             :      * Execute the query to get all the functions at once.  (Not all of them
     888             :      * may exist in older server versions.)
     889             :      */
     890          52 :     query = "select proname, oid from pg_catalog.pg_proc "
     891             :         "where proname in ("
     892             :         "'lo_open', "
     893             :         "'lo_close', "
     894             :         "'lo_creat', "
     895             :         "'lo_create', "
     896             :         "'lo_unlink', "
     897             :         "'lo_lseek', "
     898             :         "'lo_lseek64', "
     899             :         "'lo_tell', "
     900             :         "'lo_tell64', "
     901             :         "'lo_truncate', "
     902             :         "'lo_truncate64', "
     903             :         "'loread', "
     904             :         "'lowrite') "
     905             :         "and pronamespace = (select oid from pg_catalog.pg_namespace "
     906             :         "where nspname = 'pg_catalog')";
     907             : 
     908          52 :     res = PQexec(conn, query);
     909          52 :     if (res == NULL)
     910             :     {
     911           0 :         free(lobjfuncs);
     912           0 :         return -1;
     913             :     }
     914             : 
     915          52 :     if (res->resultStatus != PGRES_TUPLES_OK)
     916             :     {
     917           0 :         free(lobjfuncs);
     918           0 :         PQclear(res);
     919           0 :         appendPQExpBufferStr(&conn->errorMessage,
     920           0 :                              libpq_gettext("query to initialize large object functions did not return data\n"));
     921           0 :         return -1;
     922             :     }
     923             : 
     924             :     /*
     925             :      * Examine the result and put the OID's into the struct
     926             :      */
     927         728 :     for (n = 0; n < PQntuples(res); n++)
     928             :     {
     929         676 :         fname = PQgetvalue(res, n, 0);
     930         676 :         foid = (Oid) atoi(PQgetvalue(res, n, 1));
     931         676 :         if (strcmp(fname, "lo_open") == 0)
     932          52 :             lobjfuncs->fn_lo_open = foid;
     933         624 :         else if (strcmp(fname, "lo_close") == 0)
     934          52 :             lobjfuncs->fn_lo_close = foid;
     935         572 :         else if (strcmp(fname, "lo_creat") == 0)
     936          52 :             lobjfuncs->fn_lo_creat = foid;
     937         520 :         else if (strcmp(fname, "lo_create") == 0)
     938          52 :             lobjfuncs->fn_lo_create = foid;
     939         468 :         else if (strcmp(fname, "lo_unlink") == 0)
     940          52 :             lobjfuncs->fn_lo_unlink = foid;
     941         416 :         else if (strcmp(fname, "lo_lseek") == 0)
     942          52 :             lobjfuncs->fn_lo_lseek = foid;
     943         364 :         else if (strcmp(fname, "lo_lseek64") == 0)
     944          52 :             lobjfuncs->fn_lo_lseek64 = foid;
     945         312 :         else if (strcmp(fname, "lo_tell") == 0)
     946          52 :             lobjfuncs->fn_lo_tell = foid;
     947         260 :         else if (strcmp(fname, "lo_tell64") == 0)
     948          52 :             lobjfuncs->fn_lo_tell64 = foid;
     949         208 :         else if (strcmp(fname, "lo_truncate") == 0)
     950          52 :             lobjfuncs->fn_lo_truncate = foid;
     951         156 :         else if (strcmp(fname, "lo_truncate64") == 0)
     952          52 :             lobjfuncs->fn_lo_truncate64 = foid;
     953         104 :         else if (strcmp(fname, "loread") == 0)
     954          52 :             lobjfuncs->fn_lo_read = foid;
     955          52 :         else if (strcmp(fname, "lowrite") == 0)
     956          52 :             lobjfuncs->fn_lo_write = foid;
     957             :     }
     958             : 
     959          52 :     PQclear(res);
     960             : 
     961             :     /*
     962             :      * Finally check that we got all required large object interface functions
     963             :      * (ones that have been added later than the stone age are instead checked
     964             :      * only if used)
     965             :      */
     966          52 :     if (lobjfuncs->fn_lo_open == 0)
     967             :     {
     968           0 :         appendPQExpBuffer(&conn->errorMessage,
     969           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     970             :                           "lo_open");
     971           0 :         free(lobjfuncs);
     972           0 :         return -1;
     973             :     }
     974          52 :     if (lobjfuncs->fn_lo_close == 0)
     975             :     {
     976           0 :         appendPQExpBuffer(&conn->errorMessage,
     977           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     978             :                           "lo_close");
     979           0 :         free(lobjfuncs);
     980           0 :         return -1;
     981             :     }
     982          52 :     if (lobjfuncs->fn_lo_creat == 0)
     983             :     {
     984           0 :         appendPQExpBuffer(&conn->errorMessage,
     985           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     986             :                           "lo_creat");
     987           0 :         free(lobjfuncs);
     988           0 :         return -1;
     989             :     }
     990          52 :     if (lobjfuncs->fn_lo_unlink == 0)
     991             :     {
     992           0 :         appendPQExpBuffer(&conn->errorMessage,
     993           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
     994             :                           "lo_unlink");
     995           0 :         free(lobjfuncs);
     996           0 :         return -1;
     997             :     }
     998          52 :     if (lobjfuncs->fn_lo_lseek == 0)
     999             :     {
    1000           0 :         appendPQExpBuffer(&conn->errorMessage,
    1001           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
    1002             :                           "lo_lseek");
    1003           0 :         free(lobjfuncs);
    1004           0 :         return -1;
    1005             :     }
    1006          52 :     if (lobjfuncs->fn_lo_tell == 0)
    1007             :     {
    1008           0 :         appendPQExpBuffer(&conn->errorMessage,
    1009           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
    1010             :                           "lo_tell");
    1011           0 :         free(lobjfuncs);
    1012           0 :         return -1;
    1013             :     }
    1014          52 :     if (lobjfuncs->fn_lo_read == 0)
    1015             :     {
    1016           0 :         appendPQExpBuffer(&conn->errorMessage,
    1017           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
    1018             :                           "loread");
    1019           0 :         free(lobjfuncs);
    1020           0 :         return -1;
    1021             :     }
    1022          52 :     if (lobjfuncs->fn_lo_write == 0)
    1023             :     {
    1024           0 :         appendPQExpBuffer(&conn->errorMessage,
    1025           0 :                           libpq_gettext("cannot determine OID of function %s\n"),
    1026             :                           "lowrite");
    1027           0 :         free(lobjfuncs);
    1028           0 :         return -1;
    1029             :     }
    1030             : 
    1031             :     /*
    1032             :      * Put the structure into the connection control
    1033             :      */
    1034          52 :     conn->lobjfuncs = lobjfuncs;
    1035          52 :     return 0;
    1036             : }
    1037             : 
    1038             : /*
    1039             :  * lo_hton64
    1040             :  *    converts a 64-bit integer from host byte order to network byte order
    1041             :  */
    1042             : static pg_int64
    1043           0 : lo_hton64(pg_int64 host64)
    1044             : {
    1045             :     union
    1046             :     {
    1047             :         pg_int64    i64;
    1048             :         uint32      i32[2];
    1049             :     }           swap;
    1050             :     uint32      t;
    1051             : 
    1052             :     /* High order half first, since we're doing MSB-first */
    1053           0 :     t = (uint32) (host64 >> 32);
    1054           0 :     swap.i32[0] = pg_hton32(t);
    1055             : 
    1056             :     /* Now the low order half */
    1057           0 :     t = (uint32) host64;
    1058           0 :     swap.i32[1] = pg_hton32(t);
    1059             : 
    1060           0 :     return swap.i64;
    1061             : }
    1062             : 
    1063             : /*
    1064             :  * lo_ntoh64
    1065             :  *    converts a 64-bit integer from network byte order to host byte order
    1066             :  */
    1067             : static pg_int64
    1068           0 : lo_ntoh64(pg_int64 net64)
    1069             : {
    1070             :     union
    1071             :     {
    1072             :         pg_int64    i64;
    1073             :         uint32      i32[2];
    1074             :     }           swap;
    1075             :     pg_int64    result;
    1076             : 
    1077           0 :     swap.i64 = net64;
    1078             : 
    1079           0 :     result = (uint32) pg_ntoh32(swap.i32[0]);
    1080           0 :     result <<= 32;
    1081           0 :     result |= (uint32) pg_ntoh32(swap.i32[1]);
    1082             : 
    1083           0 :     return result;
    1084             : }

Generated by: LCOV version 1.14