]> granicus.if.org Git - postgresql/blobdiff - src/bin/psql/large_obj.c
Remove cvs keywords from all files.
[postgresql] / src / bin / psql / large_obj.c
index b39ef0dca1c9ecc803212c6baada2f04d4da9854..ecc7b76b5c82ddd6046a0da17a542046997b30b6 100644 (file)
 /*
  * psql - the PostgreSQL interactive terminal
  *
- * Copyright 2000-2002 by PostgreSQL Global Development Group
+ * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.25 2003/04/18 23:38:47 tgl Exp $
+ * src/bin/psql/large_obj.c
  */
 #include "postgres_fe.h"
 #include "large_obj.h"
 
-#include "libpq-fe.h"
 
 #include "settings.h"
-#include "variables.h"
 #include "common.h"
-#include "print.h"
 
+static void
+print_lo_result(const char *fmt,...)
+__attribute__((format(printf, 1, 2)));
 
-#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
+static void
+print_lo_result(const char *fmt,...)
+{
+       va_list         ap;
 
+       if (!pset.quiet)
+       {
+               if (pset.popt.topt.format == PRINT_HTML)
+                       fputs("<p>", pset.queryFout);
 
-/*
- * Since all large object ops must be in a transaction, we must do some magic
- * here. You can set the variable lo_transaction to one of commit|rollback|
- * nothing to get your favourite behaviour regarding any transaction in
- * progress. Rollback is default.
- */
+               va_start(ap, fmt);
+               vfprintf(pset.queryFout, fmt, ap);
+               va_end(ap);
 
-static char notice[80];
+               if (pset.popt.topt.format == PRINT_HTML)
+                       fputs("</p>\n", pset.queryFout);
+               else
+                       fputs("\n", pset.queryFout);
+       }
 
-static void
-_my_notice_handler(void *arg, const char *message)
-{
-       (void) arg;
-       strncpy(notice, message, 79);
-       notice[79] = '\0';
+       if (pset.logfile)
+       {
+               va_start(ap, fmt);
+               vfprintf(pset.logfile, fmt, ap);
+               va_end(ap);
+               fputs("\n", pset.logfile);
+       }
 }
 
 
+/*
+ * Prepare to do a large-object operation.     We *must* be inside a transaction
+ * block for all these operations, so start one if needed.
+ *
+ * Returns TRUE if okay, FALSE if failed.  *own_transaction is set to indicate
+ * if we started our own transaction or not.
+ */
 static bool
-handle_transaction(void)
+start_lo_xact(const char *operation, bool *own_transaction)
 {
+       PGTransactionStatusType tstatus;
        PGresult   *res;
-       bool            commit = false;
-       PQnoticeProcessor old_notice_hook;
 
-       switch (SwitchVariable(pset.vars, "LO_TRANSACTION", 
-                                                  "nothing", 
-                                                  "commit", 
-                                                  NULL))
+       *own_transaction = false;
+
+       if (!pset.db)
        {
-               case 1:                                 /* nothing */
-                       return true;
-               case 2:                                 /* commit */
-                       commit = true;
-                       break;
+               psql_error("%s: not connected to a database\n", operation);
+               return false;
        }
 
-       notice[0] = '\0';
-       old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
-
-       res = PSQLexec(commit ? "COMMIT" : "ROLLBACK", false);
-       if (!res)
-               return false;
+       tstatus = PQtransactionStatus(pset.db);
 
-       if (notice[0])
+       switch (tstatus)
        {
-               if ((!commit && strcmp(notice, "WARNING:  ROLLBACK: no transaction in progress\n") != 0) ||
-                       (commit && strcmp(notice, "WARNING:  COMMIT: no transaction in progress\n") != 0))
-                       fputs(notice, stderr);
+               case PQTRANS_IDLE:
+                       /* need to start our own xact */
+                       if (!(res = PSQLexec("BEGIN", false)))
+                               return false;
+                       PQclear(res);
+                       *own_transaction = true;
+                       break;
+               case PQTRANS_INTRANS:
+                       /* use the existing xact */
+                       break;
+               case PQTRANS_INERROR:
+                       psql_error("%s: current transaction is aborted\n", operation);
+                       return false;
+               default:
+                       psql_error("%s: unknown transaction status\n", operation);
+                       return false;
        }
-       else if (!QUIET())
+
+       return true;
+}
+
+/*
+ * Clean up after a successful LO operation
+ */
+static bool
+finish_lo_xact(const char *operation, bool own_transaction)
+{
+       PGresult   *res;
+
+       if (own_transaction && pset.autocommit)
        {
-               if (commit)
-                       puts(gettext("Warning: Your transaction in progress has been committed."));
-               else
-                       puts(gettext("Warning: Your transaction in progress has been rolled back."));
+               /* close out our own xact */
+               if (!(res = PSQLexec("COMMIT", false)))
+               {
+                       res = PSQLexec("ROLLBACK", false);
+                       PQclear(res);
+                       return false;
+               }
+               PQclear(res);
        }
 
-       PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
        return true;
 }
 
+/*
+ * Clean up after a failed LO operation
+ */
+static bool
+fail_lo_xact(const char *operation, bool own_transaction)
+{
+       PGresult   *res;
+
+       if (own_transaction && pset.autocommit)
+       {
+               /* close out our own xact */
+               res = PSQLexec("ROLLBACK", false);
+               PQclear(res);
+       }
+
+       return false;                           /* always */
+}
 
 
 /*
@@ -91,61 +142,32 @@ handle_transaction(void)
 bool
 do_lo_export(const char *loid_arg, const char *filename_arg)
 {
-       PGresult   *res;
        int                     status;
        bool            own_transaction;
 
-       own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
-       if (!pset.db)
-       {
-               psql_error("\\lo_export: not connected to a database\n");
+       if (!start_lo_xact("\\lo_export", &own_transaction))
                return false;
-       }
-
-       if (own_transaction)
-       {
-               if (!handle_transaction())
-                       return false;
-
-               if (!(res = PSQLexec("BEGIN", false)))
-                       return false;
-
-               PQclear(res);
-       }
 
+       SetCancelConn();
        status = lo_export(pset.db, atooid(loid_arg), filename_arg);
+       ResetCancelConn();
+
+       /* of course this status is documented nowhere :( */
        if (status != 1)
-       {                                                       /* of course this status is documented
-                                                                * nowhere :( */
+       {
                fputs(PQerrorMessage(pset.db), stderr);
-               if (own_transaction)
-               {
-                       res = PQexec(pset.db, "ROLLBACK");
-                       PQclear(res);
-               }
-               return false;
+               return fail_lo_xact("\\lo_export", own_transaction);
        }
 
-       if (own_transaction)
-       {
-               if (!(res = PSQLexec("COMMIT", false)))
-               {
-                       res = PQexec(pset.db, "ROLLBACK");
-                       PQclear(res);
-                       return false;
-               }
-
-               PQclear(res);
-       }
+       if (!finish_lo_xact("\\lo_export", own_transaction))
+               return false;
 
-       fprintf(pset.queryFout, "lo_export\n");
+       print_lo_result("lo_export");
 
        return true;
 }
 
 
-
 /*
  * do_lo_import()
  *
@@ -157,44 +179,23 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
        PGresult   *res;
        Oid                     loid;
        char            oidbuf[32];
-       unsigned int i;
        bool            own_transaction;
 
-       own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
-       if (!pset.db)
-       {
-               psql_error("\\lo_import: not connected to a database\n");
+       if (!start_lo_xact("\\lo_import", &own_transaction))
                return false;
-       }
-
-       if (own_transaction)
-       {
-               if (!handle_transaction())
-                       return false;
-
-               if (!(res = PSQLexec("BEGIN", false)))
-                       return false;
-
-               PQclear(res);
-       }
 
+       SetCancelConn();
        loid = lo_import(pset.db, filename_arg);
+       ResetCancelConn();
+
        if (loid == InvalidOid)
        {
                fputs(PQerrorMessage(pset.db), stderr);
-               if (own_transaction)
-               {
-                       res = PQexec(pset.db, "ROLLBACK");
-                       PQclear(res);
-               }
-               return false;
+               return fail_lo_xact("\\lo_import", own_transaction);
        }
 
        /* insert description if given */
-       /* XXX don't try to hack pg_description if not superuser */
-       /* XXX ought to replace this with some kind of COMMENT command */
-       if (comment_arg && pset.issuper)
+       if (comment_arg)
        {
                char       *cmdbuf;
                char       *bufptr;
@@ -202,57 +203,27 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 
                cmdbuf = malloc(slen * 2 + 256);
                if (!cmdbuf)
-               {
-                       if (own_transaction)
-                       {
-                               res = PQexec(pset.db, "ROLLBACK");
-                               PQclear(res);
-                       }
-                       return false;
-               }
-               sprintf(cmdbuf,
-                               "INSERT INTO pg_catalog.pg_description VALUES ('%u', "
-                               "'pg_catalog.pg_largeobject'::regclass, "
-                               "0, '",
-                               loid);
+                       return fail_lo_xact("\\lo_import", own_transaction);
+               sprintf(cmdbuf, "COMMENT ON LARGE OBJECT %u IS '", loid);
                bufptr = cmdbuf + strlen(cmdbuf);
-               for (i = 0; i < slen; i++)
-               {
-                       if (comment_arg[i] == '\'' || comment_arg[i] == '\\')
-                               *bufptr++ = '\\';
-                       *bufptr++ = comment_arg[i];
-               }
-               strcpy(bufptr, "')");
+               bufptr += PQescapeStringConn(pset.db, bufptr, comment_arg, slen, NULL);
+               strcpy(bufptr, "'");
 
                if (!(res = PSQLexec(cmdbuf, false)))
                {
-                       if (own_transaction)
-                       {
-                               res = PQexec(pset.db, "ROLLBACK");
-                               PQclear(res);
-                       }
                        free(cmdbuf);
-                       return false;
+                       return fail_lo_xact("\\lo_import", own_transaction);
                }
 
                PQclear(res);
                free(cmdbuf);
        }
 
-       if (own_transaction)
-       {
-               if (!(res = PSQLexec("COMMIT", false)))
-               {
-                       res = PQexec(pset.db, "ROLLBACK");
-                       PQclear(res);
-                       return false;
-               }
-
-               PQclear(res);
-       }
+       if (!finish_lo_xact("\\lo_import", own_transaction))
+               return false;
 
+       print_lo_result("lo_import %u", loid);
 
-       fprintf(pset.queryFout, "lo_import %u\n", loid);
        sprintf(oidbuf, "%u", loid);
        SetVariable(pset.vars, "LASTOID", oidbuf);
 
@@ -260,7 +231,6 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 }
 
 
-
 /*
  * do_lo_unlink()
  *
@@ -269,76 +239,27 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 bool
 do_lo_unlink(const char *loid_arg)
 {
-       PGresult   *res;
        int                     status;
        Oid                     loid = atooid(loid_arg);
-       char            buf[256];
        bool            own_transaction;
 
-       own_transaction = !VariableEquals(pset.vars, "LO_TRANSACTION", "nothing");
-
-       if (!pset.db)
-       {
-               psql_error("\\lo_unlink: not connected to a database\n");
+       if (!start_lo_xact("\\lo_unlink", &own_transaction))
                return false;
-       }
-
-       if (own_transaction)
-       {
-               if (!handle_transaction())
-                       return false;
-
-               if (!(res = PSQLexec("BEGIN", false)))
-                       return false;
-
-               PQclear(res);
-       }
 
+       SetCancelConn();
        status = lo_unlink(pset.db, loid);
+       ResetCancelConn();
+
        if (status == -1)
        {
                fputs(PQerrorMessage(pset.db), stderr);
-               if (own_transaction)
-               {
-                       res = PQexec(pset.db, "ROLLBACK");
-                       PQclear(res);
-               }
-               return false;
-       }
-
-       /* remove the comment as well */
-       /* XXX don't try to hack pg_description if not superuser */
-       /* XXX ought to replace this with some kind of COMMENT command */
-       if (pset.issuper)
-       {
-               snprintf(buf, sizeof(buf),
-                                "DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
-                                "AND classoid = 'pg_catalog.pg_largeobject'::regclass",
-                                loid);
-               if (!(res = PSQLexec(buf, false)))
-               {
-                       if (own_transaction)
-                       {
-                               res = PQexec(pset.db, "ROLLBACK");
-                               PQclear(res);
-                       }
-                       return false;
-               }
-       }
-
-       if (own_transaction)
-       {
-               if (!(res = PSQLexec("COMMIT", false)))
-               {
-                       res = PQexec(pset.db, "ROLLBACK");
-                       PQclear(res);
-                       return false;
-               }
-               PQclear(res);
+               return fail_lo_xact("\\lo_unlink", own_transaction);
        }
 
