LCOV - differential code coverage report
Current view: top level - src/interfaces/libpq - fe-lobj.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 39.8 % 374 149 23 19 113 70 23 70 56 120 64 12 10
Current Date: 2023-04-08 15:15:32 Functions: 50.0 % 20 10 1 9 8 2 9 8
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a