00001
00002
00003
00004
00005
00006
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
00051
00052
00053
00054
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
00076 if (!(res = PSQLexec("BEGIN", false)))
00077 return false;
00078 PQclear(res);
00079 *own_transaction = true;
00080 break;
00081 case PQTRANS_INTRANS:
00082
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
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
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
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
00129 res = PSQLexec("ROLLBACK", false);
00130 PQclear(res);
00131 }
00132
00133 return false;
00134 }
00135
00136
00137
00138
00139
00140
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
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
00173
00174
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
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
00236
00237
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
00271
00272
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 }