LCOV - code coverage report
Current view: top level - src/bin/psql - large_obj.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 50 118 42.4 %
Date: 2017-09-29 13:40:31 Functions: 6 8 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * psql - the PostgreSQL interactive terminal
       3             :  *
       4             :  * Copyright (c) 2000-2017, PostgreSQL Global Development Group
       5             :  *
       6             :  * src/bin/psql/large_obj.c
       7             :  */
       8             : #include "postgres_fe.h"
       9             : #include "large_obj.h"
      10             : 
      11             : 
      12             : #include "settings.h"
      13             : #include "common.h"
      14             : 
      15             : static void print_lo_result(const char *fmt,...) pg_attribute_printf(1, 2);
      16             : 
      17             : static void
      18           6 : print_lo_result(const char *fmt,...)
      19             : {
      20             :     va_list     ap;
      21             : 
      22           6 :     if (!pset.quiet)
      23             :     {
      24           0 :         if (pset.popt.topt.format == PRINT_HTML)
      25           0 :             fputs("<p>", pset.queryFout);
      26             : 
      27           0 :         va_start(ap, fmt);
      28           0 :         vfprintf(pset.queryFout, fmt, ap);
      29           0 :         va_end(ap);
      30             : 
      31           0 :         if (pset.popt.topt.format == PRINT_HTML)
      32           0 :             fputs("</p>\n", pset.queryFout);
      33             :         else
      34           0 :             fputs("\n", pset.queryFout);
      35             :     }
      36             : 
      37           6 :     if (pset.logfile)
      38             :     {
      39           0 :         va_start(ap, fmt);
      40           0 :         vfprintf(pset.logfile, fmt, ap);
      41           0 :         va_end(ap);
      42           0 :         fputs("\n", pset.logfile);
      43             :     }
      44           6 : }
      45             : 
      46             : 
      47             : /*
      48             :  * Prepare to do a large-object operation.  We *must* be inside a transaction
      49             :  * block for all these operations, so start one if needed.
      50             :  *
      51             :  * Returns TRUE if okay, FALSE if failed.  *own_transaction is set to indicate
      52             :  * if we started our own transaction or not.
      53             :  */
      54             : static bool
      55           6 : start_lo_xact(const char *operation, bool *own_transaction)
      56             : {
      57             :     PGTransactionStatusType tstatus;
      58             :     PGresult   *res;
      59             : 
      60           6 :     *own_transaction = false;
      61             : 
      62           6 :     if (!pset.db)
      63             :     {
      64           0 :         psql_error("%s: not connected to a database\n", operation);
      65           0 :         return false;
      66             :     }
      67             : 
      68           6 :     tstatus = PQtransactionStatus(pset.db);
      69             : 
      70           6 :     switch (tstatus)
      71             :     {
      72             :         case PQTRANS_IDLE:
      73             :             /* need to start our own xact */
      74           6 :             if (!(res = PSQLexec("BEGIN")))
      75           0 :                 return false;
      76           6 :             PQclear(res);
      77           6 :             *own_transaction = true;
      78           6 :             break;
      79             :         case PQTRANS_INTRANS:
      80             :             /* use the existing xact */
      81           0 :             break;
      82             :         case PQTRANS_INERROR:
      83           0 :             psql_error("%s: current transaction is aborted\n", operation);
      84           0 :             return false;
      85             :         default:
      86           0 :             psql_error("%s: unknown transaction status\n", operation);
      87           0 :             return false;
      88             :     }
      89             : 
      90           6 :     return true;
      91             : }
      92             : 
      93             : /*
      94             :  * Clean up after a successful LO operation
      95             :  */
      96             : static bool
      97           6 : finish_lo_xact(const char *operation, bool own_transaction)
      98             : {
      99             :     PGresult   *res;
     100             : 
     101           6 :     if (own_transaction && pset.autocommit)
     102             :     {
     103             :         /* close out our own xact */
     104           6 :         if (!(res = PSQLexec("COMMIT")))
     105             :         {
     106           0 :             res = PSQLexec("ROLLBACK");
     107           0 :             PQclear(res);
     108           0 :             return false;
     109             :         }
     110           6 :         PQclear(res);
     111             :     }
     112             : 
     113           6 :     return true;
     114             : }
     115             : 
     116             : /*
     117             :  * Clean up after a failed LO operation
     118             :  */
     119             : static bool
     120           0 : fail_lo_xact(const char *operation, bool own_transaction)
     121             : {
     122             :     PGresult   *res;
     123             : 
     124           0 :     if (own_transaction && pset.autocommit)
     125             :     {
     126             :         /* close out our own xact */
     127           0 :         res = PSQLexec("ROLLBACK");
     128           0 :         PQclear(res);
     129             :     }
     130             : 
     131           0 :     return false;               /* always */
     132             : }
     133             : 
     134             : 
     135             : /*
     136             :  * do_lo_export()
     137             :  *
     138             :  * Write a large object to a file
     139             :  */
     140             : bool
     141           1 : do_lo_export(const char *loid_arg, const char *filename_arg)
     142             : {
     143             :     int         status;
     144             :     bool        own_transaction;
     145             : 
     146           1 :     if (!start_lo_xact("\\lo_export", &own_transaction))
     147           0 :         return false;
     148             : 
     149           1 :     SetCancelConn();
     150           1 :     status = lo_export(pset.db, atooid(loid_arg), filename_arg);
     151           1 :     ResetCancelConn();
     152             : 
     153             :     /* of course this status is documented nowhere :( */
     154           1 :     if (status != 1)
     155             :     {
     156           0 :         psql_error("%s", PQerrorMessage(pset.db));
     157           0 :         return fail_lo_xact("\\lo_export", own_transaction);
     158             :     }
     159             : 
     160           1 :     if (!finish_lo_xact("\\lo_export", own_transaction))
     161           0 :         return false;
     162             : 
     163           1 :     print_lo_result("lo_export");
     164             : 
     165           1 :     return true;
     166             : }
     167             : 
     168             : 
     169             : /*
     170             :  * do_lo_import()
     171             :  *
     172             :  * Copy large object from file to database
     173             :  */
     174             : bool
     175           2 : do_lo_import(const char *filename_arg, const char *comment_arg)
     176             : {
     177             :     PGresult   *res;
     178             :     Oid         loid;
     179             :     char        oidbuf[32];
     180             :     bool        own_transaction;
     181             : 
     182           2 :     if (!start_lo_xact("\\lo_import", &own_transaction))
     183           0 :         return false;
     184             : 
     185           2 :     SetCancelConn();
     186           2 :     loid = lo_import(pset.db, filename_arg);
     187           2 :     ResetCancelConn();
     188             : 
     189           2 :     if (loid == InvalidOid)
     190             :     {
     191           0 :         psql_error("%s", PQerrorMessage(pset.db));
     192           0 :         return fail_lo_xact("\\lo_import", own_transaction);
     193             :     }
     194             : 
     195             :     /* insert description if given */
     196           2 :     if (comment_arg)
     197             :     {
     198             :         char       *cmdbuf;
     199             :         char       *bufptr;
     200           0 :         size_t      slen = strlen(comment_arg);
     201             : 
     202           0 :         cmdbuf = malloc(slen * 2 + 256);
     203           0 :         if (!cmdbuf)
     204           0 :             return fail_lo_xact("\\lo_import", own_transaction);
     205           0 :         sprintf(cmdbuf, "COMMENT ON LARGE OBJECT %u IS '", loid);
     206           0 :         bufptr = cmdbuf + strlen(cmdbuf);
     207           0 :         bufptr += PQescapeStringConn(pset.db, bufptr, comment_arg, slen, NULL);
     208           0 :         strcpy(bufptr, "'");
     209             : 
     210           0 :         if (!(res = PSQLexec(cmdbuf)))
     211             :         {
     212           0 :             free(cmdbuf);
     213           0 :             return fail_lo_xact("\\lo_import", own_transaction);
     214             :         }
     215             : 
     216           0 :         PQclear(res);
     217           0 :         free(cmdbuf);
     218             :     }
     219             : 
     220           2 :     if (!finish_lo_xact("\\lo_import", own_transaction))
     221           0 :         return false;
     222             : 
     223           2 :     print_lo_result("lo_import %u", loid);
     224             : 
     225           2 :     sprintf(oidbuf, "%u", loid);
     226           2 :     SetVariable(pset.vars, "LASTOID", oidbuf);
     227             : 
     228           2 :     return true;
     229             : }
     230             : 
     231             : 
     232             : /*
     233             :  * do_lo_unlink()
     234             :  *
     235             :  * removes a large object out of the database
     236             :  */
     237             : bool
     238           3 : do_lo_unlink(const char *loid_arg)
     239             : {
     240             :     int         status;
     241           3 :     Oid         loid = atooid(loid_arg);
     242             :     bool        own_transaction;
     243             : 
     244           3 :     if (!start_lo_xact("\\lo_unlink", &own_transaction))
     245           0 :         return false;
     246             : 
     247           3 :     SetCancelConn();
     248           3 :     status = lo_unlink(pset.db, loid);
     249           3 :     ResetCancelConn();
     250             : 
     251           3 :     if (status == -1)
     252             :     {
     253           0 :         psql_error("%s", PQerrorMessage(pset.db));
     254           0 :         return fail_lo_xact("\\lo_unlink", own_transaction);
     255             :     }
     256             : 
     257           3 :     if (!finish_lo_xact("\\lo_unlink", own_transaction))
     258           0 :         return false;
     259             : 
     260           3 :     print_lo_result("lo_unlink %u", loid);
     261             : 
     262           3 :     return true;
     263             : }
     264             : 
     265             : 
     266             : 
     267             : /*
     268             :  * do_lo_list()
     269             :  *
     270             :  * Show all large objects in database with comments
     271             :  */
     272             : bool
     273           0 : do_lo_list(void)
     274             : {
     275             :     PGresult   *res;
     276             :     char        buf[1024];
     277           0 :     printQueryOpt myopt = pset.popt;
     278             : 
     279           0 :     if (pset.sversion >= 90000)
     280             :     {
     281           0 :         snprintf(buf, sizeof(buf),
     282             :                  "SELECT oid as \"%s\",\n"
     283             :                  "  pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n"
     284             :                  "  pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
     285             :                  "  FROM pg_catalog.pg_largeobject_metadata "
     286             :                  "  ORDER BY oid",
     287             :                  gettext_noop("ID"),
     288             :                  gettext_noop("Owner"),
     289             :                  gettext_noop("Description"));
     290             :     }
     291             :     else
     292             :     {
     293           0 :         snprintf(buf, sizeof(buf),
     294             :                  "SELECT loid as \"%s\",\n"
     295             :                  "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
     296             :                  "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
     297             :                  "ORDER BY 1",
     298             :                  gettext_noop("ID"),
     299             :                  gettext_noop("Description"));
     300             :     }
     301             : 
     302           0 :     res = PSQLexec(buf);
     303           0 :     if (!res)
     304           0 :         return false;
     305             : 
     306           0 :     myopt.topt.tuples_only = false;
     307           0 :     myopt.nullPrint = NULL;
     308           0 :     myopt.title = _("Large objects");
     309           0 :     myopt.translate_header = true;
     310             : 
     311           0 :     printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
     312             : 
     313           0 :     PQclear(res);
     314           0 :     return true;
     315             : }

Generated by: LCOV version 1.11