+       if (!finish_lo_xact("\\lo_unlink", own_transaction))
+               return false;
 
-       fprintf(pset.queryFout, "lo_unlink %u\n", loid);
+       print_lo_result("lo_unlink %u", loid);
 
        return true;
 }
@@ -357,11 +278,28 @@ do_lo_list(void)
        char            buf[1024];
        printQueryOpt myopt = pset.popt;
 
-       snprintf(buf, sizeof(buf),
-                        "SELECT loid as \"ID\", pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
-                "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
-                        "ORDER BY \"ID\"",
-                        gettext("Description"));
+       if (pset.sversion >= 90000)
+       {
+               snprintf(buf, sizeof(buf),
+                                "SELECT oid as \"%s\",\n"
+                                "  pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n"
+                       "  pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
+                                "  FROM pg_catalog.pg_largeobject_metadata "
+                                "  ORDER BY oid",
+                                gettext_noop("ID"),
+                                gettext_noop("Owner"),
+                                gettext_noop("Description"));
+       }
+       else
+       {
+               snprintf(buf, sizeof(buf),
+                                "SELECT loid as \"%s\",\n"
+                  "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
+                        "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
+                                "ORDER BY 1",
+                                gettext_noop("ID"),
+                                gettext_noop("Description"));
+       }
 
        res = PSQLexec(buf, false);
        if (!res)
@@ -369,9 +307,10 @@ do_lo_list(void)
 
        myopt.topt.tuples_only = false;
        myopt.nullPrint = NULL;
-       myopt.title = gettext("Large objects");
+       myopt.title = _("Large objects");
+       myopt.translate_header = true;
 
-       printQuery(res, &myopt, pset.queryFout);
+       printQuery(res, &myopt, pset.queryFout, pset.logfile);
 
        PQclear(res);
        return true;