YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/postgres/src/bin/psql/large_obj.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * psql - the PostgreSQL interactive terminal
3
 *
4
 * Copyright (c) 2000-2018, PostgreSQL Global Development Group
5
 *
6
 * src/bin/psql/large_obj.c
7
 */
8
#include "postgres_fe.h"
9
#include "large_obj.h"
10
11
12
#include "settings.h"
13
#include "common.h"
14
15
static void print_lo_result(const char *fmt,...) pg_attribute_printf(1, 2);
16
17
static void
18
print_lo_result(const char *fmt,...)
19
0
{
20
0
  va_list   ap;
21
22
0
  if (!pset.quiet)
23
0
  {
24
0
    if (pset.popt.topt.format == PRINT_HTML)
25
0
      fputs("<p>", pset.queryFout);
26
27
0
    va_start(ap, fmt);
28
0
    vfprintf(pset.queryFout, fmt, ap);
29
0
    va_end(ap);
30
31
0
    if (pset.popt.topt.format == PRINT_HTML)
32
0
      fputs("</p>\n", pset.queryFout);
33
0
    else
34
0
      fputs("\n", pset.queryFout);
35
0
  }
36
37
0
  if (pset.logfile)
38
0
  {
39
0
    va_start(ap, fmt);
40
0
    vfprintf(pset.logfile, fmt, ap);
41
0
    va_end(ap);
42
0
    fputs("\n", pset.logfile);
43
0
  }
44
0
}
45
46
47
/*
48
 * Prepare to do a large-object operation.  We *must* be inside a transaction
49
 * block for all these operations, so start one if needed.
50
 *
51
 * Returns true if okay, false if failed.  *own_transaction is set to indicate
52
 * if we started our own transaction or not.
53
 */
54
static bool
55
start_lo_xact(const char *operation, bool *own_transaction)
56
0
{
57
0
  PGTransactionStatusType tstatus;
58
0
  PGresult   *res;
59
60
0
  *own_transaction = false;
61
62
0
  if (!pset.db)
63
0
  {
64
0
    psql_error("%s: not connected to a database\n", operation);
65
0
    return false;
66
0
  }
67
68
0
  tstatus = PQtransactionStatus(pset.db);
69
70
0
  switch (tstatus)
71
0
  {
72
0
    case PQTRANS_IDLE:
73
      /* need to start our own xact */
74
0
      if (!(res = PSQLexec("BEGIN")))
75
0
        return false;
76
0
      PQclear(res);
77
0
      *own_transaction = true;
78
0
      break;
79
0
    case PQTRANS_INTRANS:
80
      /* use the existing xact */
81
0
      break;
82
0
    case PQTRANS_INERROR:
83
0
      psql_error("%s: current transaction is aborted\n", operation);
84
0
      return false;
85
0
    default:
86
0
      psql_error("%s: unknown transaction status\n", operation);
87
0
      return false;
88
0
  }
89
90
0
  return true;
91
0
}
92
93
/*
94
 * Clean up after a successful LO operation
95
 */
96
static bool
97
finish_lo_xact(const char *operation, bool own_transaction)
98
0
{
99
0
  PGresult   *res;
100
101
0
  if (own_transaction && pset.autocommit)
102
0
  {
103
    /* close out our own xact */
104
0
    if (!(res = PSQLexec("COMMIT")))
105
0
    {
106
0
      res = PSQLexec("ROLLBACK");
107
0
      PQclear(res);
108
0
      return false;
109
0
    }
110
0
    PQclear(res);
111
0
  }
112
113
0
  return true;
114
0
}
115
116
/*
117
 * Clean up after a failed LO operation
118
 */
119
static bool
120
fail_lo_xact(const char *operation, bool own_transaction)
121
0
{
122
0
  PGresult   *res;
123
124
0
  if (own_transaction && pset.autocommit)
125
0
  {
126
    /* close out our own xact */
127
0
    res = PSQLexec("ROLLBACK");
128
0
    PQclear(res);
129
0
  }
130
131
0
  return false;       /* always */
132
0
}
133
134
135
/*
136
 * do_lo_export()
137
 *
138
 * Write a large object to a file
139
 */
140
bool
141
do_lo_export(const char *loid_arg, const char *filename_arg)
142
0
{
143
0
  int     status;
144
0
  bool    own_transaction;
145
146
0
  if (!start_lo_xact("\\lo_export", &own_transaction))
147
0
    return false;
148
149
0
  SetCancelConn();
150
0
  status = lo_export(pset.db, atooid(loid_arg), filename_arg);
151
0
  ResetCancelConn();
152
153
  /* of course this status is documented nowhere :( */
154
0
  if (status != 1)
155
0
  {
156
0
    psql_error("%s", PQerrorMessage(pset.db));
157
0
    return fail_lo_xact("\\lo_export", own_transaction);
158
0
  }
159
160
0
  if (!finish_lo_xact("\\lo_export", own_transaction))
161
0
    return false;
162
163
0
  print_lo_result("lo_export");
164
165
0
  return true;
166
0
}
167
168
169
/*
170
 * do_lo_import()
171
 *
172
 * Copy large object from file to database
173
 */
