Header And Logo

PostgreSQL
| The world's most advanced open source database.

large_obj.c

Go to the documentation of this file.
00001 /*
00002  * psql - the PostgreSQL interactive terminal
00003  *
00004  * Copyright (c) 2000-2013, PostgreSQL Global Development Group
00005  *
00006  * src/bin/psql/large_obj.c
00007  */
00008 #include "postgres_fe.h"
00009 #include "large_obj.h"
00010 
00011 
00012 #include "settings.h"
00013 #include "common.h"
00014 
00015 static void
00016 print_lo_result(const char *fmt,...)
00017 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
00018 
00019 static void
00020 print_lo_result(const char *fmt,...)
00021 {
00022     va_list     ap;
00023 
00024     if (!pset.quiet)
00025     {
00026         if (pset.popt.topt.format == PRINT_HTML)
00027             fputs("<p>", pset.queryFout);
00028 
00029         va_start(ap, fmt);
00030         vfprintf(pset.queryFout, fmt, ap);
00031         va_end(ap);
00032 
00033         if (pset.popt.topt.format == PRINT_HTML)
00034             fputs("</p>\n", pset.queryFout);
00035         else
00036             fputs("\n", pset.queryFout);
00037     }
00038 
00039     if (pset.logfile)
00040     {
00041         va_start(ap, fmt);
00042         vfprintf(pset.logfile, fmt, ap);
00043         va_end(ap);
00044         fputs("\n", pset.logfile);
00045     }
00046 }
00047 
00048 
00049 /*
00050  * Prepare to do a large-object operation.  We *must* be inside a transaction
00051  * block for all these operations, so start one if needed.
00052  *
00053  * Returns TRUE if okay, FALSE if failed.  *own_transaction is set to indicate
00054  * if we started our own transaction or not.
00055  */
00056 static bool
00057 start_lo_xact(const char *operation, bool *own_transaction)
00058 {
00059     PGTransactionStatusType tstatus;
00060     PGresult   *res;
00061 
00062     *own_transaction = false;
00063 
00064     if (!pset.db)
00065     {
00066         psql_error("%s: not connected to a database\n", operation);
00067         return false;
00068     }
00069 
00070     tstatus = PQtransactionStatus(pset.db);
00071 
00072     switch (tstatus)
00073     {
00074         case PQTRANS_IDLE:
00075             /* need to start our own xact */
00076             if (!(res = PSQLexec("BEGIN", false)))
00077                 return false;
00078             PQclear(res);
00079             *own_transaction = true;
00080             break;
00081         case PQTRANS_INTRANS:
00082             /* use the existing xact */
00083             break;
00084         case PQTRANS_INERROR:
00085             psql_error("%s: current transaction is aborted\n", operation);
00086             return false;
00087         default:
00088             psql_error("%s: unknown transaction status\n", operation);
00089             return false;
00090     }
00091 
00092     return true;
00093 }
00094 
00095 /*
00096  * Clean up after a successful LO operation
00097  */
00098 static bool
00099 finish_lo_xact(const char *operation, bool own_transaction)
00100 {
00101     PGresult   *res;
00102 
00103     if (own_transaction && pset.autocommit)
00104     {
00105         /* close out our own xact */
00106         if (!(res = PSQLexec("COMMIT", false)))
00107         {
00108             res = PSQLexec("ROLLBACK", false);
00109             PQclear(res);
00110             return false;
00111         }
00112         PQclear(res);
00113     }
00114 
00115     return true;
00116 }
00117 
00118 /*
00119  * Clean up after a failed LO operation
00120  */
00121 static bool
00122 fail_lo_xact(const char *operation, bool own_transaction)
00123 {
00124     PGresult   *res;
00125 
00126     if (own_transaction && pset.autocommit)
00127     {
00128         /* close out our own xact */
00129         res = PSQLexec("ROLLBACK", false);
00130         PQclear(res);
00131     }
00132 
00133     return false;               /* always */
00134 }
00135 
00136 
00137 /*
00138  * do_lo_export()
00139  *
00140  * Write a large object to a file
00141  */
00142 bool
00143 do_lo_export(const char *loid_arg, const char *filename_arg)
00144 {
00145     int         status;
00146     bool        own_transaction;
00147 
00148     if (!start_lo_xact("\\lo_export", &own_transaction))
00149         return false;
00150 
00151     SetCancelConn();
00152     status = lo_export(pset.db, atooid(loid_arg), filename_arg);
00153     ResetCancelConn();
00154 
00155     /* of course this status is documented nowhere :( */
00156     if (status != 1)
00157     {
00158         psql_error("%s", PQerrorMessage(pset.db));
00159         return fail_lo_xact("\\lo_export", own_transaction);
00160     }
00161 
00162     if (!finish_lo_xact("\\lo_export", own_transaction))
00163         return false;
00164 
00165     print_lo_result("lo_export");
00166 
00167     return true;
00168 }
00169 
00170 
00171 /*
00172  * do_lo_import()
00173  *
00174  * Copy large object from file to database
00175  */
00176 bool
00177 do_lo_import(const char *filename_arg, const char *comment_arg)
00178 {
00179     PGresult   *res;
00180     Oid         loid;
00181     char        oidbuf[32];
00182     bool        own_transaction;
00183 
00184     if (!start_lo_xact("\\lo_import", &own_transaction))
00185         return false;
00186 
00187     SetCancelConn();
00188     loid = lo_import(pset.db, filename_arg);
00189     ResetCancelConn();
00190 
00191     if (loid == InvalidOid)
00192     {
00193         psql_error("%s", PQerrorMessage(pset.db));
00194         return fail_lo_xact("\\lo_import", own_transaction);
00195     }
00196 
00197     /* insert description if given */
00198     if (comment_arg)
00199     {
00200         char       *cmdbuf;
00201         char       *bufptr;
00202         size_t      slen = strlen(comment_arg);
00203 
00204         cmdbuf = malloc(slen * 2 + 256);
00205         if (!cmdbuf)
00206             return fail_lo_xact("\\lo_import", own_transaction);
00207         sprintf(cmdbuf, "COMMENT ON LARGE OBJECT %u IS '", loid);
00208         bufptr = cmdbuf + strlen(cmdbuf);
00209         bufptr += PQescapeStringConn(pset.db, bufptr, comment_arg, slen, NULL);
00210         strcpy(bufptr, "'");
00211 
00212         if (!(res = PSQLexec(cmdbuf, false)))
00213         {
00214             free(cmdbuf);
00215             return fail_lo_xact("\\lo_import", own_transaction);
00216         }
00217 
00218         PQclear(res);
00219         free(cmdbuf);
00220     }
00221 
00222     if (!finish_lo_xact("\\lo_import", own_transaction))
00223         return false;
00224 
00225     print_lo_result("lo_import %u", loid);
00226 
00227     sprintf(oidbuf, "%u", loid);
00228     SetVariable(pset.vars, "LASTOID", oidbuf);
00229 
00230     return true;
00231 }
00232 
00233 
00234 /*
00235  * do_lo_unlink()
00236  *
00237  * removes a large object out of the database
00238  */
00239 bool
00240 do_lo_unlink(const char *loid_arg)
00241 {
00242     int         status;
00243     Oid         loid = atooid(loid_arg);
00244     bool        own_transaction;
00245 
00246     if (!start_lo_xact("\\lo_unlink", &own_transaction))
00247         return false;
00248 
00249     SetCancelConn();
00250     status = lo_unlink(pset.db, loid);
00251     ResetCancelConn();
00252 
00253     if (status == -1)
00254     {
00255         psql_error("%s", PQerrorMessage(pset.db));
00256         return fail_lo_xact("\\lo_unlink", own_transaction);
00257     }
00258 
00259     if (!finish_lo_xact("\\lo_unlink", own_transaction))
00260         return false;
00261 
00262     print_lo_result("lo_unlink %u", loid);
00263 
00264     return true;
00265 }
00266 
00267 
00268 
00269 /*
00270  * do_lo_list()
00271  *
00272  * Show all large objects in database with comments
00273  */
00274 bool
00275 do_lo_list(void)
00276 {
00277     PGresult   *res;
00278     char        buf[1024];
00279     printQueryOpt myopt = pset.popt;
00280 
00281     if (pset.sversion >= 90000)
00282     {
00283         snprintf(buf, sizeof(buf),
00284                  "SELECT oid as \"%s\",\n"
00285                  "  pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n"
00286             "  pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
00287                  "  FROM pg_catalog.pg_largeobject_metadata "
00288                  "  ORDER BY oid",
00289                  gettext_noop("ID"),
00290                  gettext_noop("Owner"),
00291                  gettext_noop("Description"));
00292     }
00293     else
00294     {
00295         snprintf(buf, sizeof(buf),
00296                  "SELECT loid as \"%s\",\n"
00297            "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
00298              "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
00299                  "ORDER BY 1",
00300                  gettext_noop("ID"),
00301                  gettext_noop("Description"));
00302     }
00303 
00304     res = PSQLexec(buf, false);
00305     if (!res)
00306         return false;
00307 
00308     myopt.topt.tuples_only = false;
00309     myopt.nullPrint = NULL;
00310     myopt.title = _("Large objects");
00311     myopt.translate_header = true;
00312 
00313     printQuery(res, &myopt, pset.queryFout, pset.logfile);
00314 
00315     PQclear(res);
00316     return true;
00317 }