LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-lobj.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 41.8 % 488 204
Test Date: 2026-01-26 10:56:24 Functions: 50.0 % 20 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 44.1 % 170 75

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

Generated by: LCOV version 2.3.2-1