Fix obsolete comment regarding FSM truncation.
[PostgreSQL.git] / src / bin / psql / large_obj.c
blobe029884c17e8c4a28d94df18f75381f6897f0bd8
1 /*
2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
6 * $PostgreSQL$
7 */
8 #include "postgres_fe.h"
9 #include "large_obj.h"
12 #include "settings.h"
13 #include "common.h"
15 static void
16 print_lo_result(const char *fmt,...)
17 __attribute__((format(printf, 1, 2)));
19 static void
20 print_lo_result(const char *fmt,...)
22 va_list ap;
24 if (!pset.quiet)
26 if (pset.popt.topt.format == PRINT_HTML)
27 fputs("<p>", pset.queryFout);
29 va_start(ap, fmt);
30 vfprintf(pset.queryFout, fmt, ap);
31 va_end(ap);
33 if (pset.popt.topt.format == PRINT_HTML)
34 fputs("</p>\n", pset.queryFout);
35 else
36 fputs("\n", pset.queryFout);
39 if (pset.logfile)
41 va_start(ap, fmt);
42 vfprintf(pset.logfile, fmt, ap);
43 va_end(ap);
44 fputs("\n", pset.logfile);
50 * Prepare to do a large-object operation. We *must* be inside a transaction
51 * block for all these operations, so start one if needed.
53 * Returns TRUE if okay, FALSE if failed. *own_transaction is set to indicate
54 * if we started our own transaction or not.
56 static bool
57 start_lo_xact(const char *operation, bool *own_transaction)
59 PGTransactionStatusType tstatus;
60 PGresult *res;
62 *own_transaction = false;
64 if (!pset.db)
66 psql_error("%s: not connected to a database\n", operation);
67 return false;
70 tstatus = PQtransactionStatus(pset.db);
72 switch (tstatus)
74 case PQTRANS_IDLE:
75 /* need to start our own xact */
76 if (!(res = PSQLexec("BEGIN", false)))
77 return false;
78 PQclear(res);
79 *own_transaction = true;
80 break;
81 case PQTRANS_INTRANS:
82 /* use the existing xact */
83 break;
84 case PQTRANS_INERROR:
85 psql_error("%s: current transaction is aborted\n", operation);
86 return false;
87 default:
88 psql_error("%s: unknown transaction status\n", operation);
89 return false;
92 return true;
96 * Clean up after a successful LO operation
98 static bool
99 finish_lo_xact(const char *operation, bool own_transaction)
101 PGresult *res;
103 if (own_transaction && pset.autocommit)
105 /* close out our own xact */
106 if (!(res = PSQLexec("COMMIT", false)))
108 res = PSQLexec("ROLLBACK", false);
109 PQclear(res);
110 return false;
112 PQclear(res);
115 return true;
119 * Clean up after a failed LO operation
121 static bool
122 fail_lo_xact(const char *operation, bool own_transaction)
124 PGresult *res;
126 if (own_transaction && pset.autocommit)
128 /* close out our own xact */
129 res = PSQLexec("ROLLBACK", false);
130 PQclear(res);
133 return false; /* always */
138 * do_lo_export()
140 * Write a large object to a file
142 bool
143 do_lo_export(const char *loid_arg, const char *filename_arg)
145 int status;
146 bool own_transaction;
148 if (!start_lo_xact("\\lo_export", &own_transaction))
149 return false;
151 SetCancelConn();
152 status = lo_export(pset.db, atooid(loid_arg), filename_arg);
153 ResetCancelConn();
155 /* of course this status is documented nowhere :( */
156 if (status != 1)
158 fputs(PQerrorMessage(pset.db), stderr);
159 return fail_lo_xact("\\lo_export", own_transaction);
162 if (!finish_lo_xact("\\lo_export", own_transaction))
163 return false;
165 print_lo_result("lo_export");
167 return true;
172 * do_lo_import()
174 * Copy large object from file to database
176 bool
177 do_lo_import(const char *filename_arg, const char *comment_arg)
179 PGresult *res;
180 Oid loid;
181 char oidbuf[32];
182 bool own_transaction;
184 if (!start_lo_xact("\\lo_import", &own_transaction))
185 return false;
187 SetCancelConn();
188 loid = lo_import(pset.db, filename_arg);
189 ResetCancelConn();
191 if (loid == InvalidOid)
193 fputs(PQerrorMessage(pset.db), stderr);
194 return fail_lo_xact("\\lo_import", own_transaction);
197 /* insert description if given */
198 if (comment_arg)
200 char *cmdbuf;
201 char *bufptr;
202 size_t slen = strlen(comment_arg);
204 cmdbuf = malloc(slen * 2 + 256);
205 if (!cmdbuf)
206 return fail_lo_xact("\\lo_import", own_transaction);
207 sprintf(cmdbuf, "COMMENT ON LARGE OBJECT %u IS '", loid);
208 bufptr = cmdbuf + strlen(cmdbuf);
209 bufptr += PQescapeStringConn(pset.db, bufptr, comment_arg, slen, NULL);
210 strcpy(bufptr, "'");
212 if (!(res = PSQLexec(cmdbuf, false)))
214 free(cmdbuf);
215 return fail_lo_xact("\\lo_import", own_transaction);
218 PQclear(res);
219 free(cmdbuf);
222 if (!finish_lo_xact("\\lo_import", own_transaction))
223 return false;
225 print_lo_result("lo_import %u", loid);
227 sprintf(oidbuf, "%u", loid);
228 SetVariable(pset.vars, "LASTOID", oidbuf);
230 return true;
235 * do_lo_unlink()
237 * removes a large object out of the database
239 bool
240 do_lo_unlink(const char *loid_arg)
242 int status;
243 Oid loid = atooid(loid_arg);
244 bool own_transaction;
246 if (!start_lo_xact("\\lo_unlink", &own_transaction))
247 return false;
249 SetCancelConn();
250 status = lo_unlink(pset.db, loid);
251 ResetCancelConn();
253 if (status == -1)
255 fputs(PQerrorMessage(pset.db), stderr);
256 return fail_lo_xact("\\lo_unlink", own_transaction);
259 if (!finish_lo_xact("\\lo_unlink", own_transaction))
260 return false;
262 print_lo_result("lo_unlink %u", loid);
264 return true;
270 * do_lo_list()
272 * Show all large objects in database with comments
274 bool
275 do_lo_list(void)
277 PGresult *res;
278 char buf[1024];
279 printQueryOpt myopt = pset.popt;
281 snprintf(buf, sizeof(buf),
282 "SELECT loid as \"%s\",\n"
283 " pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
284 "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
285 "ORDER BY 1",
286 gettext_noop("ID"),
287 gettext_noop("Description"));
289 res = PSQLexec(buf, false);
290 if (!res)
291 return false;
293 myopt.topt.tuples_only = false;
294 myopt.nullPrint = NULL;
295 myopt.title = _("Large objects");
296 myopt.translate_header = true;
298 printQuery(res, &myopt, pset.queryFout, pset.logfile);
300 PQclear(res);
301 return true;