2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2025, PostgreSQL Global Development Group
6 * src/bin/psql/large_obj.c
8 #include "postgres_fe.h"
11 #include "common/logging.h"
12 #include "fe_utils/cancel.h"
13 #include "large_obj.h"
16 static void print_lo_result(const char *fmt
,...) pg_attribute_printf(1, 2);
19 print_lo_result(const char *fmt
,...)
25 if (pset
.popt
.topt
.format
== PRINT_HTML
)
26 fputs("<p>", pset
.queryFout
);
29 vfprintf(pset
.queryFout
, fmt
, ap
);
32 if (pset
.popt
.topt
.format
== PRINT_HTML
)
33 fputs("</p>\n", pset
.queryFout
);
35 fputs("\n", pset
.queryFout
);
41 vfprintf(pset
.logfile
, fmt
, ap
);
43 fputs("\n", pset
.logfile
);
49 * Prepare to do a large-object operation. We *must* be inside a transaction
50 * block for all these operations, so start one if needed.
52 * Returns true if okay, false if failed. *own_transaction is set to indicate
53 * if we started our own transaction or not.
56 start_lo_xact(const char *operation
, bool *own_transaction
)
58 PGTransactionStatusType tstatus
;
61 *own_transaction
= false;
65 pg_log_error("%s: not connected to a database", operation
);
69 tstatus
= PQtransactionStatus(pset
.db
);
74 /* need to start our own xact */
75 if (!(res
= PSQLexec("BEGIN")))
78 *own_transaction
= true;
81 /* use the existing xact */
84 pg_log_error("%s: current transaction is aborted", operation
);
87 pg_log_error("%s: unknown transaction status", operation
);
95 * Clean up after a successful LO operation
98 finish_lo_xact(const char *operation
, bool own_transaction
)
102 if (own_transaction
&& pset
.autocommit
)
104 /* close out our own xact */
105 if (!(res
= PSQLexec("COMMIT")))
107 res
= PSQLexec("ROLLBACK");
118 * Clean up after a failed LO operation
121 fail_lo_xact(const char *operation
, bool own_transaction
)
125 if (own_transaction
&& pset
.autocommit
)
127 /* close out our own xact */
128 res
= PSQLexec("ROLLBACK");
132 return false; /* always */
139 * Write a large object to a file
142 do_lo_export(const char *loid_arg
, const char *filename_arg
)
145 bool own_transaction
;
147 if (!start_lo_xact("\\lo_export", &own_transaction
))
151 status
= lo_export(pset
.db
, atooid(loid_arg
), filename_arg
);
154 /* of course this status is documented nowhere :( */
157 pg_log_info("%s", PQerrorMessage(pset
.db
));
158 return fail_lo_xact("\\lo_export", own_transaction
);
161 if (!finish_lo_xact("\\lo_export", own_transaction
))
164 print_lo_result("lo_export");
173 * Copy large object from file to database
176 do_lo_import(const char *filename_arg
, const char *comment_arg
)
181 bool own_transaction
;
183 if (!start_lo_xact("\\lo_import", &own_transaction
))
187 loid
= lo_import(pset
.db
, filename_arg
);
190 if (loid
== InvalidOid
)
192 pg_log_info("%s", PQerrorMessage(pset
.db
));
193 return fail_lo_xact("\\lo_import", own_transaction
);
196 /* insert description if given */
201 size_t slen
= strlen(comment_arg
);
203 cmdbuf
= pg_malloc_extended(slen
* 2 + 256, MCXT_ALLOC_NO_OOM
);
205 return fail_lo_xact("\\lo_import", own_transaction
);
206 sprintf(cmdbuf
, "COMMENT ON LARGE OBJECT %u IS '", loid
);
207 bufptr
= cmdbuf
+ strlen(cmdbuf
);
208 bufptr
+= PQescapeStringConn(pset
.db
, bufptr
, comment_arg
, slen
, NULL
);
211 if (!(res
= PSQLexec(cmdbuf
)))
214 return fail_lo_xact("\\lo_import", own_transaction
);
221 if (!finish_lo_xact("\\lo_import", own_transaction
))
224 print_lo_result("lo_import %u", loid
);
226 sprintf(oidbuf
, "%u", loid
);
227 SetVariable(pset
.vars
, "LASTOID", oidbuf
);
236 * removes a large object out of the database
239 do_lo_unlink(const char *loid_arg
)
242 Oid loid
= atooid(loid_arg
);
243 bool own_transaction
;
245 if (!start_lo_xact("\\lo_unlink", &own_transaction
))
249 status
= lo_unlink(pset
.db
, loid
);
254 pg_log_info("%s", PQerrorMessage(pset
.db
));
255 return fail_lo_xact("\\lo_unlink", own_transaction
);
258 if (!finish_lo_xact("\\lo_unlink", own_transaction
))
261 print_lo_result("lo_unlink %u", loid
);