174
bool
175
do_lo_import(const char *filename_arg, const char *comment_arg)
176
0
{
177
0
  PGresult   *res;
178
0
  Oid     loid;
179
0
  char    oidbuf[32];
180
0
  bool    own_transaction;
181
182
0
  if (!start_lo_xact("\\lo_import", &own_transaction))
183
0
    return false;
184
185
0
  SetCancelConn();
186
0
  loid = lo_import(pset.db, filename_arg);
187
0
  ResetCancelConn();
188
189
0
  if (loid == InvalidOid)
190
0
  {
191
0
    psql_error("%s", PQerrorMessage(pset.db));
192
0
    return fail_lo_xact("\\lo_import", own_transaction);
193
0
  }
194
195
  /* insert description if given */
196
0
  if (comment_arg)
197
0
  {
198
0
    char     *cmdbuf;
199
0
    char     *bufptr;
200
0
    size_t    slen = strlen(comment_arg);
201
202
0
    cmdbuf = malloc(slen * 2 + 256);
203
0
    if (!cmdbuf)
204
0
      return fail_lo_xact("\\lo_import", own_transaction);
205
0
    sprintf(cmdbuf, "COMMENT ON LARGE OBJECT %u IS '", loid);
206
0
    bufptr = cmdbuf + strlen(cmdbuf);
207
0
    bufptr += PQescapeStringConn(pset.db, bufptr, comment_arg, slen, NULL);
208
0
    strcpy(bufptr, "'");
209
210
0
    if (!(res = PSQLexec(cmdbuf)))
211
0
    {
212
0
      free(cmdbuf);
213
0
      return fail_lo_xact("\\lo_import", own_transaction);
214
0
    }
215
216
0
    PQclear(res);
217
0
    free(cmdbuf);
218
0
  }
219
220
0
  if (!finish_lo_xact("\\lo_import", own_transaction))
221
0
    return false;
222
223
0
  print_lo_result("lo_import %u", loid);
224
225
0
  sprintf(oidbuf, "%u", loid);
226
0
  SetVariable(pset.vars, "LASTOID", oidbuf);
227
228
0
  return true;
229
0
}
230
231
232
/*
233
 * do_lo_unlink()
234
 *
235
 * removes a large object out of the database
236
 */
237
bool
238
do_lo_unlink(const char *loid_arg)
239
0
{
240
0
  int     status;
241
0
  Oid     loid = atooid(loid_arg);
242
0
  bool    own_transaction;
243
244
0
  if (!start_lo_xact("\\lo_unlink", &own_transaction))
245
0
    return false;
246
247
0
  SetCancelConn();
248
0
  status = lo_unlink(pset.db, loid);
249
0
  ResetCancelConn();
250
251
0
  if (status == -1)
252
0
  {
253
0
    psql_error("%s", PQerrorMessage(pset.db));
254
0
    return fail_lo_xact("\\lo_unlink", own_transaction);
255
0
  }
256
257
0
  if (!finish_lo_xact("\\lo_unlink", own_transaction))
258
0
    return false;
259
260
0
  print_lo_result("lo_unlink %u", loid);
261
262
0
  return true;
263
0
}
264
265
266
267
/*
268
 * do_lo_list()
269
 *
270
 * Show all large objects in database with comments
271
 */
272
bool
273
do_lo_list(void)
274
0
{
275
0
  PGresult   *res;
276
0
  char    buf[1024];
277
0
  printQueryOpt myopt = pset.popt;
278
279
0
  if (pset.sversion >= 90000)
280
0
  {
281
0
    snprintf(buf, sizeof(buf),
282
0
         "SELECT oid as \"%s\",\n"
283
0
         "  pg_catalog.pg_get_userbyid(lomowner) as \"%s\",\n"
284
0
         "  pg_catalog.obj_description(oid, 'pg_largeobject') as \"%s\"\n"
285
0
         "  FROM pg_catalog.pg_largeobject_metadata "
286
0
         "  ORDER BY oid",
287
0
         gettext_noop("ID"),
288
0
         gettext_noop("Owner"),
289
0
         gettext_noop("Description"));
290
0
  }
291
0
  else
292
0
  {
293
0
    snprintf(buf, sizeof(buf),
294
0
         "SELECT loid as \"%s\",\n"
295
0
         "  pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
296
0
         "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
297
0
         "ORDER BY 1",
298
0
         gettext_noop("ID"),
299
0
         gettext_noop("Description"));
300
0
  }
301
302
0
  res = PSQLexec(buf);
303
0
  if (!res)
304
0
    return false;
305
306
0
  myopt.topt.tuples_only = false;
307
0
  myopt.nullPrint = NULL;
308
0
  myopt.title = _("Large objects");
309
0
  myopt.translate_header = true;
310
311
0
  printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
312
313
0
  PQclear(res);
314
0
  return true;
315
0
}