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/command.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/command.c
7
 */
8
#include "postgres_fe.h"
9
#include "command.h"
10
11
#include <ctype.h>
12
#include <time.h>
13
#include <pwd.h>
14
#include <utime.h>
15
#ifndef WIN32
16
#include <sys/stat.h>     /* for stat() */
17
#include <fcntl.h>        /* open() flags */
18
#include <unistd.h>       /* for geteuid(), getpid(), stat() */
19
#else
20
#include <win32.h>
21
#include <io.h>
22
#include <fcntl.h>
23
#include <direct.h>
24
#include <sys/stat.h>     /* for stat() */
25
#endif
26
27
#include "catalog/pg_class_d.h"
28
#include "portability/instr_time.h"
29
30
#include "libpq-fe.h"
31
#include "pqexpbuffer.h"
32
#include "fe_utils/string_utils.h"
33
34
#include "common.h"
35
#include "copy.h"
36
#include "crosstabview.h"
37
#include "describe.h"
38
#include "help.h"
39
#include "input.h"
40
#include "large_obj.h"
41
#include "mainloop.h"
42
#include "fe_utils/print.h"
43
#include "psqlscanslash.h"
44
#include "settings.h"
45
#include "variables.h"
46
47
/*
48
 * Editable database object types.
49
 */
50
typedef enum EditableObjectType
51
{
52
  EditableFunction,
53
  EditableView
54
} EditableObjectType;
55
56
/* local function declarations */
57
static backslashResult exec_command(const char *cmd,
58
       PsqlScanState scan_state,
59
       ConditionalStack cstack,
60
       PQExpBuffer query_buf,
61
       PQExpBuffer previous_buf);
62
static backslashResult exec_command_a(PsqlScanState scan_state, bool active_branch);
63
static backslashResult exec_command_C(PsqlScanState scan_state, bool active_branch);
64
static backslashResult exec_command_connect(PsqlScanState scan_state, bool active_branch);
65
static backslashResult exec_command_cd(PsqlScanState scan_state, bool active_branch,
66
        const char *cmd);
67
static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch);
68
static backslashResult exec_command_copy(PsqlScanState scan_state, bool active_branch);
69
static backslashResult exec_command_copyright(PsqlScanState scan_state, bool active_branch);
70
static backslashResult exec_command_crosstabview(PsqlScanState scan_state, bool active_branch);
71
static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch,
72
         const char *cmd);
73
static backslashResult exec_command_edit(PsqlScanState scan_state, bool active_branch,
74
          PQExpBuffer query_buf, PQExpBuffer previous_buf);
75
static backslashResult exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
76
           PQExpBuffer query_buf, bool is_func);
77
static backslashResult exec_command_echo(PsqlScanState scan_state, bool active_branch,
78
          const char *cmd);
79
static backslashResult exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
80
          PQExpBuffer query_buf);
81
static backslashResult exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
82
          PQExpBuffer query_buf);
83
static backslashResult exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
84
           PQExpBuffer query_buf);
85
static backslashResult exec_command_encoding(PsqlScanState scan_state, bool active_branch);
86
static backslashResult exec_command_errverbose(PsqlScanState scan_state, bool active_branch);
87
static backslashResult exec_command_f(PsqlScanState scan_state, bool active_branch);
88
static backslashResult exec_command_g(PsqlScanState scan_state, bool active_branch,
89
         const char *cmd);
90
static backslashResult exec_command_gdesc(PsqlScanState scan_state, bool active_branch);
91
static backslashResult exec_command_gexec(PsqlScanState scan_state, bool active_branch);
92
static backslashResult exec_command_gset(PsqlScanState scan_state, bool active_branch);
93
static backslashResult exec_command_help(PsqlScanState scan_state, bool active_branch);
94
static backslashResult exec_command_html(PsqlScanState scan_state, bool active_branch);
95
static backslashResult exec_command_include(PsqlScanState scan_state, bool active_branch,
96
           const char *cmd);
97
static backslashResult exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
98
        PQExpBuffer query_buf);
99
static backslashResult exec_command_list(PsqlScanState scan_state, bool active_branch,
100
          const char *cmd);
101
static backslashResult exec_command_lo(PsqlScanState scan_state, bool active_branch,
102
        const char *cmd);
103
static backslashResult exec_command_out(PsqlScanState scan_state, bool active_branch);
104
static backslashResult exec_command_print(PsqlScanState scan_state, bool active_branch,
105
           PQExpBuffer query_buf, PQExpBuffer previous_buf);
106
static backslashResult exec_command_password(PsqlScanState scan_state, bool active_branch);
107
static backslashResult exec_command_prompt(PsqlScanState scan_state, bool active_branch,
108
          const char *cmd);
109
static backslashResult exec_command_pset(PsqlScanState scan_state, bool active_branch);
110
static backslashResult exec_command_quit(PsqlScanState scan_state, bool active_branch);
111
static backslashResult exec_command_reset(PsqlScanState scan_state, bool active_branch,
112
           PQExpBuffer query_buf);
113
static backslashResult exec_command_s(PsqlScanState scan_state, bool active_branch);
114
static backslashResult exec_command_set(PsqlScanState scan_state, bool active_branch);
115
static backslashResult exec_command_setenv(PsqlScanState scan_state, bool active_branch,
116
          const char *cmd);
117
static backslashResult exec_command_sf_sv(PsqlScanState scan_state, bool active_branch,
118
           const char *cmd, bool is_func);
119
static backslashResult exec_command_t(PsqlScanState scan_state, bool active_branch);
120
static backslashResult exec_command_T(PsqlScanState scan_state, bool active_branch);
121
static backslashResult exec_command_timing(PsqlScanState scan_state, bool active_branch);
122
static backslashResult exec_command_unset(PsqlScanState scan_state, bool active_branch,
123
           const char *cmd);
124
static backslashResult exec_command_write(PsqlScanState scan_state, bool active_branch,
125
           const char *cmd,
126
           PQExpBuffer query_buf, PQExpBuffer previous_buf);
127
static backslashResult exec_command_watch(PsqlScanState scan_state, bool active_branch,
128
           PQExpBuffer query_buf, PQExpBuffer previous_buf);
129
static backslashResult exec_command_x(PsqlScanState scan_state, bool active_branch);
130
static backslashResult exec_command_z(PsqlScanState scan_state, bool active_branch);
131
static backslashResult exec_command_shell_escape(PsqlScanState scan_state, bool active_branch);
132
static backslashResult exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch);
133
static char *read_connect_arg(PsqlScanState scan_state);
134
static PQExpBuffer gather_boolean_expression(PsqlScanState scan_state);
135
static bool is_true_boolean_expression(PsqlScanState scan_state, const char *name);
136
static void ignore_boolean_expression(PsqlScanState scan_state);
137
static void ignore_slash_options(PsqlScanState scan_state);
138
static void ignore_slash_filepipe(PsqlScanState scan_state);
139
static void ignore_slash_whole_line(PsqlScanState scan_state);
140
static bool is_branching_command(const char *cmd);
141
static void save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
142
            PQExpBuffer query_buf);
143
static void discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
144
           PQExpBuffer query_buf);
145
static void copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf);
146
static bool do_connect(enum trivalue reuse_previous_specification,
147
       char *dbname, char *user, char *host, char *port);
148
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
149
    int lineno, bool *edited);
150
static bool do_shell(const char *command);
151
static bool do_watch(PQExpBuffer query_buf, double sleep);
152
static bool lookup_object_oid(EditableObjectType obj_type, const char *desc,
153
          Oid *obj_oid);
154
static bool get_create_object_cmd(EditableObjectType obj_type, Oid oid,
155
            PQExpBuffer buf);
156
static int  strip_lineno_from_objdesc(char *obj);
157
static int  count_lines_in_buf(PQExpBuffer buf);
158
static void print_with_linenumbers(FILE *output, char *lines,
159
             const char *header_keyword);
160
static void minimal_error_message(PGresult *res);
161
162
static void printSSLInfo(void);
163
static bool printPsetInfo(const char *param, struct printQueryOpt *popt);
164
static char *pset_value_string(const char *param, struct printQueryOpt *popt);
165
166
#ifdef WIN32
167
static void checkWin32Codepage(void);
168
#endif
169
170
171
172
/*----------
173
 * HandleSlashCmds:
174
 *
175
 * Handles all the different commands that start with '\'.
176
 * Ordinarily called by MainLoop().
177
 *
178
 * scan_state is a lexer working state that is set to continue scanning
179
 * just after the '\'.  The lexer is advanced past the command and all
180
 * arguments on return.
181
 *
182
 * cstack is the current \if stack state.  This will be examined, and
183
 * possibly modified by conditional commands.
184
 *
185
 * query_buf contains the query-so-far, which may be modified by
186
 * execution of the backslash command (for example, \r clears it).
187
 *
188
 * previous_buf contains the query most recently sent to the server
189
 * (empty if none yet).  This should not be modified here, but some
190
 * commands copy its content into query_buf.
191
 *
192
 * query_buf and previous_buf will be NULL when executing a "-c"
193
 * command-line option.
194
 *
195
 * Returns a status code indicating what action is desired, see command.h.
196
 *----------
197
 */
198
199
backslashResult
200
HandleSlashCmds(PsqlScanState scan_state,
201
        ConditionalStack cstack,
202
        PQExpBuffer query_buf,
203
        PQExpBuffer previous_buf)
204
62
{
205
62
  backslashResult status;
206
62
  char     *cmd;
207
62
  char     *arg;
208
209
62
  Assert(scan_state != NULL);
210
62
  Assert(cstack != NULL);
211
212
  /* Parse off the command name */
213
62
  cmd = psql_scan_slash_command(scan_state);
214
215
  /* And try to execute it */
216
62
  status = exec_command(cmd, scan_state, cstack, query_buf, previous_buf);
217
218
62
  if (status == PSQL_CMD_UNKNOWN)
219
0
  {
220
0
    if (pset.cur_cmd_interactive)
221
0
      psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
222
0
    else
223
0
      psql_error("invalid command \\%s\n", cmd);
224
0
    status = PSQL_CMD_ERROR;
225
0
  }
226
227
62
  if (status != PSQL_CMD_ERROR)
228
60
  {
229
    /*
230
     * Eat any remaining arguments after a valid command.  We want to
231
     * suppress evaluation of backticks in this situation, so transiently
232
     * push an inactive conditional-stack entry.
233
     */
234
60
    bool    active_branch = conditional_active(cstack);
235
236
60
    conditional_stack_push(cstack, IFSTATE_IGNORED);
237
60
    while ((arg = psql_scan_slash_option(scan_state,
238
60
                       OT_NORMAL, NULL, false)))
239
0
    {
240
0
      if (active_branch)
241
0
        psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
242
0
      free(arg);
243
0
    }
244
60
    conditional_stack_pop(cstack);
245
60
  }
246
2
  else
247
2
  {
248
    /* silently throw away rest of line after an erroneous command */
249
2
    while ((arg = psql_scan_slash_option(scan_state,
250
2
                       OT_WHOLE_LINE, NULL, false)))
251
0
      free(arg);
252
2
  }
253
254
  /* if there is a trailing \\, swallow it */
255
62
  psql_scan_slash_command_end(scan_state);
256
257
62
  free(cmd);
258
259
  /* some commands write to queryFout, so make sure output is sent */
260
62
  fflush(pset.queryFout);
261
262
62
  return status;
263
62
}
264
265
266
/*
267
 * Subroutine to actually try to execute a backslash command.
268
 *
269
 * The typical "success" result code is PSQL_CMD_SKIP_LINE, although some
270
 * commands return something else.  Failure results are PSQL_CMD_ERROR,
271
 * unless PSQL_CMD_UNKNOWN is more appropriate.
272
 */
273
static backslashResult
274
exec_command(const char *cmd,
275
       PsqlScanState scan_state,
276
       ConditionalStack cstack,
277
       PQExpBuffer query_buf,
278
       PQExpBuffer previous_buf)
279
62
{
280
62
  backslashResult status;
281
62
  bool    active_branch = conditional_active(cstack);
282
283
  /*
284
   * In interactive mode, warn when we're ignoring a command within a false
285
   * \if-branch.  But we continue on, so as to parse and discard the right
286
   * amount of parameter text.  Each individual backslash command subroutine
287
   * is responsible for doing nothing after discarding appropriate
288
   * arguments, if !active_branch.
289
   */
290
62
  if (pset.cur_cmd_interactive && !active_branch &&
291
0
    !is_branching_command(cmd))
292
0
  {
293
0
    psql_error("\\%s command ignored; use \\endif or Ctrl-C to exit current \\if block\n",
294
0
           cmd);
295
0
  }
296
297
62
  if (strcmp(cmd, "a") == 0)
298
0
    status = exec_command_a(scan_state, active_branch);
299
62
  else if (strcmp(cmd, "C") == 0)
300
0
    status = exec_command_C(scan_state, active_branch);
301
62
  else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
302
3
    status = exec_command_connect(scan_state, active_branch);
303
59
  else if (strcmp(cmd, "cd") == 0)
304
0
    status = exec_command_cd(scan_state, active_branch, cmd);
305
59
  else if (strcmp(cmd, "conninfo") == 0)
306
0
    status = exec_command_conninfo(scan_state, active_branch);
307
59
  else if (pg_strcasecmp(cmd, "copy") == 0)
308
6
    status = exec_command_copy(scan_state, active_branch);
309
53
  else if (strcmp(cmd, "copyright") == 0)
310
0
    status = exec_command_copyright(scan_state, active_branch);
311
53
  else if (strcmp(cmd, "crosstabview") == 0)
312
0
    status = exec_command_crosstabview(scan_state, active_branch);
313
53
  else if (cmd[0] == 'd')
314
40
    status = exec_command_d(scan_state, active_branch, cmd);
315
13
  else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
316
0
    status = exec_command_edit(scan_state, active_branch,
317
0
                   query_buf, previous_buf);
318
13
  else if (strcmp(cmd, "ef") == 0)
319
0
    status = exec_command_ef_ev(scan_state, active_branch, query_buf, true);
320
13
  else if (strcmp(cmd, "ev") == 0)
321
0
    status = exec_command_ef_ev(scan_state, active_branch, query_buf, false);
322
13
  else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
323
0
    status = exec_command_echo(scan_state, active_branch, cmd);
324
13
  else if (strcmp(cmd, "elif") == 0)
325
0
    status = exec_command_elif(scan_state, cstack, query_buf);
326
13
  else if (strcmp(cmd, "else") == 0)
327
0
    status = exec_command_else(scan_state, cstack, query_buf);
328
13
  else if (strcmp(cmd, "endif") == 0)
329
0
    status = exec_command_endif(scan_state, cstack, query_buf);
330
13
  else if (strcmp(cmd, "encoding") == 0)
331
0
    status = exec_command_encoding(scan_state, active_branch);
332
13
  else if (strcmp(cmd, "errverbose") == 0)
333
0
    status = exec_command_errverbose(scan_state, active_branch);
334
13
  else if (strcmp(cmd, "f") == 0)
335
0
    status = exec_command_f(scan_state, active_branch);
336
13
  else if (strcmp(cmd, "g") == 0 || strcmp(cmd, "gx") == 0)
337
0
    status = exec_command_g(scan_state, active_branch, cmd);
338
13
  else if (strcmp(cmd, "gdesc") == 0)
339
0
    status = exec_command_gdesc(scan_state, active_branch);
340
13
  else if (strcmp(cmd, "gexec") == 0)
341
0
    status = exec_command_gexec(scan_state, active_branch);
342
13
  else if (strcmp(cmd, "gset") == 0)
343
0
    status = exec_command_gset(scan_state, active_branch);
344
13
  else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
345
0
    status = exec_command_help(scan_state, active_branch);
346
13
  else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
347
0
    status = exec_command_html(scan_state, active_branch);
348
13
  else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0 ||
349
13
       strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
350
0
    status = exec_command_include(scan_state, active_branch, cmd);
351
13
  else if (strcmp(cmd, "if") == 0)
352
0
    status = exec_command_if(scan_state, cstack, query_buf);
353
13
  else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
354
13
       strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
355
0
    status = exec_command_list(scan_state, active_branch, cmd);
356
13
  else if (strncmp(cmd, "lo_", 3) == 0)
357
0
    status = exec_command_lo(scan_state, active_branch, cmd);
358
13
  else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
359
0
    status = exec_command_out(scan_state, active_branch);
360
13
  else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
361
0
    status = exec_command_print(scan_state, active_branch,
362
0
                  query_buf, previous_buf);
363
13
  else if (strcmp(cmd, "password") == 0)
364
0
    status = exec_command_password(scan_state, active_branch);
365
13
  else if (strcmp(cmd, "prompt") == 0)
366
0
    status = exec_command_prompt(scan_state, active_branch, cmd);
367
13
  else if (strcmp(cmd, "pset") == 0)
368
1
    status = exec_command_pset(scan_state, active_branch);
369
12
  else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
370
0
    status = exec_command_quit(scan_state, active_branch);
371
12
  else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
372
0
    status = exec_command_reset(scan_state, active_branch, query_buf);
373
12
  else if (strcmp(cmd, "s") == 0)
374
0
    status = exec_command_s(scan_state, active_branch);
375
12
  else if (strcmp(cmd, "set") == 0)
376
4
    status = exec_command_set(scan_state, active_branch);
377
8
  else if (strcmp(cmd, "setenv") == 0)
378
0
    status = exec_command_setenv(scan_state, active_branch, cmd);
379
8
  else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
380
0
    status = exec_command_sf_sv(scan_state, active_branch, cmd, true);
381
8
  else if (strcmp(cmd, "sv") == 0 || strcmp(cmd, "sv+") == 0)
382
0
    status = exec_command_sf_sv(scan_state, active_branch, cmd, false);
383
8
  else if (strcmp(cmd, "t") == 0)
384
8
    status = exec_command_t(scan_state, active_branch);
385
0
  else if (strcmp(cmd, "T") == 0)
386
0
    status = exec_command_T(scan_state, active_branch);
387
0
  else if (strcmp(cmd, "timing") == 0)
388
0
    status = exec_command_timing(scan_state, active_branch);
389
0
  else if (strcmp(cmd, "unset") == 0)
390
0
    status = exec_command_unset(scan_state, active_branch, cmd);
391
0
  else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
392
0
    status = exec_command_write(scan_state, active_branch, cmd,
393
0
                  query_buf, previous_buf);
394
0
  else if (strcmp(cmd, "watch") == 0)
395
0
    status = exec_command_watch(scan_state, active_branch,
396
0
                  query_buf, previous_buf);
397
0
  else if (strcmp(cmd, "x") == 0)
398
0
    status = exec_command_x(scan_state, active_branch);
399
0
  else if (strcmp(cmd, "z") == 0)
400
0
    status = exec_command_z(scan_state, active_branch);
401
0
  else if (strcmp(cmd, "!") == 0)
402
0
    status = exec_command_shell_escape(scan_state, active_branch);
403
0
  else if (strcmp(cmd, "?") == 0)
404
0
    status = exec_command_slash_command_help(scan_state, active_branch);
405
0
  else
406
0
    status = PSQL_CMD_UNKNOWN;
407
408
  /*
409
   * All the commands that return PSQL_CMD_SEND want to execute previous_buf
410
   * if query_buf is empty.  For convenience we implement that here, not in
411
   * the individual command subroutines.
412
   */
413
62
  if (status == PSQL_CMD_SEND)
414
0
    copy_previous_query(query_buf, previous_buf);
415
416
62
  return status;
417
62
}
418
419
420
/*
421
 * \a -- toggle field alignment
422
 *
423
 * This makes little sense but we keep it around.
424
 */
425
static backslashResult
426
exec_command_a(PsqlScanState scan_state, bool active_branch)
427
0
{
428
0
  bool    success = true;
429
430
0
  if (active_branch)
431
0
  {
432
0
    if (pset.popt.topt.format != PRINT_ALIGNED)
433
0
      success = do_pset("format", "aligned", &pset.popt, pset.quiet);
434
0
    else
435
0
      success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
436
0
  }
437
438
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
439
0
}
440
441
/*
442
 * \C -- override table title (formerly change HTML caption)
443
 */
444
static backslashResult
445
exec_command_C(PsqlScanState scan_state, bool active_branch)
446
0
{
447
0
  bool    success = true;
448
449
0
  if (active_branch)
450
0
  {
451
0
    char     *opt = psql_scan_slash_option(scan_state,
452
0
                         OT_NORMAL, NULL, true);
453
454
0
    success = do_pset("title", opt, &pset.popt, pset.quiet);
455
0
    free(opt);
456
0
  }
457
0
  else
458
0
    ignore_slash_options(scan_state);
459
460
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
461
0
}
462
463
/*
464
 * \c or \connect -- connect to database using the specified parameters.
465
 *
466
 * \c [-reuse-previous=BOOL] dbname user host port
467
 *
468
 * Specifying a parameter as '-' is equivalent to omitting it.  Examples:
469
 *
470
 * \c - - hst   Connect to current database on current port of
471
 *          host "hst" as current user.
472
 * \c - usr - prt Connect to current database on port "prt" of current host
473
 *          as user "usr".
474
 * \c dbs     Connect to database "dbs" on current port of current host
475
 *          as current user.
476
 */
477
static backslashResult
478
exec_command_connect(PsqlScanState scan_state, bool active_branch)
479
3
{
480
3
  bool    success = true;
481
482
3
  if (active_branch)
483
3
  {
484
3
    static const char prefix[] = "-reuse-previous=";
485
3
    char     *opt1,
486
3
           *opt2,
487
3
           *opt3,
488
3
           *opt4;
489
3
    enum trivalue reuse_previous = TRI_DEFAULT;
490
491
3
    opt1 = read_connect_arg(scan_state);
492
3
    if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0)
493
0
    {
494
0
      bool    on_off;
495
496
0
      success = ParseVariableBool(opt1 + sizeof(prefix) - 1,
497
0
                    "-reuse-previous",
498
0
                    &on_off);
499
0
      if (success)
500
0
      {
501
0
        reuse_previous = on_off ? TRI_YES : TRI_NO;
502
0
        free(opt1);
503
0
        opt1 = read_connect_arg(scan_state);
504
0
      }
505
0
    }
506
507
3
    if (success)     /* give up if reuse_previous was invalid */
508
3
    {
509
3
      opt2 = read_connect_arg(scan_state);
510
3
      opt3 = read_connect_arg(scan_state);
511
3
      opt4 = read_connect_arg(scan_state);
512
513
3
      success = do_connect(reuse_previous, opt1, opt2, opt3, opt4);
514
515
3
      free(opt2);
516
3
      free(opt3);
517
3
      free(opt4);
518
3
    }
519
3
    free(opt1);
520
3
  }
521
0
  else
522
0
    ignore_slash_options(scan_state);
523
524
2
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
525
3
}
526
527
/*
528
 * \cd -- change directory
529
 */
530
static backslashResult
531
exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
532
0
{
533
0
  bool    success = true;
534
535
0
  if (active_branch)
536
0
  {
537
0
    char     *opt = psql_scan_slash_option(scan_state,
538
0
                         OT_NORMAL, NULL, true);
539
0
    char     *dir;
540
541
0
    if (opt)
542
0
      dir = opt;
543
0
    else
544
0
    {
545
0
#ifndef WIN32
546
0
      struct passwd *pw;
547
0
      uid_t   user_id = geteuid();
548
549
0
      errno = 0;      /* clear errno before call */
550
0
      pw = getpwuid(user_id);
551
0
      if (!pw)
552
0
      {
553
0
        psql_error("could not get home directory for user ID %ld: %s\n",
554
0
               (long) user_id,
555
0
               errno ? strerror(errno) : _("user does not exist"));
556
0
        exit(EXIT_FAILURE);
557
0
      }
558
0
      dir = pw->pw_dir;
559
#else             /* WIN32 */
560
561
      /*
562
       * On Windows, 'cd' without arguments prints the current
563
       * directory, so if someone wants to code this here instead...
564
       */
565
      dir = "/";
566
#endif              /* WIN32 */
567
0
    }
568
569
0
    if (chdir(dir) == -1)
570
0
    {
571
0
      psql_error("\\%s: could not change directory to \"%s\": %s\n",
572
0
             cmd, dir, strerror(errno));
573
0
      success = false;
574
0
    }
575
576
0
    if (opt)
577
0
      free(opt);
578
0
  }
579
0
  else
580
0
    ignore_slash_options(scan_state);
581
582
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
583
0
}
584
585
/*
586
 * \conninfo -- display information about the current connection
587
 */
588
static backslashResult
589
exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
590
0
{
591
0
  if (active_branch)
592
0
  {
593
0
    char     *db = PQdb(pset.db);
594
595
0
    if (db == NULL)
596
0
      printf(_("You are currently not connected to a database.\n"));
597
0
    else
598
0
    {
599
0
      char     *host = PQhost(pset.db);
600
601
      /* If the host is an absolute path, the connection is via socket */
602
0
      if (is_absolute_path(host))
603
0
        printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
604
0
             db, PQuser(pset.db), host, PQport(pset.db));
605
0
      else
606
0
        printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
607
0
             db, PQuser(pset.db), host, PQport(pset.db));
608
0
      printSSLInfo();
609
0
    }
610
0
  }
611
612
0
  return PSQL_CMD_SKIP_LINE;
613
0
}
614
615
/*
616
 * \copy -- run a COPY command
617
 */
618
static backslashResult
619
exec_command_copy(PsqlScanState scan_state, bool active_branch)
620
6
{
621
6
  bool    success = true;
622
623
6
  if (active_branch)
624
6
  {
625
6
    char     *opt = psql_scan_slash_option(scan_state,
626
6
                         OT_WHOLE_LINE, NULL, false);
627
628
6
    success = do_copy(opt);
629
6
    free(opt);
630
6
  }
631
0
  else
632
0
    ignore_slash_whole_line(scan_state);
633
634
5
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
635
6
}
636
637
/*
638
 * \copyright -- print copyright notice
639
 */
640
static backslashResult
641
exec_command_copyright(PsqlScanState scan_state, bool active_branch)
642
0
{
643
0
  if (active_branch)
644
0
    print_copyright();
645
646
0
  return PSQL_CMD_SKIP_LINE;
647
0
}
648
649
/*
650
 * \crosstabview -- execute a query and display results in crosstab
651
 */
652
static backslashResult
653
exec_command_crosstabview(PsqlScanState scan_state, bool active_branch)
654
0
{
655
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
656
657
0
  if (active_branch)
658
0
  {
659
0
    int     i;
660
661
0
    for (i = 0; i < lengthof(pset.ctv_args); i++)
662
0
      pset.ctv_args[i] = psql_scan_slash_option(scan_state,
663
0
                            OT_NORMAL, NULL, true);
664
0
    pset.crosstab_flag = true;
665
0
    status = PSQL_CMD_SEND;
666
0
  }
667
0
  else
668
0
    ignore_slash_options(scan_state);
669
670
0
  return status;
671
0
}
672
673
/*
674
 * \d* commands
675
 */
676
static backslashResult
677
exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
678
40
{
679
40
  backslashResult status = PSQL_CMD_SKIP_LINE;
680
40
  bool    success = true;
681
682
40
  if (active_branch)
683
40
  {
684
40
    char     *pattern;
685
40
    bool    show_verbose,
686
40
          show_system;
687
688
    /* We don't do SQLID reduction on the pattern yet */
689
40
    pattern = psql_scan_slash_option(scan_state,
690
40
                     OT_NORMAL, NULL, true);
691
692
40
    show_verbose = strchr(cmd, '+') ? true : false;
693
40
    show_system = strchr(cmd, 'S') ? true : false;
694
695
40
    switch (cmd[1])
696
40
    {
697
13
      case '\0':
698
13
      case '+':
699
13
      case 'S':
700
13
        if (pattern)
701
13
          success = describeTableDetails(pattern, show_verbose, show_system);
702
0
        else
703
          /* standard listing of interesting things */
704
0
          success = listTables("tvmsE", NULL, show_verbose, show_system);
705
13
        break;
706
0
      case 'A':
707
0
        success = describeAccessMethods(pattern, show_verbose);
708
0
        break;
709
0
      case 'a':
710
0
        success = describeAggregates(pattern, show_verbose, show_system);
711
0
        break;
712
0
      case 'b':
713
0
        success = describeTablespaces(pattern, show_verbose);
714
0
        break;
715
0
      case 'c':
716
0
        success = listConversions(pattern, show_verbose, show_system);
717
0
        break;
718
0
      case 'C':
719
0
        success = listCasts(pattern, show_verbose);
720
0
        break;
721
0
      case 'd':
722
0
        if (strncmp(cmd, "ddp", 3) == 0)
723
0
          success = listDefaultACLs(pattern);
724
0
        else
725
0
          success = objectDescription(pattern, show_system);
726
0
        break;
727
0
      case 'D':
728
0
        success = listDomains(pattern, show_verbose, show_system);
729
0
        break;
730
4
      case 'f':     /* function subsystem */
731
4
        switch (cmd[2])
732
4
        {
733
4
          case '\0':
734
4
          case '+':
735
4
          case 'S':
736
4
          case 'a':
737
4
          case 'n':
738
4
          case 'p':
739
4
          case 't':
740
4
          case 'w':
741
4
            success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
742
4
            break;
743
0
          default:
744
0
            status = PSQL_CMD_UNKNOWN;
745
0
            break;
746
4
        }
747
4
        break;
748
0
      case 'g':
749
0
        if (strncmp(cmd, "dgrt", 4) == 0)
750
0
          success = listTablegroups(pattern, show_verbose, true);
751
0
        else if (strncmp(cmd, "dgr", 3) == 0)
752
0
        {
753
0
          success = listTablegroups(pattern, show_verbose, false);
754
0
        }
755
0
        else
756
0
        {
757
          /* no longer distinct from \du */
758
0
          success = describeRoles(pattern, show_verbose, show_system);
759
0
        }
760
0
        break;
761
0
      case 'l':
762
0
        success = do_lo_list();
763
0
        break;
764
0
      case 'L':
765
0
        success = listLanguages(pattern, show_verbose, show_system);
766
0
        break;
767
0
      case 'n':
768
0
        success = listSchemas(pattern, show_verbose, show_system);
769
0
        break;
770
4
      case 'o':
771
4
        success = describeOperators(pattern, show_verbose, show_system);
772
4
        break;
773
0
      case 'O':
774
0
        success = listCollations(pattern, show_verbose, show_system);
775
0
        break;
776
0
      case 'p':
777
0
        success = permissionsList(pattern);
778
0
        break;
779
7
      case 'T':
780
7
        success = describeTypes(pattern, show_verbose, show_system);
781
7
        break;
782
3
      case 't':
783
3
      case 'v':
784
3
      case 'm':
785
6
      case 'i':
786
6
      case 's':
787
6
      case 'E':
788
6
        success = listTables(&cmd[1], pattern, show_verbose, show_system);
789
6
        break;
790
0
      case 'r':
791
0
        if (cmd[2] == 'd' && cmd[3] == 's')
792
0
        {
793
0
          char     *pattern2 = NULL;
794
795
0
          if (pattern)
796
0
            pattern2 = psql_scan_slash_option(scan_state,
797
0
                              OT_NORMAL, NULL, true);
798
0
          success = listDbRoleSettings(pattern, pattern2);
799
800
0
          if (pattern2)
801
0
            free(pattern2);
802
0
        }
803
0
        else
804
0
          status = PSQL_CMD_UNKNOWN;
805
0
        break;
806
0
      case 'R':
807
0
        switch (cmd[2])
808
0
        {
809
0
          case 'p':
810
0
            if (show_verbose)
811
0
              success = describePublications(pattern);
812
0
            else
813
0
              success = listPublications(pattern);
814
0
            break;
815
0
          case 's':
816
0
            success = describeSubscriptions(pattern, show_verbose);
817
0
            break;
818
0
          default:
819
0
            status = PSQL_CMD_UNKNOWN;
820
0
        }
821
0
        break;
822
0
      case 'u':
823
0
        success = describeRoles(pattern, show_verbose, show_system);
824
0
        break;
825
0
      case 'F':     /* text search subsystem */
826
0
        switch (cmd[2])
827
0
        {
828
0
          case '\0':
829
0
          case '+':
830
0
            success = listTSConfigs(pattern, show_verbose);
831
0
            break;
832
0
          case 'p':
833
0
            success = listTSParsers(pattern, show_verbose);
834
0
            break;
835
0
          case 'd':
836
0
            success = listTSDictionaries(pattern, show_verbose);
837
0
            break;
838
0
          case 't':
839
0
            success = listTSTemplates(pattern, show_verbose);
840
0
            break;
841
0
          default:
842
0
            status = PSQL_CMD_UNKNOWN;
843
0
            break;
844
0
        }
845
0
        break;
846
6
      case 'e':     /* SQL/MED subsystem */
847
6
        switch (cmd[2])
848
6
        {
849
0
          case 's':
850
0
            success = listForeignServers(pattern, show_verbose);
851
0
            break;
852
0
          case 'u':
853
0
            success = listUserMappings(pattern, show_verbose);
854
0
            break;
855
0
          case 'w':
856
0
            success = listForeignDataWrappers(pattern, show_verbose);
857
0
            break;
858
6
          case 't':
859
6
            success = listForeignTables(pattern, show_verbose);
860
6
            break;
861
0
          default:
862
0
            status = PSQL_CMD_UNKNOWN;
863
0
            break;
864
6
        }
865
6
        break;
866
0
      case 'x':     /* Extensions */
867
0
        if (show_verbose)
868
0
          success = listExtensionContents(pattern);
869
0
        else
870
0
          success = listExtensions(pattern);
871
0
        break;
872
0
      case 'y':     /* Event Triggers */
873
0
        success = listEventTriggers(pattern, show_verbose);
874
0
        break;
875
0
      default:
876
0
        status = PSQL_CMD_UNKNOWN;
877
40
    }
878
879
40
    if (pattern)
880
28
      free(pattern);
881
40
  }
882
0
  else
883
0
    ignore_slash_options(scan_state);
884
885
40
  if (!success)
886
0
    status = PSQL_CMD_ERROR;
887
888
40
  return status;
889
40
}
890
891
/*
892
 * \e or \edit -- edit the current query buffer, or edit a file and
893
 * make it the query buffer
894
 */
895
static backslashResult
896
exec_command_edit(PsqlScanState scan_state, bool active_branch,
897
          PQExpBuffer query_buf, PQExpBuffer previous_buf)
898
0
{
899
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
900
901
0
  if (active_branch)
902
0
  {
903
0
    if (!query_buf)
904
0
    {
905
0
      psql_error("no query buffer\n");
906
0
      status = PSQL_CMD_ERROR;
907
0
    }
908
0
    else
909
0
    {
910
0
      char     *fname;
911
0
      char     *ln = NULL;
912
0
      int     lineno = -1;
913
914
0
      fname = psql_scan_slash_option(scan_state,
915
0
                       OT_NORMAL, NULL, true);
916
0
      if (fname)
917
0
      {
918
        /* try to get separate lineno arg */
919
0
        ln = psql_scan_slash_option(scan_state,
920
0
                      OT_NORMAL, NULL, true);
921
0
        if (ln == NULL)
922
0
        {
923
          /* only one arg; maybe it is lineno not fname */
924
0
          if (fname[0] &&
925
0
            strspn(fname, "0123456789") == strlen(fname))
926
0
          {
927
            /* all digits, so assume it is lineno */
928
0
            ln = fname;
929
0
            fname = NULL;
930
0
          }
931
0
        }
932
0
      }
933
0
      if (ln)
934
0
      {
935
0
        lineno = atoi(ln);
936
0
        if (lineno < 1)
937
0
        {
938
0
          psql_error("invalid line number: %s\n", ln);
939
0
          status = PSQL_CMD_ERROR;
940
0
        }
941
0
      }
942
0
      if (status != PSQL_CMD_ERROR)
943
0
      {
944
0
        expand_tilde(&fname);
945
0
        if (fname)
946
0
          canonicalize_path(fname);
947
948
        /* If query_buf is empty, recall previous query for editing */
949
0
        copy_previous_query(query_buf, previous_buf);
950
951
0
        if (do_edit(fname, query_buf, lineno, NULL))
952
0
          status = PSQL_CMD_NEWEDIT;
953
0
        else
954
0
          status = PSQL_CMD_ERROR;
955
0
      }
956
0
      if (fname)
957
0
        free(fname);
958
0
      if (ln)
959
0
        free(ln);
960
0
    }
961
0
  }
962
0
  else
963
0
    ignore_slash_options(scan_state);
964
965
0
  return status;
966
0
}
967
968
/*
969
 * \ef/\ev -- edit the named function/view, or
970
 * present a blank CREATE FUNCTION/VIEW template if no argument is given
971
 */
972
static backslashResult
973
exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
974
           PQExpBuffer query_buf, bool is_func)
975
0
{
976
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
977
978
0
  if (active_branch)
979
0
  {
980
0
    char     *obj_desc = psql_scan_slash_option(scan_state,
981
0
                            OT_WHOLE_LINE,
982
0
                            NULL, true);
983
0
    int     lineno = -1;
984
985
0
    if (pset.sversion < (is_func ? 80400 : 70400))
986
0
    {
987
0
      char    sverbuf[32];
988
989
0
      formatPGVersionNumber(pset.sversion, false,
990
0
                  sverbuf, sizeof(sverbuf));
991
0
      if (is_func)
992
0
        psql_error("The server (version %s) does not support editing function source.\n",
993
0
               sverbuf);
994
0
      else
995
0
        psql_error("The server (version %s) does not support editing view definitions.\n",
996
0
               sverbuf);
997
0
      status = PSQL_CMD_ERROR;
998
0
    }
999
0
    else if (!query_buf)
1000
0
    {
1001
0
      psql_error("no query buffer\n");
1002
0
      status = PSQL_CMD_ERROR;
1003
0
    }
1004
0
    else
1005
0
    {
1006
0
      Oid     obj_oid = InvalidOid;
1007
0
      EditableObjectType eot = is_func ? EditableFunction : EditableView;
1008
1009
0
      lineno = strip_lineno_from_objdesc(obj_desc);
1010
0
      if (lineno == 0)
1011
0
      {
1012
        /* error already reported */
1013
0
        status = PSQL_CMD_ERROR;
1014
0
      }
1015
0
      else if (!obj_desc)
1016
0
      {
1017
        /* set up an empty command to fill in */
1018
0
        resetPQExpBuffer(query_buf);
1019
0
        if (is_func)
1020
0
          appendPQExpBufferStr(query_buf,
1021
0
                     "CREATE FUNCTION ( )\n"
1022
0
                     " RETURNS \n"
1023
0
                     " LANGUAGE \n"
1024
0
                     " -- common options:  IMMUTABLE  STABLE  STRICT  SECURITY DEFINER\n"
1025
0
                     "AS $function$\n"
1026
0
                     "\n$function$\n");
1027
0
        else
1028
0
          appendPQExpBufferStr(query_buf,
1029
0
                     "CREATE VIEW  AS\n"
1030
0
                     " SELECT \n"
1031
0
                     "  -- something...\n");
1032
0
      }
1033
0
      else if (!lookup_object_oid(eot, obj_desc, &obj_oid))
1034
0
      {
1035
        /* error already reported */
1036
0
        status = PSQL_CMD_ERROR;
1037
0
      }
1038
0
      else if (!get_create_object_cmd(eot, obj_oid, query_buf))
1039
0
      {
1040
        /* error already reported */
1041
0
        status = PSQL_CMD_ERROR;
1042
0
      }
1043
0
      else if (is_func && lineno > 0)
1044
0
      {
1045
        /*
1046
         * lineno "1" should correspond to the first line of the
1047
         * function body.  We expect that pg_get_functiondef() will
1048
         * emit that on a line beginning with "AS ", and that there
1049
         * can be no such line before the real start of the function
1050
         * body.  Increment lineno by the number of lines before that
1051
         * line, so that it becomes relative to the first line of the
1052
         * function definition.
1053
         */
1054
0
        const char *lines = query_buf->data;
1055
1056
0
        while (*lines != '\0')
1057
0
        {
1058
0
          if (strncmp(lines, "AS ", 3) == 0)
1059
0
            break;
1060
0
          lineno++;
1061
          /* find start of next line */
1062
0
          lines = strchr(lines, '\n');
1063
0
          if (!lines)
1064
0
            break;
1065
0
          lines++;
1066
0
        }
1067
0
      }
1068
0
    }
1069
1070
0
    if (status != PSQL_CMD_ERROR)
1071
0
    {
1072
0
      bool    edited = false;
1073
1074
0
      if (!do_edit(NULL, query_buf, lineno, &edited))
1075
0
        status = PSQL_CMD_ERROR;
1076
0
      else if (!edited)
1077
0
        puts(_("No changes"));
1078
0
      else
1079
0
        status = PSQL_CMD_NEWEDIT;
1080
0
    }
1081
1082
0
    if (obj_desc)
1083
0
      free(obj_desc);
1084
0
  }
1085
0
  else
1086
0
    ignore_slash_whole_line(scan_state);
1087
1088
0
  return status;
1089
0
}
1090
1091
/*
1092
 * \echo and \qecho -- echo arguments to stdout or query output
1093
 */
1094
static backslashResult
1095
exec_command_echo(PsqlScanState scan_state, bool active_branch, const char *cmd)
1096
0
{
1097
0
  if (active_branch)
1098
0
  {
1099
0
    char     *value;
1100
0
    char    quoted;
1101
0
    bool    no_newline = false;
1102
0
    bool    first = true;
1103
0
    FILE     *fout;
1104
1105
0
    if (strcmp(cmd, "qecho") == 0)
1106
0
      fout = pset.queryFout;
1107
0
    else
1108
0
      fout = stdout;
1109
1110
0
    while ((value = psql_scan_slash_option(scan_state,
1111
0
                         OT_NORMAL, &quoted, false)))
1112
0
    {
1113
0
      if (!quoted && strcmp(value, "-n") == 0)
1114
0
        no_newline = true;
1115
0
      else
1116
0
      {
1117
0
        if (first)
1118
0
          first = false;
1119
0
        else
1120
0
          fputc(' ', fout);
1121
0
        fputs(value, fout);
1122
0
      }
1123
0
      free(value);
1124
0
    }
1125
0
    if (!no_newline)
1126
0
      fputs("\n", fout);
1127
0
  }
1128
0
  else
1129
0
    ignore_slash_options(scan_state);
1130
1131
0
  return PSQL_CMD_SKIP_LINE;
1132
0
}
1133
1134
/*
1135
 * \encoding -- set/show client side encoding
1136
 */
1137
static backslashResult
1138
exec_command_encoding(PsqlScanState scan_state, bool active_branch)
1139
0
{
1140
0
  if (active_branch)
1141
0
  {
1142
0
    char     *encoding = psql_scan_slash_option(scan_state,
1143
0
                            OT_NORMAL, NULL, false);
1144
1145
0
    if (!encoding)
1146
0
    {
1147
      /* show encoding */
1148
0
      puts(pg_encoding_to_char(pset.encoding));
1149
0
    }
1150
0
    else
1151
0
    {
1152
      /* set encoding */
1153
0
      if (PQsetClientEncoding(pset.db, encoding) == -1)
1154
0
        psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
1155
0
      else
1156
0
      {
1157
        /* save encoding info into psql internal data */
1158
0
        pset.encoding = PQclientEncoding(pset.db);
1159
0
        pset.popt.topt.encoding = pset.encoding;
1160
0
        SetVariable(pset.vars, "ENCODING",
1161
0
              pg_encoding_to_char(pset.encoding));
1162
0
      }
1163
0
      free(encoding);
1164
0
    }
1165
0
  }
1166
0
  else
1167
0
    ignore_slash_options(scan_state);
1168
1169
0
  return PSQL_CMD_SKIP_LINE;
1170
0
}
1171
1172
/*
1173
 * \errverbose -- display verbose message from last failed query
1174
 */
1175
static backslashResult
1176
exec_command_errverbose(PsqlScanState scan_state, bool active_branch)
1177
0
{
1178
0
  if (active_branch)
1179
0
  {
1180
0
    if (pset.last_error_result)
1181
0
    {
1182
0
      char     *msg;
1183
1184
0
      msg = PQresultVerboseErrorMessage(pset.last_error_result,
1185
0
                        PQERRORS_VERBOSE,
1186
0
                        PQSHOW_CONTEXT_ALWAYS);
1187
0
      if (msg)
1188
0
      {
1189
0
        psql_error("%s", msg);
1190
0
        PQfreemem(msg);
1191
0
      }
1192
0
      else
1193
0
        puts(_("out of memory"));
1194
0
    }
1195
0
    else
1196
0
      puts(_("There is no previous error."));
1197
0
  }
1198
1199
0
  return PSQL_CMD_SKIP_LINE;
1200
0
}
1201
1202
/*
1203
 * \f -- change field separator
1204
 */
1205
static backslashResult
1206
exec_command_f(PsqlScanState scan_state, bool active_branch)
1207
0
{
1208
0
  bool    success = true;
1209
1210
0
  if (active_branch)
1211
0
  {
1212
0
    char     *fname = psql_scan_slash_option(scan_state,
1213
0
                           OT_NORMAL, NULL, false);
1214
1215
0
    success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
1216
0
    free(fname);
1217
0
  }
1218
0
  else
1219
0
    ignore_slash_options(scan_state);
1220
1221
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1222
0
}
1223
1224
/*
1225
 * \g [filename] -- send query, optionally with output to file/pipe
1226
 * \gx [filename] -- same as \g, with expanded mode forced
1227
 */
1228
static backslashResult
1229
exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd)
1230
0
{
1231
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
1232
1233
0
  if (active_branch)
1234
0
  {
1235
0
    char     *fname = psql_scan_slash_option(scan_state,
1236
0
                           OT_FILEPIPE, NULL, false);
1237
1238
0
    if (!fname)
1239
0
      pset.gfname = NULL;
1240
0
    else
1241
0
    {
1242
0
      expand_tilde(&fname);
1243
0
      pset.gfname = pg_strdup(fname);
1244
0
    }
1245
0
    free(fname);
1246
0
    if (strcmp(cmd, "gx") == 0)
1247
0
      pset.g_expanded = true;
1248
0
    status = PSQL_CMD_SEND;
1249
0
  }
1250
0
  else
1251
0
    ignore_slash_filepipe(scan_state);
1252
1253
0
  return status;
1254
0
}
1255
1256
/*
1257
 * \gdesc -- describe query result
1258
 */
1259
static backslashResult
1260
exec_command_gdesc(PsqlScanState scan_state, bool active_branch)
1261
0
{
1262
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
1263
1264
0
  if (active_branch)
1265
0
  {
1266
0
    pset.gdesc_flag = true;
1267
0
    status = PSQL_CMD_SEND;
1268
0
  }
1269
1270
0
  return status;
1271
0
}
1272
1273
/*
1274
 * \gexec -- send query and execute each field of result
1275
 */
1276
static backslashResult
1277
exec_command_gexec(PsqlScanState scan_state, bool active_branch)
1278
0
{
1279
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
1280
1281
0
  if (active_branch)
1282
0
  {
1283
0
    pset.gexec_flag = true;
1284
0
    status = PSQL_CMD_SEND;
1285
0
  }
1286
1287
0
  return status;
1288
0
}
1289
1290
/*
1291
 * \gset [prefix] -- send query and store result into variables
1292
 */
1293
static backslashResult
1294
exec_command_gset(PsqlScanState scan_state, bool active_branch)
1295
0
{
1296
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
1297
1298
0
  if (active_branch)
1299
0
  {
1300
0
    char     *prefix = psql_scan_slash_option(scan_state,
1301
0
                          OT_NORMAL, NULL, false);
1302
1303
0
    if (prefix)
1304
0
      pset.gset_prefix = prefix;
1305
0
    else
1306
0
    {
1307
      /* we must set a non-NULL prefix to trigger storing */
1308
0
      pset.gset_prefix = pg_strdup("");
1309
0
    }
1310
    /* gset_prefix is freed later */
1311
0
    status = PSQL_CMD_SEND;
1312
0
  }
1313
0
  else
1314
0
    ignore_slash_options(scan_state);
1315
1316
0
  return status;
1317
0
}
1318
1319
/*
1320
 * \help [topic] -- print help about SQL commands
1321
 */
1322
static backslashResult
1323
exec_command_help(PsqlScanState scan_state, bool active_branch)
1324
0
{
1325
0
  if (active_branch)
1326
0
  {
1327
0
    char     *opt = psql_scan_slash_option(scan_state,
1328
0
                         OT_WHOLE_LINE, NULL, false);
1329
0
    size_t    len;
1330
1331
    /* strip any trailing spaces and semicolons */
1332
0
    if (opt)
1333
0
    {
1334
0
      len = strlen(opt);
1335
0
      while (len > 0 &&
1336
0
           (isspace((unsigned char) opt[len - 1])
1337
0
          || opt[len - 1] == ';'))
1338
0
        opt[--len] = '\0';
1339
0
    }
1340
1341
0
    helpSQL(opt, pset.popt.topt.pager);
1342
0
    free(opt);
1343
0
  }
1344
0
  else
1345
0
    ignore_slash_whole_line(scan_state);
1346
1347
0
  return PSQL_CMD_SKIP_LINE;
1348
0
}
1349
1350
/*
1351
 * \H and \html -- toggle HTML formatting
1352
 */
1353
static backslashResult
1354
exec_command_html(PsqlScanState scan_state, bool active_branch)
1355
0
{
1356
0
  bool    success = true;
1357
1358
0
  if (active_branch)
1359
0
  {
1360
0
    if (pset.popt.topt.format != PRINT_HTML)
1361
0
      success = do_pset("format", "html", &pset.popt, pset.quiet);
1362
0
    else
1363
0
      success = do_pset("format", "aligned", &pset.popt, pset.quiet);
1364
0
  }
1365
1366
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1367
0
}
1368
1369
/*
1370
 * \i and \ir -- include a file
1371
 */
1372
static backslashResult
1373
exec_command_include(PsqlScanState scan_state, bool active_branch, const char *cmd)
1374
0
{
1375
0
  bool    success = true;
1376
1377
0
  if (active_branch)
1378
0
  {
1379
0
    char     *fname = psql_scan_slash_option(scan_state,
1380
0
                           OT_NORMAL, NULL, true);
1381
1382
0
    if (!fname)
1383
0
    {
1384
0
      psql_error("\\%s: missing required argument\n", cmd);
1385
0
      success = false;
1386
0
    }
1387
0
    else
1388
0
    {
1389
0
      bool    include_relative;
1390
1391
0
      include_relative = (strcmp(cmd, "ir") == 0
1392
0
                || strcmp(cmd, "include_relative") == 0);
1393
0
      expand_tilde(&fname);
1394
0
      success = (process_file(fname, include_relative) == EXIT_SUCCESS);
1395
0
      free(fname);
1396
0
    }
1397
0
  }
1398
0
  else
1399
0
    ignore_slash_options(scan_state);
1400
1401
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1402
0
}
1403
1404
/*
1405
 * \if <expr> -- beginning of an \if..\endif block
1406
 *
1407
 * <expr> is parsed as a boolean expression.  Invalid expressions will emit a
1408
 * warning and be treated as false.  Statements that follow a false expression
1409
 * will be parsed but ignored.  Note that in the case where an \if statement
1410
 * is itself within an inactive section of a block, then the entire inner
1411
 * \if..\endif block will be parsed but ignored.
1412
 */
1413
static backslashResult
1414
exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
1415
        PQExpBuffer query_buf)
1416
0
{
1417
0
  if (conditional_active(cstack))
1418
0
  {
1419
    /*
1420
     * First, push a new active stack entry; this ensures that the lexer
1421
     * will perform variable substitution and backtick evaluation while
1422
     * scanning the expression.  (That should happen anyway, since we know
1423
     * we're in an active outer branch, but let's be sure.)
1424
     */
1425
0
    conditional_stack_push(cstack, IFSTATE_TRUE);
1426
1427
    /* Remember current query state in case we need to restore later */
1428
0
    save_query_text_state(scan_state, cstack, query_buf);
1429
1430
    /*
1431
     * Evaluate the expression; if it's false, change to inactive state.
1432
     */
1433
0
    if (!is_true_boolean_expression(scan_state, "\\if expression"))
1434
0
      conditional_stack_poke(cstack, IFSTATE_FALSE);
1435
0
  }
1436
0
  else
1437
0
  {
1438
    /*
1439
     * We're within an inactive outer branch, so this entire \if block
1440
     * will be ignored.  We don't want to evaluate the expression, so push
1441
     * the "ignored" stack state before scanning it.
1442
     */
1443
0
    conditional_stack_push(cstack, IFSTATE_IGNORED);
1444
1445
    /* Remember current query state in case we need to restore later */
1446
0
    save_query_text_state(scan_state, cstack, query_buf);
1447
1448
0
    ignore_boolean_expression(scan_state);
1449
0
  }
1450
1451
0
  return PSQL_CMD_SKIP_LINE;
1452
0
}
1453
1454
/*
1455
 * \elif <expr> -- alternative branch in an \if..\endif block
1456
 *
1457
 * <expr> is evaluated the same as in \if <expr>.
1458
 */
1459
static backslashResult
1460
exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
1461
          PQExpBuffer query_buf)
1462
0
{
1463
0
  bool    success = true;
1464
1465
0
  switch (conditional_stack_peek(cstack))
1466
0
  {
1467
0
    case IFSTATE_TRUE:
1468
1469
      /*
1470
       * Just finished active branch of this \if block.  Update saved
1471
       * state so we will keep whatever data was put in query_buf by the
1472
       * active branch.
1473
       */
1474
0
      save_query_text_state(scan_state, cstack, query_buf);
1475
1476
      /*
1477
       * Discard \elif expression and ignore the rest until \endif.
1478
       * Switch state before reading expression to ensure proper lexer
1479
       * behavior.
1480
       */
1481
0
      conditional_stack_poke(cstack, IFSTATE_IGNORED);
1482
0
      ignore_boolean_expression(scan_state);
1483
0
      break;
1484
0
    case IFSTATE_FALSE:
1485
1486
      /*
1487
       * Discard any query text added by the just-skipped branch.
1488
       */
1489
0
      discard_query_text(scan_state, cstack, query_buf);
1490
1491
      /*
1492
       * Have not yet found a true expression in this \if block, so this
1493
       * might be the first.  We have to change state before examining
1494
       * the expression, or the lexer won't do the right thing.
1495
       */
1496
0
      conditional_stack_poke(cstack, IFSTATE_TRUE);
1497
0
      if (!is_true_boolean_expression(scan_state, "\\elif expression"))
1498
0
        conditional_stack_poke(cstack, IFSTATE_FALSE);
1499
0
      break;
1500
0
    case IFSTATE_IGNORED:
1501
1502
      /*
1503
       * Discard any query text added by the just-skipped branch.
1504
       */
1505
0
      discard_query_text(scan_state, cstack, query_buf);
1506
1507
      /*
1508
       * Skip expression and move on.  Either the \if block already had
1509
       * an active section, or whole block is being skipped.
1510
       */
1511
0
      ignore_boolean_expression(scan_state);
1512
0
      break;
1513
0
    case IFSTATE_ELSE_TRUE:
1514
0
    case IFSTATE_ELSE_FALSE:
1515
0
      psql_error("\\elif: cannot occur after \\else\n");
1516
0
      success = false;
1517
0
      break;
1518
0
    case IFSTATE_NONE:
1519
      /* no \if to elif from */
1520
0
      psql_error("\\elif: no matching \\if\n");
1521
0
      success = false;
1522
0
      break;
1523
0
  }
1524
1525
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1526
0
}
1527
1528
/*
1529
 * \else -- final alternative in an \if..\endif block
1530
 *
1531
 * Statements within an \else branch will only be executed if
1532
 * all previous \if and \elif expressions evaluated to false
1533
 * and the block was not itself being ignored.
1534
 */
1535
static backslashResult
1536
exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
1537
          PQExpBuffer query_buf)
1538
0
{
1539
0
  bool    success = true;
1540
1541
0
  switch (conditional_stack_peek(cstack))
1542
0
  {
1543
0
    case IFSTATE_TRUE:
1544
1545
      /*
1546
       * Just finished active branch of this \if block.  Update saved
1547
       * state so we will keep whatever data was put in query_buf by the
1548
       * active branch.
1549
       */
1550
0
      save_query_text_state(scan_state, cstack, query_buf);
1551
1552
      /* Now skip the \else branch */
1553
0
      conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
1554
0
      break;
1555
0
    case IFSTATE_FALSE:
1556
1557
      /*
1558
       * Discard any query text added by the just-skipped branch.
1559
       */
1560
0
      discard_query_text(scan_state, cstack, query_buf);
1561
1562
      /*
1563
       * We've not found any true \if or \elif expression, so execute
1564
       * the \else branch.
1565
       */
1566
0
      conditional_stack_poke(cstack, IFSTATE_ELSE_TRUE);
1567
0
      break;
1568
0
    case IFSTATE_IGNORED:
1569
1570
      /*
1571
       * Discard any query text added by the just-skipped branch.
1572
       */
1573
0
      discard_query_text(scan_state, cstack, query_buf);
1574
1575
      /*
1576
       * Either we previously processed the active branch of this \if,
1577
       * or the whole \if block is being skipped.  Either way, skip the
1578
       * \else branch.
1579
       */
1580
0
      conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
1581
0
      break;
1582
0
    case IFSTATE_ELSE_TRUE:
1583
0
    case IFSTATE_ELSE_FALSE:
1584
0
      psql_error("\\else: cannot occur after \\else\n");
1585
0
      success = false;
1586
0
      break;
1587
0
    case IFSTATE_NONE:
1588
      /* no \if to else from */
1589
0
      psql_error("\\else: no matching \\if\n");
1590
0
      success = false;
1591
0
      break;
1592
0
  }
1593
1594
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1595
0
}
1596
1597
/*
1598
 * \endif -- ends an \if...\endif block
1599
 */
1600
static backslashResult
1601
exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
1602
           PQExpBuffer query_buf)
1603
0
{
1604
0
  bool    success = true;
1605
1606
0
  switch (conditional_stack_peek(cstack))
1607
0
  {
1608
0
    case IFSTATE_TRUE:
1609
0
    case IFSTATE_ELSE_TRUE:
1610
      /* Close the \if block, keeping the query text */
1611
0
      success = conditional_stack_pop(cstack);
1612
0
      Assert(success);
1613
0
      break;
1614
0
    case IFSTATE_FALSE:
1615
0
    case IFSTATE_IGNORED:
1616
0
    case IFSTATE_ELSE_FALSE:
1617
1618
      /*
1619
       * Discard any query text added by the just-skipped branch.
1620
       */
1621
0
      discard_query_text(scan_state, cstack, query_buf);
1622
1623
      /* Close the \if block */
1624
0
      success = conditional_stack_pop(cstack);
1625
0
      Assert(success);
1626
0
      break;
1627
0
    case IFSTATE_NONE:
1628
      /* no \if to end */
1629
0
      psql_error("\\endif: no matching \\if\n");
1630
0
      success = false;
1631
0
      break;
1632
0
  }
1633
1634
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1635
0
}
1636
1637
/*
1638
 * \l -- list databases
1639
 */
1640
static backslashResult
1641
exec_command_list(PsqlScanState scan_state, bool active_branch, const char *cmd)
1642
0
{
1643
0
  bool    success = true;
1644
1645
0
  if (active_branch)
1646
0
  {
1647
0
    char     *pattern;
1648
0
    bool    show_verbose;
1649
1650
0
    pattern = psql_scan_slash_option(scan_state,
1651
0
                     OT_NORMAL, NULL, true);
1652
1653
0
    show_verbose = strchr(cmd, '+') ? true : false;
1654
1655
0
    success = listAllDbs(pattern, show_verbose);
1656
1657
0
    if (pattern)
1658
0
      free(pattern);
1659
0
  }
1660
0
  else
1661
0
    ignore_slash_options(scan_state);
1662
1663
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1664
0
}
1665
1666
/*
1667
 * \lo_* -- large object operations
1668
 */
1669
static backslashResult
1670
exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
1671
0
{
1672
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
1673
0
  bool    success = true;
1674
1675
0
  if (active_branch)
1676
0
  {
1677
0
    char     *opt1,
1678
0
           *opt2;
1679
1680
0
    opt1 = psql_scan_slash_option(scan_state,
1681
0
                    OT_NORMAL, NULL, true);
1682
0
    opt2 = psql_scan_slash_option(scan_state,
1683
0
                    OT_NORMAL, NULL, true);
1684
1685
0
    if (strcmp(cmd + 3, "export") == 0)
1686
0
    {
1687
0
      if (!opt2)
1688
0
      {
1689
0
        psql_error("\\%s: missing required argument\n", cmd);
1690
0
        success = false;
1691
0
      }
1692
0
      else
1693
0
      {
1694
0
        expand_tilde(&opt2);
1695
0
        success = do_lo_export(opt1, opt2);
1696
0
      }
1697
0
    }
1698
1699
0
    else if (strcmp(cmd + 3, "import") == 0)
1700
0
    {
1701
0
      if (!opt1)
1702
0
      {
1703
0
        psql_error("\\%s: missing required argument\n", cmd);
1704
0
        success = false;
1705
0
      }
1706
0
      else
1707
0
      {
1708
0
        expand_tilde(&opt1);
1709
0
        success = do_lo_import(opt1, opt2);
1710
0
      }
1711
0
    }
1712
1713
0
    else if (strcmp(cmd + 3, "list") == 0)
1714
0
      success = do_lo_list();
1715
1716
0
    else if (strcmp(cmd + 3, "unlink") == 0)
1717
0
    {
1718
0
      if (!opt1)
1719
0
      {
1720
0
        psql_error("\\%s: missing required argument\n", cmd);
1721
0
        success = false;
1722
0
      }
1723
0
      else
1724
0
        success = do_lo_unlink(opt1);
1725
0
    }
1726
1727
0
    else
1728
0
      status = PSQL_CMD_UNKNOWN;
1729
1730
0
    free(opt1);
1731
0
    free(opt2);
1732
0
  }
1733
0
  else
1734
0
    ignore_slash_options(scan_state);
1735
1736
0
  if (!success)
1737
0
    status = PSQL_CMD_ERROR;
1738
1739
0
  return status;
1740
0
}
1741
1742
/*
1743
 * \o -- set query output
1744
 */
1745
static backslashResult
1746
exec_command_out(PsqlScanState scan_state, bool active_branch)
1747
0
{
1748
0
  bool    success = true;
1749
1750
0
  if (active_branch)
1751
0
  {
1752
0
    char     *fname = psql_scan_slash_option(scan_state,
1753
0
                           OT_FILEPIPE, NULL, true);
1754
1755
0
    expand_tilde(&fname);
1756
0
    success = setQFout(fname);
1757
0
    free(fname);
1758
0
  }
1759
0
  else
1760
0
    ignore_slash_filepipe(scan_state);
1761
1762
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1763
0
}
1764
1765
/*
1766
 * \p -- print the current query buffer
1767
 */
1768
static backslashResult
1769
exec_command_print(PsqlScanState scan_state, bool active_branch,
1770
           PQExpBuffer query_buf, PQExpBuffer previous_buf)
1771
0
{
1772
0
  if (active_branch)
1773
0
  {
1774
    /*
1775
     * We want to print the same thing \g would execute, but not to change
1776
     * the query buffer state; so we can't use copy_previous_query().
1777
     * Also, beware of possibility that buffer pointers are NULL.
1778
     */
1779
0
    if (query_buf && query_buf->len > 0)
1780
0
      puts(query_buf->data);
1781
0
    else if (previous_buf && previous_buf->len > 0)
1782
0
      puts(previous_buf->data);
1783
0
    else if (!pset.quiet)
1784
0
      puts(_("Query buffer is empty."));
1785
0
    fflush(stdout);
1786
0
  }
1787
1788
0
  return PSQL_CMD_SKIP_LINE;
1789
0
}
1790
1791
/*
1792
 * \password -- set user password
1793
 */
1794
static backslashResult
1795
exec_command_password(PsqlScanState scan_state, bool active_branch)
1796
0
{
1797
0
  bool    success = true;
1798
1799
0
  if (active_branch)
1800
0
  {
1801
0
    char     *opt0 = psql_scan_slash_option(scan_state,
1802
0
                          OT_SQLID, NULL, true);
1803
0
    char    pw1[100];
1804
0
    char    pw2[100];
1805
1806
0
    simple_prompt("Enter new password: ", pw1, sizeof(pw1), false);
1807
0
    simple_prompt("Enter it again: ", pw2, sizeof(pw2), false);
1808
1809
0
    if (strcmp(pw1, pw2) != 0)
1810
0
    {
1811
0
      psql_error("Passwords didn't match.\n");
1812
0
      success = false;
1813
0
    }
1814
0
    else
1815
0
    {
1816
0
      char     *user;
1817
0
      char     *encrypted_password;
1818
1819
0
      if (opt0)
1820
0
        user = opt0;
1821
0
      else
1822
0
        user = PQuser(pset.db);
1823
1824
0
      encrypted_password = PQencryptPasswordConn(pset.db, pw1, user, NULL);
1825
1826
0
      if (!encrypted_password)
1827
0
      {
1828
0
        psql_error("%s", PQerrorMessage(pset.db));
1829
0
        success = false;
1830
0
      }
1831
0
      else
1832
0
      {
1833
0
        PQExpBufferData buf;
1834
0
        PGresult   *res;
1835
1836
0
        initPQExpBuffer(&buf);
1837
0
        printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
1838
0
                  fmtId(user));
1839
0
        appendStringLiteralConn(&buf, encrypted_password, pset.db);
1840
0
        res = PSQLexec(buf.data);
1841
0
        termPQExpBuffer(&buf);
1842
0
        if (!res)
1843
0
          success = false;
1844
0
        else
1845
0
          PQclear(res);
1846
0
        PQfreemem(encrypted_password);
1847
0
      }
1848
0
    }
1849
1850
0
    if (opt0)
1851
0
      free(opt0);
1852
0
  }
1853
0
  else
1854
0
    ignore_slash_options(scan_state);
1855
1856
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1857
0
}
1858
1859
/*
1860
 * \prompt -- prompt and set variable
1861
 */
1862
static backslashResult
1863
exec_command_prompt(PsqlScanState scan_state, bool active_branch,
1864
          const char *cmd)
1865
0
{
1866
0
  bool    success = true;
1867
1868
0
  if (active_branch)
1869
0
  {
1870
0
    char     *opt,
1871
0
           *prompt_text = NULL;
1872
0
    char     *arg1,
1873
0
           *arg2;
1874
1875
0
    arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
1876
0
    arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
1877
1878
0
    if (!arg1)
1879
0
    {
1880
0
      psql_error("\\%s: missing required argument\n", cmd);
1881
0
      success = false;
1882
0
    }
1883
0
    else
1884
0
    {
1885
0
      char     *result;
1886
1887
0
      if (arg2)
1888
0
      {
1889
0
        prompt_text = arg1;
1890
0
        opt = arg2;
1891
0
      }
1892
0
      else
1893
0
        opt = arg1;
1894
1895
0
      if (!pset.inputfile)
1896
0
      {
1897
0
        result = (char *) pg_malloc(4096);
1898
0
        simple_prompt(prompt_text, result, 4096, true);
1899
0
      }
1900
0
      else
1901
0
      {
1902
0
        if (prompt_text)
1903
0
        {
1904
0
          fputs(prompt_text, stdout);
1905
0
          fflush(stdout);
1906
0
        }
1907
0
        result = gets_fromFile(stdin);
1908
0
        if (!result)
1909
0
        {
1910
0
          psql_error("\\%s: could not read value for variable\n",
1911
0
                 cmd);
1912
0
          success = false;
1913
0
        }
1914
0
      }
1915
1916
0
      if (result &&
1917
0
        !SetVariable(pset.vars, opt, result))
1918
0
        success = false;
1919
1920
0
      if (result)
1921
0
        free(result);
1922
0
      if (prompt_text)
1923
0
        free(prompt_text);
1924
0
      free(opt);
1925
0
    }
1926
0
  }
1927
0
  else
1928
0
    ignore_slash_options(scan_state);
1929
1930
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1931
0
}
1932
1933
/*
1934
 * \pset -- set printing parameters
1935
 */
1936
static backslashResult
1937
exec_command_pset(PsqlScanState scan_state, bool active_branch)
1938
1
{
1939
1
  bool    success = true;
1940
1941
1
  if (active_branch)
1942
1
  {
1943
1
    char     *opt0 = psql_scan_slash_option(scan_state,
1944
1
                          OT_NORMAL, NULL, false);
1945
1
    char     *opt1 = psql_scan_slash_option(scan_state,
1946
1
                          OT_NORMAL, NULL, false);
1947
1948
1
    if (!opt0)
1949
0
    {
1950
      /* list all variables */
1951
1952
0
      int     i;
1953
0
      static const char *const my_list[] = {
1954
0
        "border", "columns", "expanded", "fieldsep", "fieldsep_zero",
1955
0
        "footer", "format", "linestyle", "null",
1956
0
        "numericlocale", "pager", "pager_min_lines",
1957
0
        "recordsep", "recordsep_zero",
1958
0
        "tableattr", "title", "tuples_only",
1959
0
        "unicode_border_linestyle",
1960
0
        "unicode_column_linestyle",
1961
0
        "unicode_header_linestyle",
1962
0
        NULL
1963
0
      };
1964
1965
0
      for (i = 0; my_list[i] != NULL; i++)
1966
0
      {
1967
0
        char     *val = pset_value_string(my_list[i], &pset.popt);
1968
1969
0
        printf("%-24s %s\n", my_list[i], val);
1970
0
        free(val);
1971
0
      }
1972
1973
0
      success = true;
1974
0
    }
1975
1
    else
1976
1
      success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
1977
1978
1
    free(opt0);
1979
1
    free(opt1);
1980
1
  }
1981
0
  else
1982
0
    ignore_slash_options(scan_state);
1983
1984
1
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
1985
1
}
1986
1987
/*
1988
 * \q or \quit -- exit psql
1989
 */
1990
static backslashResult
1991
exec_command_quit(PsqlScanState scan_state, bool active_branch)
1992
0
{
1993
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
1994
1995
0
  if (active_branch)
1996
0
    status = PSQL_CMD_TERMINATE;
1997
1998
0
  return status;
1999
0
}
2000
2001
/*
2002
 * \r -- reset (clear) the query buffer
2003
 */
2004
static backslashResult
2005
exec_command_reset(PsqlScanState scan_state, bool active_branch,
2006
           PQExpBuffer query_buf)
2007
0
{
2008
0
  if (active_branch)
2009
0
  {
2010
0
    resetPQExpBuffer(query_buf);
2011
0
    psql_scan_reset(scan_state);
2012
0
    if (!pset.quiet)
2013
0
      puts(_("Query buffer reset (cleared)."));
2014
0
  }
2015
2016
0
  return PSQL_CMD_SKIP_LINE;
2017
0
}
2018
2019
/*
2020
 * \s -- save history in a file or show it on the screen
2021
 */
2022
static backslashResult
2023
exec_command_s(PsqlScanState scan_state, bool active_branch)
2024
0
{
2025
0
  bool    success = true;
2026
2027
0
  if (active_branch)
2028
0
  {
2029
0
    char     *fname = psql_scan_slash_option(scan_state,
2030
0
                           OT_NORMAL, NULL, true);
2031
2032
0
    expand_tilde(&fname);
2033
0
    success = printHistory(fname, pset.popt.topt.pager);
2034
0
    if (success && !pset.quiet && fname)
2035
0
      printf(_("Wrote history to file \"%s\".\n"), fname);
2036
0
    if (!fname)
2037
0
      putchar('\n');
2038
0
    free(fname);
2039
0
  }
2040
0
  else
2041
0
    ignore_slash_options(scan_state);
2042
2043
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2044
0
}
2045
2046
/*
2047
 * \set -- set variable
2048
 */
2049
static backslashResult
2050
exec_command_set(PsqlScanState scan_state, bool active_branch)
2051
4
{
2052
4
  bool    success = true;
2053
2054
4
  if (active_branch)
2055
4
  {
2056
4
    char     *opt0 = psql_scan_slash_option(scan_state,
2057
4
                          OT_NORMAL, NULL, false);
2058
2059
4
    if (!opt0)
2060
0
    {
2061
      /* list all variables */
2062
0
      PrintVariables(pset.vars);
2063
0
      success = true;
2064
0
    }
2065
4
    else
2066
4
    {
2067
      /*
2068
       * Set variable to the concatenation of the arguments.
2069
       */
2070
4
      char     *newval;
2071
4
      char     *opt;
2072
2073
4
      opt = psql_scan_slash_option(scan_state,
2074
4
                     OT_NORMAL, NULL, false);
2075
4
      newval = pg_strdup(opt ? opt : "");
2076
4
      free(opt);
2077
2078
4
      while ((opt = psql_scan_slash_option(scan_state,
2079
4
                         OT_NORMAL, NULL, false)))
2080
0
      {
2081
0
        newval = pg_realloc(newval, strlen(newval) + strlen(opt) + 1);
2082
0
        strcat(newval, opt);
2083
0
        free(opt);
2084
0
      }
2085
2086
4
      if (!SetVariable(pset.vars, opt0, newval))
2087
0
        success = false;
2088
2089
4
      free(newval);
2090
4
    }
2091
4
    free(opt0);
2092
4
  }
2093
0
  else
2094
0
    ignore_slash_options(scan_state);
2095
2096
4
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2097
4
}
2098
2099
/*
2100
 * \setenv -- set environment variable
2101
 */
2102
static backslashResult
2103
exec_command_setenv(PsqlScanState scan_state, bool active_branch,
2104
          const char *cmd)
2105
0
{
2106
0
  bool    success = true;
2107
2108
0
  if (active_branch)
2109
0
  {
2110
0
    char     *envvar = psql_scan_slash_option(scan_state,
2111
0
                          OT_NORMAL, NULL, false);
2112
0
    char     *envval = psql_scan_slash_option(scan_state,
2113
0
                          OT_NORMAL, NULL, false);
2114
2115
0
    if (!envvar)
2116
0
    {
2117
0
      psql_error("\\%s: missing required argument\n", cmd);
2118
0
      success = false;
2119
0
    }
2120
0
    else if (strchr(envvar, '=') != NULL)
2121
0
    {
2122
0
      psql_error("\\%s: environment variable name must not contain \"=\"\n",
2123
0
             cmd);
2124
0
      success = false;
2125
0
    }
2126
0
    else if (!envval)
2127
0
    {
2128
      /* No argument - unset the environment variable */
2129
0
      unsetenv(envvar);
2130
0
      success = true;
2131
0
    }
2132
0
    else
2133
0
    {
2134
      /* Set variable to the value of the next argument */
2135
0
      char     *newval;
2136
2137
0
      newval = psprintf("%s=%s", envvar, envval);
2138
0
      putenv(newval);
2139
0
      success = true;
2140
2141
      /*
2142
       * Do not free newval here, it will screw up the environment if
2143
       * you do. See putenv man page for details. That means we leak a
2144
       * bit of memory here, but not enough to worry about.
2145
       */
2146
0
    }
2147
0
    free(envvar);
2148
0
    free(envval);
2149
0
  }
2150
0
  else
2151
0
    ignore_slash_options(scan_state);
2152
2153
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2154
0
}
2155
2156
/*
2157
 * \sf/\sv -- show a function/view's source code
2158
 */
2159
static backslashResult
2160
exec_command_sf_sv(PsqlScanState scan_state, bool active_branch,
2161
           const char *cmd, bool is_func)
2162
0
{
2163
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
2164
2165
0
  if (active_branch)
2166
0
  {
2167
0
    bool    show_linenumbers = (strchr(cmd, '+') != NULL);
2168
0
    PQExpBuffer buf;
2169
0
    char     *obj_desc;
2170
0
    Oid     obj_oid = InvalidOid;
2171
0
    EditableObjectType eot = is_func ? EditableFunction : EditableView;
2172
2173
0
    buf = createPQExpBuffer();
2174
0
    obj_desc = psql_scan_slash_option(scan_state,
2175
0
                      OT_WHOLE_LINE, NULL, true);
2176
0
    if (pset.sversion < (is_func ? 80400 : 70400))
2177
0
    {
2178
0
      char    sverbuf[32];
2179
2180
0
      formatPGVersionNumber(pset.sversion, false,
2181
0
                  sverbuf, sizeof(sverbuf));
2182
0
      if (is_func)
2183
0
        psql_error("The server (version %s) does not support showing function source.\n",
2184
0
               sverbuf);
2185
0
      else
2186
0
        psql_error("The server (version %s) does not support showing view definitions.\n",
2187
0
               sverbuf);
2188
0
      status = PSQL_CMD_ERROR;
2189
0
    }
2190
0
    else if (!obj_desc)
2191
0
    {
2192
0
      if (is_func)
2193
0
        psql_error("function name is required\n");
2194
0
      else
2195
0
        psql_error("view name is required\n");
2196
0
      status = PSQL_CMD_ERROR;
2197
0
    }
2198
0
    else if (!lookup_object_oid(eot, obj_desc, &obj_oid))
2199
0
    {
2200
      /* error already reported */
2201
0
      status = PSQL_CMD_ERROR;
2202
0
    }
2203
0
    else if (!get_create_object_cmd(eot, obj_oid, buf))
2204
0
    {
2205
      /* error already reported */
2206
0
      status = PSQL_CMD_ERROR;
2207
0
    }
2208
0
    else
2209
0
    {
2210
0
      FILE     *output;
2211
0
      bool    is_pager;
2212
2213
      /* Select output stream: stdout, pager, or file */
2214
0
      if (pset.queryFout == stdout)
2215
0
      {
2216
        /* count lines in function to see if pager is needed */
2217
0
        int     lineno = count_lines_in_buf(buf);
2218
2219
0
        output = PageOutput(lineno, &(pset.popt.topt));
2220
0
        is_pager = true;
2221
0
      }
2222
0
      else
2223
0
      {
2224
        /* use previously set output file, without pager */
2225
0
        output = pset.queryFout;
2226
0
        is_pager = false;
2227
0
      }
2228
2229
0
      if (show_linenumbers)
2230
0
      {
2231
        /*
2232
         * For functions, lineno "1" should correspond to the first
2233
         * line of the function body.  We expect that
2234
         * pg_get_functiondef() will emit that on a line beginning
2235
         * with "AS ", and that there can be no such line before the
2236
         * real start of the function body.
2237
         */
2238
0
        print_with_linenumbers(output, buf->data,
2239
0
                     is_func ? "AS " : NULL);
2240
0
      }
2241
0
      else
2242
0
      {
2243
        /* just send the definition to output */
2244
0
        fputs(buf->data, output);
2245
0
      }
2246
2247
0
      if (is_pager)
2248
0
        ClosePager(output);
2249
0
    }
2250
2251
0
    if (obj_desc)
2252
0
      free(obj_desc);
2253
0
    destroyPQExpBuffer(buf);
2254
0
  }
2255
0
  else
2256
0
    ignore_slash_whole_line(scan_state);
2257
2258
0
  return status;
2259
0
}
2260
2261
/*
2262
 * \t -- turn off table headers and row count
2263
 */
2264
static backslashResult
2265
exec_command_t(PsqlScanState scan_state, bool active_branch)
2266
8
{
2267
8
  bool    success = true;
2268
2269
8
  if (active_branch)
2270
8
  {
2271
8
    char     *opt = psql_scan_slash_option(scan_state,
2272
8
                         OT_NORMAL, NULL, true);
2273
2274
8
    success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
2275
8
    free(opt);
2276
8
  }
2277
0
  else
2278
0
    ignore_slash_options(scan_state);
2279
2280
8
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2281
8
}
2282
2283
/*
2284
 * \T -- define html <table ...> attributes
2285
 */
2286
static backslashResult
2287
exec_command_T(PsqlScanState scan_state, bool active_branch)
2288
0
{
2289
0
  bool    success = true;
2290
2291
0
  if (active_branch)
2292
0
  {
2293
0
    char     *value = psql_scan_slash_option(scan_state,
2294
0
                           OT_NORMAL, NULL, false);
2295
2296
0
    success = do_pset("tableattr", value, &pset.popt, pset.quiet);
2297
0
    free(value);
2298
0
  }
2299
0
  else
2300
0
    ignore_slash_options(scan_state);
2301
2302
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2303
0
}
2304
2305
/*
2306
 * \timing -- enable/disable timing of queries
2307
 */
2308
static backslashResult
2309
exec_command_timing(PsqlScanState scan_state, bool active_branch)
2310
0
{
2311
0
  bool    success = true;
2312
2313
0
  if (active_branch)
2314
0
  {
2315
0
    char     *opt = psql_scan_slash_option(scan_state,
2316
0
                         OT_NORMAL, NULL, false);
2317
2318
0
    if (opt)
2319
0
      success = ParseVariableBool(opt, "\\timing", &pset.timing);
2320
0
    else
2321
0
      pset.timing = !pset.timing;
2322
0
    if (!pset.quiet)
2323
0
    {
2324
0
      if (pset.timing)
2325
0
        puts(_("Timing is on."));
2326
0
      else
2327
0
        puts(_("Timing is off."));
2328
0
    }
2329
0
    free(opt);
2330
0
  }
2331
0
  else
2332
0
    ignore_slash_options(scan_state);
2333
2334
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2335
0
}
2336
2337
/*
2338
 * \unset -- unset variable
2339
 */
2340
static backslashResult
2341
exec_command_unset(PsqlScanState scan_state, bool active_branch,
2342
           const char *cmd)
2343
0
{
2344
0
  bool    success = true;
2345
2346
0
  if (active_branch)
2347
0
  {
2348
0
    char     *opt = psql_scan_slash_option(scan_state,
2349
0
                         OT_NORMAL, NULL, false);
2350
2351
0
    if (!opt)
2352
0
    {
2353
0
      psql_error("\\%s: missing required argument\n", cmd);
2354
0
      success = false;
2355
0
    }
2356
0
    else if (!SetVariable(pset.vars, opt, NULL))
2357
0
      success = false;
2358
2359
0
    free(opt);
2360
0
  }
2361
0
  else
2362
0
    ignore_slash_options(scan_state);
2363
2364
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2365
0
}
2366
2367
/*
2368
 * \w -- write query buffer to file
2369
 */
2370
static backslashResult
2371
exec_command_write(PsqlScanState scan_state, bool active_branch,
2372
           const char *cmd,
2373
           PQExpBuffer query_buf, PQExpBuffer previous_buf)
2374
0
{
2375
0
  backslashResult status = PSQL_CMD_SKIP_LINE;
2376
2377
0
  if (active_branch)
2378
0
  {
2379
0
    char     *fname = psql_scan_slash_option(scan_state,
2380
0
                           OT_FILEPIPE, NULL, true);
2381
0
    FILE     *fd = NULL;
2382
0
    bool    is_pipe = false;
2383
2384
0
    if (!query_buf)
2385
0
    {
2386
0
      psql_error("no query buffer\n");
2387
0
      status = PSQL_CMD_ERROR;
2388
0
    }
2389
0
    else
2390
0
    {
2391
0
      if (!fname)
2392
0
      {
2393
0
        psql_error("\\%s: missing required argument\n", cmd);
2394
0
        status = PSQL_CMD_ERROR;
2395
0
      }
2396
0
      else
2397
0
      {
2398
0
        expand_tilde(&fname);
2399
0
        if (fname[0] == '|')
2400
0
        {
2401
0
          is_pipe = true;
2402
0
          disable_sigpipe_trap();
2403
0
          fd = popen(&fname[1], "w");
2404
0
        }
2405
0
        else
2406
0
        {
2407
0
          canonicalize_path(fname);
2408
0
          fd = fopen(fname, "w");
2409
0
        }
2410
0
        if (!fd)
2411
0
        {
2412
0
          psql_error("%s: %s\n", fname, strerror(errno));
2413
0
          status = PSQL_CMD_ERROR;
2414
0
        }
2415
0
      }
2416
0
    }
2417
2418
0
    if (fd)
2419
0
    {
2420
0
      int     result;
2421
2422
      /*
2423
       * We want to print the same thing \g would execute, but not to
2424
       * change the query buffer state; so we can't use
2425
       * copy_previous_query().  Also, beware of possibility that buffer
2426
       * pointers are NULL.
2427
       */
2428
0
      if (query_buf && query_buf->len > 0)
2429
0
        fprintf(fd, "%s\n", query_buf->data);
2430
0
      else if (previous_buf && previous_buf->len > 0)
2431
0
        fprintf(fd, "%s\n", previous_buf->data);
2432
2433
0
      if (is_pipe)
2434
0
        result = pclose(fd);
2435
0
      else
2436
0
        result = fclose(fd);
2437
2438
0
      if (result == EOF)
2439
0
      {
2440
0
        psql_error("%s: %s\n", fname, strerror(errno));
2441
0
        status = PSQL_CMD_ERROR;
2442
0
      }
2443
0
    }
2444
2445
0
    if (is_pipe)
2446
0
      restore_sigpipe_trap();
2447
2448
0
    free(fname);
2449
0
  }
2450
0
  else
2451
0
    ignore_slash_filepipe(scan_state);
2452
2453
0
  return status;
2454
0
}
2455
2456
/*
2457
 * \watch -- execute a query every N seconds
2458
 */
2459
static backslashResult
2460
exec_command_watch(PsqlScanState scan_state, bool active_branch,
2461
           PQExpBuffer query_buf, PQExpBuffer previous_buf)
2462
0
{
2463
0
  bool    success = true;
2464
2465
0
  if (active_branch)
2466
0
  {
2467
0
    char     *opt = psql_scan_slash_option(scan_state,
2468
0
                         OT_NORMAL, NULL, true);
2469
0
    double    sleep = 2;
2470
2471
    /* Convert optional sleep-length argument */
2472
0
    if (opt)
2473
0
    {
2474
0
      sleep = strtod(opt, NULL);
2475
0
      if (sleep <= 0)
2476
0
        sleep = 1;
2477
0
      free(opt);
2478
0
    }
2479
2480
    /* If query_buf is empty, recall and execute previous query */
2481
0
    copy_previous_query(query_buf, previous_buf);
2482
2483
0
    success = do_watch(query_buf, sleep);
2484
2485
    /* Reset the query buffer as though for \r */
2486
0
    resetPQExpBuffer(query_buf);
2487
0
    psql_scan_reset(scan_state);
2488
0
  }
2489
0
  else
2490
0
    ignore_slash_options(scan_state);
2491
2492
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2493
0
}
2494
2495
/*
2496
 * \x -- set or toggle expanded table representation
2497
 */
2498
static backslashResult
2499
exec_command_x(PsqlScanState scan_state, bool active_branch)
2500
0
{
2501
0
  bool    success = true;
2502
2503
0
  if (active_branch)
2504
0
  {
2505
0
    char     *opt = psql_scan_slash_option(scan_state,
2506
0
                         OT_NORMAL, NULL, true);
2507
2508
0
    success = do_pset("expanded", opt, &pset.popt, pset.quiet);
2509
0
    free(opt);
2510
0
  }
2511
0
  else
2512
0
    ignore_slash_options(scan_state);
2513
2514
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2515
0
}
2516
2517
/*
2518
 * \z -- list table privileges (equivalent to \dp)
2519
 */
2520
static backslashResult
2521
exec_command_z(PsqlScanState scan_state, bool active_branch)
2522
0
{
2523
0
  bool    success = true;
2524
2525
0
  if (active_branch)
2526
0
  {
2527
0
    char     *pattern = psql_scan_slash_option(scan_state,
2528
0
                           OT_NORMAL, NULL, true);
2529
2530
0
    success = permissionsList(pattern);
2531
0
    if (pattern)
2532
0
      free(pattern);
2533
0
  }
2534
0
  else
2535
0
    ignore_slash_options(scan_state);
2536
2537
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2538
0
}
2539
2540
/*
2541
 * \! -- execute shell command
2542
 */
2543
static backslashResult
2544
exec_command_shell_escape(PsqlScanState scan_state, bool active_branch)
2545
0
{
2546
0
  bool    success = true;
2547
2548
0
  if (active_branch)
2549
0
  {
2550
0
    char     *opt = psql_scan_slash_option(scan_state,
2551
0
                         OT_WHOLE_LINE, NULL, false);
2552
2553
0
    success = do_shell(opt);
2554
0
    free(opt);
2555
0
  }
2556
0
  else
2557
0
    ignore_slash_whole_line(scan_state);
2558
2559
0
  return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
2560
0
}
2561
2562
/*
2563
 * \? -- print help about backslash commands
2564
 */
2565
static backslashResult
2566
exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch)
2567
0
{
2568
0
  if (active_branch)
2569
0
  {
2570
0
    char     *opt0 = psql_scan_slash_option(scan_state,
2571
0
                          OT_NORMAL, NULL, false);
2572
2573
0
    if (!opt0 || strcmp(opt0, "commands") == 0)
2574
0
      slashUsage(pset.popt.topt.pager);
2575
0
    else if (strcmp(opt0, "options") == 0)
2576
0
      usage(pset.popt.topt.pager);
2577
0
    else if (strcmp(opt0, "variables") == 0)
2578
0
      helpVariables(pset.popt.topt.pager);
2579
0
    else
2580
0
      slashUsage(pset.popt.topt.pager);
2581
2582
0
    if (opt0)
2583
0
      free(opt0);
2584
0
  }
2585
0
  else
2586
0
    ignore_slash_options(scan_state);
2587
2588
0
  return PSQL_CMD_SKIP_LINE;
2589
0
}
2590
2591
2592
/*
2593
 * Read and interpret an argument to the \connect slash command.
2594
 *
2595
 * Returns a malloc'd string, or NULL if no/empty argument.
2596
 */
2597
static char *
2598
read_connect_arg(PsqlScanState scan_state)
2599
12
{
2600
12
  char     *result;
2601
12
  char    quote;
2602
2603
  /*
2604
   * Ideally we should treat the arguments as SQL identifiers.  But for
2605
   * backwards compatibility with 7.2 and older pg_dump files, we have to
2606
   * take unquoted arguments verbatim (don't downcase them). For now,
2607
   * double-quoted arguments may be stripped of double quotes (as if SQL
2608
   * identifiers).  By 7.4 or so, pg_dump files can be expected to
2609
   * double-quote all mixed-case \connect arguments, and then we can get rid
2610
   * of OT_SQLIDHACK.
2611
   */
2612
12
  result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, &quote, true);
2613
2614
12
  if (!result)
2615
9
    return NULL;
2616
2617
3
  if (quote)
2618
0
    return result;
2619
2620
3
  if (*result == '\0' || strcmp(result, "-") == 0)
2621
0
  {
2622
0
    free(result);
2623
0
    return NULL;
2624
0
  }
2625
2626
3
  return result;
2627
3
}
2628
2629
/*
2630
 * Read a boolean expression, return it as a PQExpBuffer string.
2631
 *
2632
 * Note: anything more or less than one token will certainly fail to be
2633
 * parsed by ParseVariableBool, so we don't worry about complaining here.
2634
 * This routine's return data structure will need to be rethought anyway
2635
 * to support likely future extensions such as "\if defined VARNAME".
2636
 */
2637
static PQExpBuffer
2638
gather_boolean_expression(PsqlScanState scan_state)
2639
0
{
2640
0
  PQExpBuffer exp_buf = createPQExpBuffer();
2641
0
  int     num_options = 0;
2642
0
  char     *value;
2643
2644
  /* collect all arguments for the conditional command into exp_buf */
2645
0
  while ((value = psql_scan_slash_option(scan_state,
2646
0
                       OT_NORMAL, NULL, false)) != NULL)
2647
0
  {
2648
    /* add spaces between tokens */
2649
0
    if (num_options > 0)
2650
0
      appendPQExpBufferChar(exp_buf, ' ');
2651
0
    appendPQExpBufferStr(exp_buf, value);
2652
0
    num_options++;
2653
0
    free(value);
2654
0
  }
2655
2656
0
  return exp_buf;
2657
0
}
2658
2659
/*
2660
 * Read a boolean expression, return true if the expression
2661
 * was a valid boolean expression that evaluated to true.
2662
 * Otherwise return false.
2663
 *
2664
 * Note: conditional stack's top state must be active, else lexer will
2665
 * fail to expand variables and backticks.
2666
 */
2667
static bool
2668
is_true_boolean_expression(PsqlScanState scan_state, const char *name)
2669
0
{
2670
0
  PQExpBuffer buf = gather_boolean_expression(scan_state);
2671
0
  bool    value = false;
2672
0
  bool    success = ParseVariableBool(buf->data, name, &value);
2673
2674
0
  destroyPQExpBuffer(buf);
2675
0
  return success && value;
2676
0
}
2677
2678
/*
2679
 * Read a boolean expression, but do nothing with it.
2680
 *
2681
 * Note: conditional stack's top state must be INACTIVE, else lexer will
2682
 * expand variables and backticks, which we do not want here.
2683
 */
2684
static void
2685
ignore_boolean_expression(PsqlScanState scan_state)
2686
0
{
2687
0
  PQExpBuffer buf = gather_boolean_expression(scan_state);
2688
2689
0
  destroyPQExpBuffer(buf);
2690
0
}
2691
2692
/*
2693
 * Read and discard "normal" slash command options.
2694
 *
2695
 * This should be used for inactive-branch processing of any slash command
2696
 * that eats one or more OT_NORMAL, OT_SQLID, or OT_SQLIDHACK parameters.
2697
 * We don't need to worry about exactly how many it would eat, since the
2698
 * cleanup logic in HandleSlashCmds would silently discard any extras anyway.
2699
 */
2700
static void
2701
ignore_slash_options(PsqlScanState scan_state)
2702
0
{
2703
0
  char     *arg;
2704
2705
0
  while ((arg = psql_scan_slash_option(scan_state,
2706
0
                     OT_NORMAL, NULL, false)) != NULL)
2707
0
    free(arg);
2708
0
}
2709
2710
/*
2711
 * Read and discard FILEPIPE slash command argument.
2712
 *
2713
 * This *MUST* be used for inactive-branch processing of any slash command
2714
 * that takes an OT_FILEPIPE option.  Otherwise we might consume a different
2715
 * amount of option text in active and inactive cases.
2716
 */
2717
static void
2718
ignore_slash_filepipe(PsqlScanState scan_state)
2719
0
{
2720
0
  char     *arg = psql_scan_slash_option(scan_state,
2721
0
                       OT_FILEPIPE, NULL, false);
2722
2723
0
  if (arg)
2724
0
    free(arg);
2725
0
}
2726
2727
/*
2728
 * Read and discard whole-line slash command argument.
2729
 *
2730
 * This *MUST* be used for inactive-branch processing of any slash command
2731
 * that takes an OT_WHOLE_LINE option.  Otherwise we might consume a different
2732
 * amount of option text in active and inactive cases.
2733
 */
2734
static void
2735
ignore_slash_whole_line(PsqlScanState scan_state)
2736
0
{
2737
0
  char     *arg = psql_scan_slash_option(scan_state,
2738
0
                       OT_WHOLE_LINE, NULL, false);
2739
2740
0
  if (arg)
2741
0
    free(arg);
2742
0
}
2743
2744
/*
2745
 * Return true if the command given is a branching command.
2746
 */
2747
static bool
2748
is_branching_command(const char *cmd)
2749
0
{
2750
0
  return (strcmp(cmd, "if") == 0 ||
2751
0
      strcmp(cmd, "elif") == 0 ||
2752
0
      strcmp(cmd, "else") == 0 ||
2753
0
      strcmp(cmd, "endif") == 0);
2754
0
}
2755
2756
/*
2757
 * Prepare to possibly restore query buffer to its current state
2758
 * (cf. discard_query_text).
2759
 *
2760
 * We need to remember the length of the query buffer, and the lexer's
2761
 * notion of the parenthesis nesting depth.
2762
 */
2763
static void
2764
save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
2765
            PQExpBuffer query_buf)
2766
0
{
2767
0
  if (query_buf)
2768
0
    conditional_stack_set_query_len(cstack, query_buf->len);
2769
0
  conditional_stack_set_paren_depth(cstack,
2770
0
                    psql_scan_get_paren_depth(scan_state));
2771
0
}
2772
2773
/*
2774
 * Discard any query text absorbed during an inactive conditional branch.
2775
 *
2776
 * We must discard data that was appended to query_buf during an inactive
2777
 * \if branch.  We don't have to do anything there if there's no query_buf.
2778
 *
2779
 * Also, reset the lexer state to the same paren depth there was before.
2780
 * (The rest of its state doesn't need attention, since we could not be
2781
 * inside a comment or literal or partial token.)
2782
 */
2783
static void
2784
discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
2785
           PQExpBuffer query_buf)
2786
0
{
2787
0
  if (query_buf)
2788
0
  {
2789
0
    int     new_len = conditional_stack_get_query_len(cstack);
2790
2791
0
    Assert(new_len >= 0 && new_len <= query_buf->len);
2792
0
    query_buf->len = new_len;
2793
0
    query_buf->data[new_len] = '\0';
2794
0
  }
2795
0
  psql_scan_set_paren_depth(scan_state,
2796
0
                conditional_stack_get_paren_depth(cstack));
2797
0
}
2798
2799
/*
2800
 * If query_buf is empty, copy previous_buf into it.
2801
 *
2802
 * This is used by various slash commands for which re-execution of a
2803
 * previous query is a common usage.  For convenience, we allow the
2804
 * case of query_buf == NULL (and do nothing).
2805
 */
2806
static void
2807
copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
2808
0
{
2809
0
  if (query_buf && query_buf->len == 0)
2810
0
    appendPQExpBufferStr(query_buf, previous_buf->data);
2811
0
}
2812
2813
/*
2814
 * Ask the user for a password; 'username' is the username the
2815
 * password is for, if one has been explicitly specified. Returns a
2816
 * malloc'd string.
2817
 */
2818
static char *
2819
prompt_for_password(const char *username)
2820
0
{
2821
0
  char    buf[100];
2822
2823
0
  if (username == NULL || username[0] == '\0')
2824
0
    simple_prompt("Password: ", buf, sizeof(buf), false);
2825
0
  else
2826
0
  {
2827
0
    char     *prompt_text;
2828
2829
0
    prompt_text = psprintf(_("Password for user %s: "), username);
2830
0
    simple_prompt(prompt_text, buf, sizeof(buf), false);
2831
0
    free(prompt_text);
2832
0
  }
2833
0
  return pg_strdup(buf);
2834
0
}
2835
2836
static bool
2837
param_is_newly_set(const char *old_val, const char *new_val)
2838
0
{
2839
0
  if (new_val == NULL)
2840
0
    return false;
2841
2842
0
  if (old_val == NULL || strcmp(old_val, new_val) != 0)
2843
0
    return true;
2844
2845
0
  return false;
2846
0
}
2847
2848
/*
2849
 * do_connect -- handler for \connect
2850
 *
2851
 * Connects to a database with given parameters. Absent an established
2852
 * connection, all parameters are required. Given -reuse-previous=off or a
2853
 * connection string without -reuse-previous=on, NULL values will pass through
2854
 * to PQconnectdbParams(), so the libpq defaults will be used. Otherwise, NULL
2855
 * values will be replaced with the ones in the current connection.
2856
 *
2857
 * In interactive mode, if connection fails with the given parameters,
2858
 * the old connection will be kept.
2859
 */
2860
static bool
2861
do_connect(enum trivalue reuse_previous_specification,
2862
       char *dbname, char *user, char *host, char *port)
2863
3
{
2864
3
  PGconn     *o_conn = pset.db,
2865
3
         *n_conn = NULL;
2866
3
  PQconninfoOption *cinfo;
2867
3
  int     nconnopts = 0;
2868
3
  bool    same_host = false;
2869
3
  char     *password = NULL;
2870
3
  char     *client_encoding;
2871
3
  bool    success = true;
2872
3
  bool    keep_password = true;
2873
3
  bool    has_connection_string;
2874
3
  bool    reuse_previous;
2875
2876
3
  if (!o_conn && (!dbname || !user || !host || !port))
2877
0
  {
2878
    /*
2879
     * We don't know the supplied connection parameters and don't want to
2880
     * connect to the wrong database by using defaults, so require all
2881
     * parameters to be specified.
2882
     */
2883
0
    psql_error("All connection parameters must be supplied because no "
2884
0
           "database connection exists\n");
2885
0
    return false;
2886
0
  }
2887
2888
3
  has_connection_string = dbname ?
2889
3
    recognized_connection_string(dbname) : false;
2890
3
  switch (reuse_previous_specification)
2891
3
  {
2892
0
    case TRI_YES:
2893
0
      reuse_previous = true;
2894
0
      break;
2895
0
    case TRI_NO:
2896
0
      reuse_previous = false;
2897
0
      break;
2898
3
    default:
2899
3
      reuse_previous = !has_connection_string;
2900
3
      break;
2901
3
  }
2902
2903
  /* If the old connection does not exist, there is nothing to reuse. */
2904
3
  if (!o_conn)
2905
0
    reuse_previous = false;
2906
2907
  /* Silently ignore arguments subsequent to a connection string. */
2908
3
  if (has_connection_string)
2909
0
  {
2910
0
    user = NULL;
2911
0
    host = NULL;
2912
0
    port = NULL;
2913
0
  }
2914
2915
  /*
2916
   * If we intend to re-use connection parameters, collect them out of the
2917
   * old connection, then replace individual values as necessary. Otherwise,
2918
   * obtain a PQconninfoOption array containing libpq's defaults, and modify
2919
   * that.  Note this function assumes that PQconninfo, PQconndefaults, and
2920
   * PQconninfoParse will all produce arrays containing the same options in
2921
   * the same order.
2922
   */
2923
3
  if (reuse_previous)
2924
3
    cinfo = PQconninfo(o_conn);
2925
0
  else
2926
0
    cinfo = PQconndefaults();
2927
2928
3
  if (cinfo)
2929
3
  {
2930
3
    if (has_connection_string)
2931
0
    {
2932
      /* Parse the connstring and insert values into cinfo */
2933
0
      PQconninfoOption *replcinfo;
2934
0
      char     *errmsg;
2935
2936
0
      replcinfo = PQconninfoParse(dbname, &errmsg);
2937
0
      if (replcinfo)
2938
0
      {
2939
0
        PQconninfoOption *ci;
2940
0
        PQconninfoOption *replci;
2941
0
        bool    have_password = false;
2942
2943
0
        for (ci = cinfo, replci = replcinfo;
2944
0
           ci->keyword && replci->keyword;
2945
0
           ci++, replci++)
2946
0
        {
2947
0
          Assert(strcmp(ci->keyword, replci->keyword) == 0);
2948
          /* Insert value from connstring if one was provided */
2949
0
          if (replci->val)
2950
0
          {
2951
            /*
2952
             * We know that both val strings were allocated by
2953
             * libpq, so the least messy way to avoid memory leaks
2954
             * is to swap them.
2955
             */
2956
0
            char     *swap = replci->val;
2957
2958
0
            replci->val = ci->val;
2959
0
            ci->val = swap;
2960
2961
            /*
2962
             * Check whether connstring provides options affecting
2963
             * password re-use.  While any change in user, host,
2964
             * hostaddr, or port causes us to ignore the old
2965
             * connection's password, we don't force that for
2966
             * dbname, since passwords aren't database-specific.
2967
             */
2968
0
            if (replci->val == NULL ||
2969
0
              strcmp(ci->val, replci->val) != 0)
2970
0
            {
2971
0
              if (strcmp(replci->keyword, "user") == 0 ||
2972
0
                strcmp(replci->keyword, "host") == 0 ||
2973
0
                strcmp(replci->keyword, "hostaddr") == 0 ||
2974
0
                strcmp(replci->keyword, "port") == 0)
2975
0
                keep_password = false;
2976
0
            }
2977
            /* Also note whether connstring contains a password. */
2978
0
            if (strcmp(replci->keyword, "password") == 0)
2979
0
              have_password = true;
2980
0
          }
2981
0
          else if (!reuse_previous)
2982
0
          {
2983
            /*
2984
             * When we have a connstring and are not re-using
2985
             * parameters, swap *all* entries, even those not set
2986
             * by the connstring.  This avoids absorbing
2987
             * environment-dependent defaults from the result of
2988
             * PQconndefaults().  We don't want to do that because
2989
             * they'd override service-file entries if the
2990
             * connstring specifies a service parameter, whereas
2991
             * the priority should be the other way around.  libpq
2992
             * can certainly recompute any defaults we don't pass
2993
             * here.  (In this situation, it's a bit wasteful to
2994
             * have called PQconndefaults() at all, but not doing
2995
             * so would require yet another major code path here.)
2996
             */
2997
0
            replci->val = ci->val;
2998
0
            ci->val = NULL;
2999
0
          }
3000
0
        }
3001
0
        Assert(ci->keyword == NULL && replci->keyword == NULL);
3002
3003
        /* While here, determine how many option slots there are */
3004
0
        nconnopts = ci - cinfo;
3005
3006
0
        PQconninfoFree(replcinfo);
3007
3008
        /*
3009
         * If the connstring contains a password, tell the loop below
3010
         * that we may use it, regardless of other settings (i.e.,
3011
         * cinfo's password is no longer an "old" password).
3012
         */
3013
0
        if (have_password)
3014
0
          keep_password = true;
3015
3016
        /* Don't let code below try to inject dbname into params. */
3017
0
        dbname = NULL;
3018
0
      }
3019
0
      else
3020
0
      {
3021
        /* PQconninfoParse failed */
3022
0
        if (errmsg)
3023
0
        {
3024
0
          psql_error("%s", errmsg);
3025
0
          PQfreemem(errmsg);
3026
0
        }
3027
0
        else
3028
0
          psql_error("out of memory\n");
3029
0
        success = false;
3030
0
      }
3031
0
    }
3032
3
    else
3033
3
    {
3034
      /*
3035
       * If dbname isn't a connection string, then we'll inject it and
3036
       * the other parameters into the keyword array below.  (We can't
3037
       * easily insert them into the cinfo array because of memory
3038
       * management issues: PQconninfoFree would misbehave on Windows.)
3039
       * However, to avoid dependencies on the order in which parameters
3040
       * appear in the array, make a preliminary scan to set
3041
       * keep_password and same_host correctly.
3042
       *
3043
       * While any change in user, host, or port causes us to ignore the
3044
       * old connection's password, we don't force that for dbname,
3045
       * since passwords aren't database-specific.
3046
       */
3047
3
      PQconninfoOption *ci;
3048
3049
87
      for (ci = cinfo; ci->keyword; ci++)
3050
84
      {
3051
84
        if (user && strcmp(ci->keyword, "user") == 0)
3052
0
        {
3053
0
          if (!(ci->val && strcmp(user, ci->val) == 0))
3054
0
            keep_password = false;
3055
0
        }
3056
84
        else if (host && strcmp(ci->keyword, "host") == 0)
3057
0
        {
3058
0
          if (ci->val && strcmp(host, ci->val) == 0)
3059
0
            same_host = true;
3060
0
          else
3061
0
            keep_password = false;
3062
0
        }
3063
84
        else if (port && strcmp(ci->keyword, "port") == 0)
3064
0
        {
3065
0
          if (!(ci->val && strcmp(port, ci->val) == 0))
3066
0
            keep_password = false;
3067
0
        }
3068
84
      }
3069
3070
      /* While here, determine how many option slots there are */
3071
3
      nconnopts = ci - cinfo;
3072
3
    }
3073
3
  }
3074
0
  else
3075
0
  {
3076
    /* We failed to create the cinfo structure */
3077
0
    psql_error("out of memory\n");
3078
0
    success = false;
3079
0
  }
3080
3081
  /*
3082
   * If the user asked to be prompted for a password, ask for one now. If
3083
   * not, use the password from the old connection, provided the username
3084
   * etc have not changed. Otherwise, try to connect without a password
3085
   * first, and then ask for a password if needed.
3086
   *
3087
   * XXX: this behavior leads to spurious connection attempts recorded in
3088
   * the postmaster's log.  But libpq offers no API that would let us obtain
3089
   * a password and then continue with the first connection attempt.
3090
   */
3091
3
  if (pset.getPassword == TRI_YES && success)
3092
0
  {
3093
    /*
3094
     * If a connstring or URI is provided, we don't know which username
3095
     * will be used, since we haven't dug that out of the connstring.
3096
     * Don't risk issuing a misleading prompt.  As in startup.c, it does
3097
     * not seem worth working harder, since this getPassword setting is
3098
     * normally only used in noninteractive cases.
3099
     */
3100
0
    password = prompt_for_password(has_connection_string ? NULL : user);
3101
0
  }
3102
3103
  /*
3104
   * Consider whether to force client_encoding to "auto" (overriding
3105
   * anything in the connection string).  We do so if we have a terminal
3106
   * connection and there is no PGCLIENTENCODING environment setting.
3107
   */
3108
3
  if (pset.notty || getenv("PGCLIENTENCODING"))
3109
3
    client_encoding = NULL;
3110
3
  else
3111
0
    client_encoding = "auto";
3112
3113
  /* Loop till we have a connection or fail, which we might've already */
3114
4
  while (success)
3115
3
  {
3116
3
    const char **keywords = pg_malloc((nconnopts + 1) * sizeof(*keywords));
3117
3
    const char **values = pg_malloc((nconnopts + 1) * sizeof(*values));
3118
3
    int     paramnum = 0;
3119
3
    PQconninfoOption *ci;
3120
3121
    /*
3122
     * Copy non-default settings into the PQconnectdbParams parameter
3123
     * arrays; but inject any values specified old-style, as well as any
3124
     * interactively-obtained password, and a couple of fields we want to
3125
     * set forcibly.
3126
     *
3127
     * If you change this code, see also the initial-connection code in
3128
     * main().
3129
     */
3130
87
    for (ci = cinfo; ci->keyword; ci++)
3131
84
    {
3132
84
      keywords[paramnum] = ci->keyword;
3133
3134
84
      if (dbname && strcmp(ci->keyword, "dbname") == 0)
3135
3
        values[paramnum++] = dbname;
3136
81
      else if (user && strcmp(ci->keyword, "user") == 0)
3137
0
        values[paramnum++] = user;
3138
81
      else if (host && strcmp(ci->keyword, "host") == 0)
3139
0
        values[paramnum++] = host;
3140
81
      else if (host && !same_host && strcmp(ci->keyword, "hostaddr") == 0)
3141
0
      {
3142
        /* If we're changing the host value, drop any old hostaddr */
3143
0
        values[paramnum++] = NULL;
3144
0
      }
3145
81
      else if (port && strcmp(ci->keyword, "port") == 0)
3146
0
        values[paramnum++] = port;
3147
      /* If !keep_password, we unconditionally drop old password */
3148
81
      else if ((password || !keep_password) &&
3149
0
           strcmp(ci->keyword, "password") == 0)
3150
0
        values[paramnum++] = password;
3151
81
      else if (strcmp(ci->keyword, "fallback_application_name") == 0)
3152
3
        values[paramnum++] = pset.progname;
3153
78
      else if (client_encoding &&
3154
0
           strcmp(ci->keyword, "client_encoding") == 0)
3155
0
        values[paramnum++] = client_encoding;
3156
78
      else if (ci->val)
3157
30
        values[paramnum++] = ci->val;
3158
      /* else, don't bother making libpq parse this keyword */
3159
84
    }
3160
    /* add array terminator */
3161
3
    keywords[paramnum] = NULL;
3162
3
    values[paramnum] = NULL;
3163
3164
    /* Note we do not want libpq to re-expand the dbname parameter */
3165
3
    n_conn = PQconnectdbParams(keywords, values, false);
3166
3167
3
    pg_free(keywords);
3168
3
    pg_free(values);
3169
3170
3
    if (PQstatus(n_conn) == CONNECTION_OK)
3171
2
      break;
3172
3173
    /*
3174
     * Connection attempt failed; either retry the connection attempt with
3175
     * a new password, or give up.
3176
     */
3177
1
    if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
3178
0
    {
3179
      /*
3180
       * Prompt for password using the username we actually connected
3181
       * with --- it might've come out of "dbname" rather than "user".
3182
       */
3183
0
      password = prompt_for_password(PQuser(n_conn));
3184
0
      PQfinish(n_conn);
3185
0
      n_conn = NULL;
3186
0
      continue;
3187
0
    }
3188
3189
    /*
3190
     * We'll report the error below ... unless n_conn is NULL, indicating
3191
     * that libpq didn't have enough memory to make a PGconn.
3192
     */
3193
1
    if (n_conn == NULL)
3194
0
      psql_error("out of memory\n");
3195
3196
1
    success = false;
3197
1
  }              /* end retry loop */
3198
3199
  /* Release locally allocated data, whether we succeeded or not */
3200
3
  if (password)
3201
0
    pg_free(password);
3202
3
  if (cinfo)
3203
3
    PQconninfoFree(cinfo);
3204
3205
3
  if (!success)
3206
1
  {
3207
    /*
3208
     * Failed to connect to the database. In interactive mode, keep the
3209
     * previous connection to the DB; in scripting mode, close our
3210
     * previous connection as well.
3211
     */
3212
1
    if (pset.cur_cmd_interactive)
3213
0
    {
3214
0
      if (n_conn)
3215
0
      {
3216
0
        psql_error("%s", PQerrorMessage(n_conn));
3217
0
        PQfinish(n_conn);
3218
0
      }
3219
3220
      /* pset.db is left unmodified */
3221
0
      if (o_conn)
3222
0
        psql_error("Previous connection kept\n");
3223
0
    }
3224
1
    else
3225
1
    {
3226
1
      if (n_conn)
3227
1
      {
3228
1
        psql_error("\\connect: %s", PQerrorMessage(n_conn));
3229
1
        PQfinish(n_conn);
3230
1
      }
3231
3232
1
      if (o_conn)
3233
1
      {
3234
1
        PQfinish(o_conn);
3235
1
        pset.db = NULL;
3236
1
      }
3237
1
    }
3238
3239
1
    return false;
3240
1
  }
3241
3242
  /*
3243
   * Replace the old connection with the new one, and update
3244
   * connection-dependent variables.
3245
   */
3246
2
  PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
3247
2
  pset.db = n_conn;
3248
2
  SyncVariables();
3249
2
  connection_warnings(false); /* Must be after SyncVariables */
3250
3251
  /* Tell the user about the new connection */
3252
2
  if (!pset.quiet)
3253
0
  {
3254
0
    if (!o_conn ||
3255
0
      param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
3256
0
      param_is_newly_set(PQport(o_conn), PQport(pset.db)))
3257
0
    {
3258
0
      char     *host = PQhost(pset.db);
3259
3260
      /* If the host is an absolute path, the connection is via socket */
3261
0
      if (is_absolute_path(host))
3262
0
        printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
3263
0
             PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3264
0
      else
3265
0
        printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
3266
0
             PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3267
0
    }
3268
0
    else
3269
0
      printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
3270
0
           PQdb(pset.db), PQuser(pset.db));
3271
0
  }
3272
3273
2
  if (o_conn)
3274
2
    PQfinish(o_conn);
3275
2
  return true;
3276
2
}
3277
3278
3279
void
3280
connection_warnings(bool in_startup)
3281
2
{
3282
2
  if (!pset.quiet && !pset.notty)
3283
0
  {
3284
0
    int     client_ver = PG_VERSION_NUM;
3285
0
    char    cverbuf[32];
3286
0
    char    sverbuf[32];
3287
3288
0
    if (pset.sversion != client_ver)
3289
0
    {
3290
0
      const char *server_version;
3291
3292
      /* Try to get full text form, might include "devel" etc */
3293
0
      server_version = PQparameterStatus(pset.db, "server_version");
3294
      /* Otherwise fall back on pset.sversion */
3295
0
      if (!server_version)
3296
0
      {
3297
0
        formatPGVersionNumber(pset.sversion, true,
3298
0
                    sverbuf, sizeof(sverbuf));
3299
0
        server_version = sverbuf;
3300
0
      }
3301
3302
0
      printf(_("%s (%s, server %s)\n"),
3303
0
           pset.progname, PG_VERSION, server_version);
3304
0
    }
3305
    /* For version match, only print psql banner on startup. */
3306
0
    else if (in_startup)
3307
0
      printf("%s (%s)\n", pset.progname, PG_VERSION);
3308
3309
0
    if (pset.sversion / 100 > client_ver / 100)
3310
0
      printf(_("WARNING: %s major version %s, server major version %s.\n"
3311
0
           "         Some psql features might not work.\n"),
3312
0
           pset.progname,
3313
0
           formatPGVersionNumber(client_ver, false,
3314
0
                     cverbuf, sizeof(cverbuf)),
3315
0
           formatPGVersionNumber(pset.sversion, false,
3316
0
                     sverbuf, sizeof(sverbuf)));
3317
3318
#ifdef WIN32
3319
    checkWin32Codepage();
3320
#endif
3321
0
    printSSLInfo();
3322
0
  }
3323
2
}
3324
3325
3326
/*
3327
 * printSSLInfo
3328
 *
3329
 * Prints information about the current SSL connection, if SSL is in use
3330
 */
3331
static void
3332
printSSLInfo(void)
3333
0
{
3334
0
  const char *protocol;
3335
0
  const char *cipher;
3336
0
  const char *bits;
3337
0
  const char *compression;
3338
3339
0
  if (!PQsslInUse(pset.db))
3340
0
    return;         /* no SSL */
3341
3342
0
  protocol = PQsslAttribute(pset.db, "protocol");
3343
0
  cipher = PQsslAttribute(pset.db, "cipher");
3344
0
  bits = PQsslAttribute(pset.db, "key_bits");
3345
0
  compression = PQsslAttribute(pset.db, "compression");
3346
3347
0
  printf(_("SSL connection (protocol: %s, cipher: %s, bits: %s, compression: %s)\n"),
3348
0
       protocol ? protocol : _("unknown"),
3349
0
       cipher ? cipher : _("unknown"),
3350
0
       bits ? bits : _("unknown"),
3351
0
       (compression && strcmp(compression, "off") != 0) ? _("on") : _("off"));
3352
0
}
3353
3354
3355
/*
3356
 * checkWin32Codepage
3357
 *
3358
 * Prints a warning when win32 console codepage differs from Windows codepage
3359
 */
3360
#ifdef WIN32
3361
static void
3362
checkWin32Codepage(void)
3363
{
3364
  unsigned int wincp,
3365
        concp;
3366
3367
  wincp = GetACP();
3368
  concp = GetConsoleCP();
3369
  if (wincp != concp)
3370
  {
3371
    printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
3372
         "         8-bit characters might not work correctly. See psql reference\n"
3373
         "         page \"Notes for Windows users\" for details.\n"),
3374
         concp, wincp);
3375
  }
3376
}
3377
#endif
3378
3379
3380
/*
3381
 * SyncVariables
3382
 *
3383
 * Make psql's internal variables agree with connection state upon
3384
 * establishing a new connection.
3385
 */
3386
void
3387
SyncVariables(void)
3388
40
{
3389
40
  char    vbuf[32];
3390
40
  const char *server_version;
3391
3392
  /* get stuff from connection */
3393
40
  pset.encoding = PQclientEncoding(pset.db);
3394
40
  pset.popt.topt.encoding = pset.encoding;
3395
40
  pset.sversion = PQserverVersion(pset.db);
3396
3397
40
  SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
3398
40
  SetVariable(pset.vars, "USER", PQuser(pset.db));
3399
40
  SetVariable(pset.vars, "HOST", PQhost(pset.db));
3400
40
  SetVariable(pset.vars, "PORT", PQport(pset.db));
3401
40
  SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
3402
3403
  /* this bit should match connection_warnings(): */
3404
  /* Try to get full text form of version, might include "devel" etc */
3405
40
  server_version = PQparameterStatus(pset.db, "server_version");
3406
  /* Otherwise fall back on pset.sversion */
3407
40
  if (!server_version)
3408
0
  {
3409
0
    formatPGVersionNumber(pset.sversion, true, vbuf, sizeof(vbuf));
3410
0
    server_version = vbuf;
3411
0
  }
3412
40
  SetVariable(pset.vars, "SERVER_VERSION_NAME", server_version);
3413
3414
40
  snprintf(vbuf, sizeof(vbuf), "%d", pset.sversion);
3415
40
  SetVariable(pset.vars, "SERVER_VERSION_NUM", vbuf);
3416
3417
  /* send stuff to it, too */
3418
40
  PQsetErrorVerbosity(pset.db, pset.verbosity);
3419
40
  PQsetErrorContextVisibility(pset.db, pset.show_context);
3420
40
}
3421
3422
/*
3423
 * UnsyncVariables
3424
 *
3425
 * Clear variables that should be not be set when there is no connection.
3426
 */
3427
void
3428
UnsyncVariables(void)
3429
0
{
3430
0
  SetVariable(pset.vars, "DBNAME", NULL);
3431
0
  SetVariable(pset.vars, "USER", NULL);
3432
0
  SetVariable(pset.vars, "HOST", NULL);
3433
0
  SetVariable(pset.vars, "PORT", NULL);
3434
0
  SetVariable(pset.vars, "ENCODING", NULL);
3435
0
  SetVariable(pset.vars, "SERVER_VERSION_NAME", NULL);
3436
0
  SetVariable(pset.vars, "SERVER_VERSION_NUM", NULL);
3437
0
}
3438
3439
3440
/*
3441
 * do_edit -- handler for \e
3442
 *
3443
 * If you do not specify a filename, the current query buffer will be copied
3444
 * into a temporary one.
3445
 */
3446
static bool
3447
editFile(const char *fname, int lineno)
3448
0
{
3449
0
  const char *editorName;
3450
0
  const char *editor_lineno_arg = NULL;
3451
0
  char     *sys;
3452
0
  int     result;
3453
3454
0
  Assert(fname != NULL);
3455
3456
  /* Find an editor to use */
3457
0
  editorName = getenv("PSQL_EDITOR");
3458
0
  if (!editorName)
3459
0
    editorName = getenv("EDITOR");
3460
0
  if (!editorName)
3461
0
    editorName = getenv("VISUAL");
3462
0
  if (!editorName)
3463
0
    editorName = DEFAULT_EDITOR;
3464
3465
  /* Get line number argument, if we need it. */
3466
0
  if (lineno > 0)
3467
0
  {
3468
0
    editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
3469
0
#ifdef DEFAULT_EDITOR_LINENUMBER_ARG
3470
0
    if (!editor_lineno_arg)
3471
0
      editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
3472
0
#endif
3473
0
    if (!editor_lineno_arg)
3474
0
    {
3475
0
      psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
3476
0
      return false;
3477
0
    }
3478
0
  }
3479
3480
  /*
3481
   * On Unix the EDITOR value should *not* be quoted, since it might include
3482
   * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
3483
   * if necessary.  But this policy is not very workable on Windows, due to
3484
   * severe brain damage in their command shell plus the fact that standard
3485
   * program paths include spaces.
3486
   */
3487
0
#ifndef WIN32
3488
0
  if (lineno > 0)
3489
0
    sys = psprintf("exec %s %s%d '%s'",
3490
0
             editorName, editor_lineno_arg, lineno, fname);
3491
0
  else
3492
0
    sys = psprintf("exec %s '%s'",
3493
0
             editorName, fname);
3494
#else
3495
  if (lineno > 0)
3496
    sys = psprintf("\"%s\" %s%d \"%s\"",
3497
             editorName, editor_lineno_arg, lineno, fname);
3498
  else
3499
    sys = psprintf("\"%s\" \"%s\"",
3500
             editorName, fname);
3501
#endif
3502
0
  result = system(sys);
3503
0
  if (result == -1)
3504
0
    psql_error("could not start editor \"%s\"\n", editorName);
3505
0
  else if (result == 127)
3506
0
    psql_error("could not start /bin/sh\n");
3507
0
  free(sys);
3508
3509
0
  return result == 0;
3510
0
}
3511
3512
3513
/* call this one */
3514
static bool
3515
do_edit(const char *filename_arg, PQExpBuffer query_buf,
3516
    int lineno, bool *edited)
3517
0
{
3518
0
  char    fnametmp[MAXPGPATH];
3519
0
  FILE     *stream = NULL;
3520
0
  const char *fname;
3521
0
  bool    error = false;
3522
0
  int     fd;
3523
0
  struct stat before,
3524
0
        after;
3525
3526
0
  if (filename_arg)
3527
0
    fname = filename_arg;
3528
0
  else
3529
0
  {
3530
    /* make a temp file to edit */
3531
0
#ifndef WIN32
3532
0
    const char *tmpdir = getenv("TMPDIR");
3533
3534
0
    if (!tmpdir)
3535
0
      tmpdir = "/tmp";
3536
#else
3537
    char    tmpdir[MAXPGPATH];
3538
    int     ret;
3539
3540
    ret = GetTempPath(MAXPGPATH, tmpdir);
3541
    if (ret == 0 || ret > MAXPGPATH)
3542
    {
3543
      psql_error("could not locate temporary directory: %s\n",
3544
             !ret ? strerror(errno) : "");
3545
      return false;
3546
    }
3547
#endif
3548
3549
    /*
3550
     * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
3551
     * current directory to the supplied path unless we use only
3552
     * backslashes, so we do that.
3553
     */
3554
0
#ifndef WIN32
3555
0
    snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
3556
0
         "/", (int) getpid());
3557
#else
3558
    snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
3559
         "" /* trailing separator already present */ , (int) getpid());
3560
#endif
3561
3562
0
    fname = (const char *) fnametmp;
3563
3564
0
    fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
3565
0
    if (fd != -1)
3566
0
      stream = fdopen(fd, "w");
3567
3568
0
    if (fd == -1 || !stream)
3569
0
    {
3570
0
      psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
3571
0
      error = true;
3572
0
    }
3573
0
    else
3574
0
    {
3575
0
      unsigned int ql = query_buf->len;
3576
3577
0
      if (ql == 0 || query_buf->data[ql - 1] != '\n')
3578
0
      {
3579
0
        appendPQExpBufferChar(query_buf, '\n');
3580
0
        ql++;
3581
0
      }
3582
3583
0
      if (fwrite(query_buf->data, 1, ql, stream) != ql)
3584
0
      {
3585
0
        psql_error("%s: %s\n", fname, strerror(errno));
3586
3587
0
        if (fclose(stream) != 0)
3588
0
          psql_error("%s: %s\n", fname, strerror(errno));
3589
3590
0
        if (remove(fname) != 0)
3591
0
          psql_error("%s: %s\n", fname, strerror(errno));
3592
3593
0
        error = true;
3594
0
      }
3595
0
      else if (fclose(stream) != 0)
3596
0
      {
3597
0
        psql_error("%s: %s\n", fname, strerror(errno));
3598
0
        if (remove(fname) != 0)
3599
0
          psql_error("%s: %s\n", fname, strerror(errno));
3600
0
        error = true;
3601
0
      }
3602
0
      else
3603
0
      {
3604
0
        struct utimbuf ut;
3605
3606
        /*
3607
         * Try to set the file modification time of the temporary file
3608
         * a few seconds in the past.  Otherwise, the low granularity
3609
         * (one second, or even worse on some filesystems) that we can
3610
         * portably measure with stat(2) could lead us to not
3611
         * recognize a modification, if the user typed very quickly.
3612
         *
3613
         * This is a rather unlikely race condition, so don't error
3614
         * out if the utime(2) call fails --- that would make the cure
3615
         * worse than the disease.
3616
         */
3617
0
        ut.modtime = ut.actime = time(NULL) - 2;
3618
0
        (void) utime(fname, &ut);
3619
0
      }
3620
0
    }
3621
0
  }
3622
3623
0
  if (!error && stat(fname, &before) != 0)
3624
0
  {
3625
0
    psql_error("%s: %s\n", fname, strerror(errno));
3626
0
    error = true;
3627
0
  }
3628
3629
  /* call editor */
3630
0
  if (!error)
3631
0
    error = !editFile(fname, lineno);
3632
3633
0
  if (!error && stat(fname, &after) != 0)
3634
0
  {
3635
0
    psql_error("%s: %s\n", fname, strerror(errno));
3636
0
    error = true;
3637
0
  }
3638
3639
  /* file was edited if the size or modification time has changed */
3640
0
  if (!error &&
3641
0
    (before.st_size != after.st_size ||
3642
0
     before.st_mtime != after.st_mtime))
3643
0
  {
3644
0
    stream = fopen(fname, PG_BINARY_R);
3645
0
    if (!stream)
3646
0
    {
3647
0
      psql_error("%s: %s\n", fname, strerror(errno));
3648
0
      error = true;
3649
0
    }
3650
0
    else
3651
0
    {
3652
      /* read file back into query_buf */
3653
0
      char    line[1024];
3654
3655
0
      resetPQExpBuffer(query_buf);
3656
0
      while (fgets(line, sizeof(line), stream) != NULL)
3657
0
        appendPQExpBufferStr(query_buf, line);
3658
3659
0
      if (ferror(stream))
3660
0
      {
3661
0
        psql_error("%s: %s\n", fname, strerror(errno));
3662
0
        error = true;
3663
0
      }
3664
0
      else if (edited)
3665
0
      {
3666
0
        *edited = true;
3667
0
      }
3668
3669
0
      fclose(stream);
3670
0
    }
3671
0
  }
3672
3673
  /* remove temp file */
3674
0
  if (!filename_arg)
3675
0
  {
3676
0
    if (remove(fname) == -1)
3677
0
    {
3678
0
      psql_error("%s: %s\n", fname, strerror(errno));
3679
0
      error = true;
3680
0
    }
3681
0
  }
3682
3683
0
  return !error;
3684
0
}
3685
3686
3687
3688
/*
3689
 * process_file
3690
 *
3691
 * Reads commands from filename and passes them to the main processing loop.
3692
 * Handler for \i and \ir, but can be used for other things as well.  Returns
3693
 * MainLoop() error code.
3694
 *
3695
 * If use_relative_path is true and filename is not an absolute path, then open
3696
 * the file from where the currently processed file (if any) is located.
3697
 */
3698
int
3699
process_file(char *filename, bool use_relative_path)
3700
38
{
3701
38
  FILE     *fd;
3702
38
  int     result;
3703
38
  char     *oldfilename;
3704
38
  char    relpath[MAXPGPATH];
3705
3706
38
  if (!filename)
3707
38
  {
3708
38
    fd = stdin;
3709
38
    filename = NULL;
3710
38
  }
3711
0
  else if (strcmp(filename, "-") != 0)
3712
0
  {
3713
0
    canonicalize_path(filename);
3714
3715
    /*
3716
     * If we were asked to resolve the pathname relative to the location
3717
     * of the currently executing script, and there is one, and this is a
3718
     * relative pathname, then prepend all but the last pathname component
3719
     * of the current script to this pathname.
3720
     */
3721
0
    if (use_relative_path && pset.inputfile &&
3722
0
      !is_absolute_path(filename) && !has_drive_prefix(filename))
3723
0
    {
3724
0
      strlcpy(relpath, pset.inputfile, sizeof(relpath));
3725
0
      get_parent_directory(relpath);
3726
0
      join_path_components(relpath, relpath, filename);
3727
0
      canonicalize_path(relpath);
3728
3729
0
      filename = relpath;
3730
0
    }
3731
3732
0
    fd = fopen(filename, PG_BINARY_R);
3733
3734
0
    if (!fd)
3735
0
    {
3736
0
      psql_error("%s: %s\n", filename, strerror(errno));
3737
0
      return EXIT_FAILURE;
3738
0
    }
3739
0
  }
3740
0
  else
3741
0
  {
3742
0
    fd = stdin;
3743
0
    filename = "<stdin>"; /* for future error messages */
3744
0
  }
3745
3746
38
  oldfilename = pset.inputfile;
3747
38
  pset.inputfile = filename;
3748
3749
38
  result = MainLoop(fd);
3750
3751
38
  if (fd != stdin)
3752
0
    fclose(fd);
3753
3754
38
  pset.inputfile = oldfilename;
3755
38
  return result;
3756
38
}
3757
3758
3759
3760
static const char *
3761
_align2string(enum printFormat in)
3762
0
{
3763
0
  switch (in)
3764
0
  {
3765
0
    case PRINT_NOTHING:
3766
0
      return "nothing";
3767
0
      break;
3768
0
    case PRINT_UNALIGNED:
3769
0
      return "unaligned";
3770
0
      break;
3771
0
    case PRINT_ALIGNED:
3772
0
      return "aligned";
3773
0
      break;
3774
0
    case PRINT_WRAPPED:
3775
0
      return "wrapped";
3776
0
      break;
3777
0
    case PRINT_HTML:
3778
0
      return "html";
3779
0
      break;
3780
0
    case PRINT_ASCIIDOC:
3781
0
      return "asciidoc";
3782
0
      break;
3783
0
    case PRINT_LATEX:
3784
0
      return "latex";
3785
0
      break;
3786
0
    case PRINT_LATEX_LONGTABLE:
3787
0
      return "latex-longtable";
3788
0
      break;
3789
0
    case PRINT_TROFF_MS:
3790
0
      return "troff-ms";
3791
0
      break;
3792
0
  }
3793
0
  return "unknown";
3794
0
}
3795
3796
/*
3797
 * Parse entered Unicode linestyle.  If ok, update *linestyle and return
3798
 * true, else return false.
3799
 */
3800
static bool
3801
set_unicode_line_style(const char *value, size_t vallen,
3802
             unicode_linestyle *linestyle)
3803
0
{
3804
0
  if (pg_strncasecmp("single", value, vallen) == 0)
3805
0
    *linestyle = UNICODE_LINESTYLE_SINGLE;
3806
0
  else if (pg_strncasecmp("double", value, vallen) == 0)
3807
0
    *linestyle = UNICODE_LINESTYLE_DOUBLE;
3808
0
  else
3809
0
    return false;
3810
0
  return true;
3811
0
}
3812
3813
static const char *
3814
_unicode_linestyle2string(int linestyle)
3815
0
{
3816
0
  switch (linestyle)
3817
0
  {
3818
0
    case UNICODE_LINESTYLE_SINGLE:
3819
0
      return "single";
3820
0
      break;
3821
0
    case UNICODE_LINESTYLE_DOUBLE:
3822
0
      return "double";
3823
0
      break;
3824
0
  }
3825
0
  return "unknown";
3826
0
}
3827
3828
/*
3829
 * do_pset
3830
 *
3831
 */
3832
bool
3833
do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
3834
9
{
3835
9
  size_t    vallen = 0;
3836
3837
9
  Assert(param != NULL);
3838
3839
9
  if (value)
3840
9
    vallen = strlen(value);
3841
3842
  /* set format */
3843
9
  if (strcmp(param, "format") == 0)
3844
0
  {
3845
0
    if (!value)
3846
0
      ;
3847
0
    else if (pg_strncasecmp("unaligned", value, vallen) == 0)
3848
0
      popt->topt.format = PRINT_UNALIGNED;
3849
0
    else if (pg_strncasecmp("aligned", value, vallen) == 0)
3850
0
      popt->topt.format = PRINT_ALIGNED;
3851
0
    else if (pg_strncasecmp("wrapped", value, vallen) == 0)
3852
0
      popt->topt.format = PRINT_WRAPPED;
3853
0
    else if (pg_strncasecmp("html", value, vallen) == 0)
3854
0
      popt->topt.format = PRINT_HTML;
3855
0
    else if (pg_strncasecmp("asciidoc", value, vallen) == 0)
3856
0
      popt->topt.format = PRINT_ASCIIDOC;
3857
0
    else if (pg_strncasecmp("latex", value, vallen) == 0)
3858
0
      popt->topt.format = PRINT_LATEX;
3859
0
    else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
3860
0
      popt->topt.format = PRINT_LATEX_LONGTABLE;
3861
0
    else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
3862
0
      popt->topt.format = PRINT_TROFF_MS;
3863
0
    else
3864
0
    {
3865
0
      psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms\n");
3866
0
      return false;
3867
0
    }
3868
9
  }
3869
3870
  /* set table line style */
3871
9
  else if (strcmp(param, "linestyle") == 0)
3872
0
  {
3873
0
    if (!value)
3874
0
      ;
3875
0
    else if (pg_strncasecmp("ascii", value, vallen) == 0)
3876
0
      popt->topt.line_style = &pg_asciiformat;
3877
0
    else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
3878
0
      popt->topt.line_style = &pg_asciiformat_old;
3879
0
    else if (pg_strncasecmp("unicode", value, vallen) == 0)
3880
0
      popt->topt.line_style = &pg_utf8format;
3881
0
    else
3882
0
    {
3883
0
      psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
3884
0
      return false;
3885
0
    }
3886
9
  }
3887
3888
  /* set unicode border line style */
3889
9
  else if (strcmp(param, "unicode_border_linestyle") == 0)
3890
0
  {
3891
0
    if (!value)
3892
0
      ;
3893
0
    else if (set_unicode_line_style(value, vallen,
3894
0
                    &popt->topt.unicode_border_linestyle))
3895
0
      refresh_utf8format(&(popt->topt));
3896
0
    else
3897
0
    {
3898
0
      psql_error("\\pset: allowed Unicode border line styles are single, double\n");
3899
0
      return false;
3900
0
    }
3901
9
  }
3902
3903
  /* set unicode column line style */
3904
9
  else if (strcmp(param, "unicode_column_linestyle") == 0)
3905
0
  {
3906
0
    if (!value)
3907
0
      ;
3908
0
    else if (set_unicode_line_style(value, vallen,
3909
0
                    &popt->topt.unicode_column_linestyle))
3910
0
      refresh_utf8format(&(popt->topt));
3911
0
    else
3912
0
    {
3913
0
      psql_error("\\pset: allowed Unicode column line styles are single, double\n");
3914
0
      return false;
3915
0
    }
3916
9
  }
3917
3918
  /* set unicode header line style */
3919
9
  else if (strcmp(param, "unicode_header_linestyle") == 0)
3920
0
  {
3921
0
    if (!value)
3922
0
      ;
3923
0
    else if (set_unicode_line_style(value, vallen,
3924
0
                    &popt->topt.unicode_header_linestyle))
3925
0
      refresh_utf8format(&(popt->topt));
3926
0
    else
3927
0
    {
3928
0
      psql_error("\\pset: allowed Unicode header line styles are single, double\n");
3929
0
      return false;
3930
0
    }
3931
9
  }
3932
3933
  /* set border style/width */
3934
9
  else if (strcmp(param, "border") == 0)
3935
0
  {
3936
0
    if (value)
3937
0
      popt->topt.border = atoi(value);
3938
0
  }
3939
3940
  /* set expanded/vertical mode */
3941
9
  else if (strcmp(param, "x") == 0 ||
3942
9
       strcmp(param, "expanded") == 0 ||
3943
9
       strcmp(param, "vertical") == 0)
3944
0
  {
3945
0
    if (value && pg_strcasecmp(value, "auto") == 0)
3946
0
      popt->topt.expanded = 2;
3947
0
    else if (value)
3948
0
    {
3949
0
      bool    on_off;
3950
3951
0
      if (ParseVariableBool(value, NULL, &on_off))
3952
0
        popt->topt.expanded = on_off ? 1 : 0;
3953
0
      else
3954
0
      {
3955
0
        PsqlVarEnumError(param, value, "on, off, auto");
3956
0
        return false;
3957
0
      }
3958
0
    }
3959
0
    else
3960
0
      popt->topt.expanded = !popt->topt.expanded;
3961
0
  }
3962
3963
  /* locale-aware numeric output */
3964
9
  else if (strcmp(param, "numericlocale") == 0)
3965
0
  {
3966
0
    if (value)
3967
0
      return ParseVariableBool(value, param, &popt->topt.numericLocale);
3968
0
    else
3969
0
      popt->topt.numericLocale = !popt->topt.numericLocale;
3970
0
  }
3971
3972
  /* null display */
3973
9
  else if (strcmp(param, "null") == 0)
3974
1
  {
3975
1
    if (value)
3976
1
    {
3977
1
      free(popt->nullPrint);
3978
1
      popt->nullPrint = pg_strdup(value);
3979
1
    }
3980
1
  }
3981
3982
  /* field separator for unaligned text */
3983
8
  else if (strcmp(param, "fieldsep") == 0)
3984
0
  {
3985
0
    if (value)
3986
0
    {
3987
0
      free(popt->topt.fieldSep.separator);
3988
0
      popt->topt.fieldSep.separator = pg_strdup(value);
3989
0
      popt->topt.fieldSep.separator_zero = false;
3990
0
    }
3991
0
  }
3992
3993
8
  else if (strcmp(param, "fieldsep_zero") == 0)
3994
0
  {
3995
0
    free(popt->topt.fieldSep.separator);
3996
0
    popt->topt.fieldSep.separator = NULL;
3997
0
    popt->topt.fieldSep.separator_zero = true;
3998
0
  }
3999
4000
  /* record separator for unaligned text */
4001
8
  else if (strcmp(param, "recordsep") == 0)
4002
0
  {
4003
0
    if (value)
4004
0
    {
4005
0
      free(popt->topt.recordSep.separator);
4006
0
      popt->topt.recordSep.separator = pg_strdup(value);
4007
0
      popt->topt.recordSep.separator_zero = false;
4008
0
    }
4009
0
  }
4010
4011
8
  else if (strcmp(param, "recordsep_zero") == 0)
4012
0
  {
4013
0
    free(popt->topt.recordSep.separator);
4014
0
    popt->topt.recordSep.separator = NULL;
4015
0
    popt->topt.recordSep.separator_zero = true;
4016
0
  }
4017
4018
  /* toggle between full and tuples-only format */
4019
8
  else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
4020
8
  {
4021
8
    if (value)
4022
8
      return ParseVariableBool(value, param, &popt->topt.tuples_only);
4023
0
    else
4024
0
      popt->topt.tuples_only = !popt->topt.tuples_only;
4025
8
  }
4026
4027
  /* set title override */
4028
0
  else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
4029
0
  {
4030
0
    free(popt->title);
4031
0
    if (!value)
4032
0
      popt->title = NULL;
4033
0
    else
4034
0
      popt->title = pg_strdup(value);
4035
0
  }
4036
4037
  /* set HTML table tag options */
4038
0
  else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
4039
0
  {
4040
0
    free(popt->topt.tableAttr);
4041
0
    if (!value)
4042
0
      popt->topt.tableAttr = NULL;
4043
0
    else
4044
0
      popt->topt.tableAttr = pg_strdup(value);
4045
0
  }
4046
4047
  /* toggle use of pager */
4048
0
  else if (strcmp(param, "pager") == 0)
4049
0
  {
4050
0
    if (value && pg_strcasecmp(value, "always") == 0)
4051
0
      popt->topt.pager = 2;
4052
0
    else if (value)
4053
0
    {
4054
0
      bool    on_off;
4055
4056
0
      if (!ParseVariableBool(value, NULL, &on_off))
4057
0
      {
4058
0
        PsqlVarEnumError(param, value, "on, off, always");
4059
0
        return false;
4060
0
      }
4061
0
      popt->topt.pager = on_off ? 1 : 0;
4062
0
    }
4063
0
    else if (popt->topt.pager == 1)
4064
0
      popt->topt.pager = 0;
4065
0
    else
4066
0
      popt->topt.pager = 1;
4067
0
  }
4068
4069
  /* set minimum lines for pager use */
4070
0
  else if (strcmp(param, "pager_min_lines") == 0)
4071
0
  {
4072
0
    if (value)
4073
0
      popt->topt.pager_min_lines = atoi(value);
4074
0
  }
4075
4076
  /* disable "(x rows)" footer */
4077
0
  else if (strcmp(param, "footer") == 0)
4078
0
  {
4079
0
    if (value)
4080
0
      return ParseVariableBool(value, param, &popt->topt.default_footer);
4081
0
    else
4082
0
      popt->topt.default_footer = !popt->topt.default_footer;
4083
0
  }
4084
4085
  /* set border style/width */
4086
0
  else if (strcmp(param, "columns") == 0)
4087
0
  {
4088
0
    if (value)
4089
0
      popt->topt.columns = atoi(value);
4090
0
  }
4091
0
  else
4092
0
  {
4093
0
    psql_error("\\pset: unknown option: %s\n", param);
4094
0
    return false;
4095
0
  }
4096
4097
1
  if (!quiet)
4098
0
    printPsetInfo(param, &pset.popt);
4099
4100
1
  return true;
4101
1
}
4102
4103
4104
static bool
4105
printPsetInfo(const char *param, struct printQueryOpt *popt)
4106
0
{
4107
0
  Assert(param != NULL);
4108
4109
  /* show border style/width */
4110
0
  if (strcmp(param, "border") == 0)
4111
0
    printf(_("Border style is %d.\n"), popt->topt.border);
4112
4113
  /* show the target width for the wrapped format */
4114
0
  else if (strcmp(param, "columns") == 0)
4115
0
  {
4116
0
    if (!popt->topt.columns)
4117
0
      printf(_("Target width is unset.\n"));
4118
0
    else
4119
0
      printf(_("Target width is %d.\n"), popt->topt.columns);
4120
0
  }
4121
4122
  /* show expanded/vertical mode */
4123
0
  else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
4124
0
  {
4125
0
    if (popt->topt.expanded == 1)
4126
0
      printf(_("Expanded display is on.\n"));
4127
0
    else if (popt->topt.expanded == 2)
4128
0
      printf(_("Expanded display is used automatically.\n"));
4129
0
    else
4130
0
      printf(_("Expanded display is off.\n"));
4131
0
  }
4132
4133
  /* show field separator for unaligned text */
4134
0
  else if (strcmp(param, "fieldsep") == 0)
4135
0
  {
4136
0
    if (popt->topt.fieldSep.separator_zero)
4137
0
      printf(_("Field separator is zero byte.\n"));
4138
0
    else
4139
0
      printf(_("Field separator is \"%s\".\n"),
4140
0
           popt->topt.fieldSep.separator);
4141
0
  }
4142
4143
0
  else if (strcmp(param, "fieldsep_zero") == 0)
4144
0
  {
4145
0
    printf(_("Field separator is zero byte.\n"));
4146
0
  }
4147
4148
  /* show disable "(x rows)" footer */
4149
0
  else if (strcmp(param, "footer") == 0)
4150
0
  {
4151
0
    if (popt->topt.default_footer)
4152
0
      printf(_("Default footer is on.\n"));
4153
0
    else
4154
0
      printf(_("Default footer is off.\n"));
4155
0
  }
4156
4157
  /* show format */
4158
0
  else if (strcmp(param, "format") == 0)
4159
0
  {
4160
0
    printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
4161
0
  }
4162
4163
  /* show table line style */
4164
0
  else if (strcmp(param, "linestyle") == 0)
4165
0
  {
4166
0
    printf(_("Line style is %s.\n"),
4167
0
         get_line_style(&popt->topt)->name);
4168
0
  }
4169
4170
  /* show null display */
4171
0
  else if (strcmp(param, "null") == 0)
4172
0
  {
4173
0
    printf(_("Null display is \"%s\".\n"),
4174
0
         popt->nullPrint ? popt->nullPrint : "");
4175
0
  }
4176
4177
  /* show locale-aware numeric output */
4178
0
  else if (strcmp(param, "numericlocale") == 0)
4179
0
  {
4180
0
    if (popt->topt.numericLocale)
4181
0
      printf(_("Locale-adjusted numeric output is on.\n"));
4182
0
    else
4183
0
      printf(_("Locale-adjusted numeric output is off.\n"));
4184
0
  }
4185
4186
  /* show toggle use of pager */
4187
0
  else if (strcmp(param, "pager") == 0)
4188
0
  {
4189
0
    if (popt->topt.pager == 1)
4190
0
      printf(_("Pager is used for long output.\n"));
4191
0
    else if (popt->topt.pager == 2)
4192
0
      printf(_("Pager is always used.\n"));
4193
0
    else
4194
0
      printf(_("Pager usage is off.\n"));
4195
0
  }
4196
4197
  /* show minimum lines for pager use */
4198
0
  else if (strcmp(param, "pager_min_lines") == 0)
4199
0
  {
4200
0
    printf(ngettext("Pager won't be used for less than %d line.\n",
4201
0
            "Pager won't be used for less than %d lines.\n",
4202
0
            popt->topt.pager_min_lines),
4203
0
         popt->topt.pager_min_lines);
4204
0
  }
4205
4206
  /* show record separator for unaligned text */
4207
0
  else if (strcmp(param, "recordsep") == 0)
4208
0
  {
4209
0
    if (popt->topt.recordSep.separator_zero)
4210
0
      printf(_("Record separator is zero byte.\n"));
4211
0
    else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
4212
0
      printf(_("Record separator is <newline>.\n"));
4213
0
    else
4214
0
      printf(_("Record separator is \"%s\".\n"),
4215
0
           popt->topt.recordSep.separator);
4216
0
  }
4217
4218
0
  else if (strcmp(param, "recordsep_zero") == 0)
4219
0
  {
4220
0
    printf(_("Record separator is zero byte.\n"));
4221
0
  }
4222
4223
  /* show HTML table tag options */
4224
0
  else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
4225
0
  {
4226
0
    if (popt->topt.tableAttr)
4227
0
      printf(_("Table attributes are \"%s\".\n"),
4228
0
           popt->topt.tableAttr);
4229
0
    else
4230
0
      printf(_("Table attributes unset.\n"));
4231
0
  }
4232
4233
  /* show title override */
4234
0
  else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
4235
0
  {
4236
0
    if (popt->title)
4237
0
      printf(_("Title is \"%s\".\n"), popt->title);
4238
0
    else
4239
0
      printf(_("Title is unset.\n"));
4240
0
  }
4241
4242
  /* show toggle between full and tuples-only format */
4243
0
  else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
4244
0
  {
4245
0
    if (popt->topt.tuples_only)
4246
0
      printf(_("Tuples only is on.\n"));
4247
0
    else
4248
0
      printf(_("Tuples only is off.\n"));
4249
0
  }
4250
4251
  /* Unicode style formatting */
4252
0
  else if (strcmp(param, "unicode_border_linestyle") == 0)
4253
0
  {
4254
0
    printf(_("Unicode border line style is \"%s\".\n"),
4255
0
         _unicode_linestyle2string(popt->topt.unicode_border_linestyle));
4256
0
  }
4257
4258
0
  else if (strcmp(param, "unicode_column_linestyle") == 0)
4259
0
  {
4260
0
    printf(_("Unicode column line style is \"%s\".\n"),
4261
0
         _unicode_linestyle2string(popt->topt.unicode_column_linestyle));
4262
0
  }
4263
4264
0
  else if (strcmp(param, "unicode_header_linestyle") == 0)
4265
0
  {
4266
0
    printf(_("Unicode header line style is \"%s\".\n"),
4267
0
         _unicode_linestyle2string(popt->topt.unicode_header_linestyle));
4268
0
  }
4269
4270
0
  else
4271
0
  {
4272
0
    psql_error("\\pset: unknown option: %s\n", param);
4273
0
    return false;
4274
0
  }
4275
4276
0
  return true;
4277
0
}
4278
4279
4280
static const char *
4281
pset_bool_string(bool val)
4282
0
{
4283
0
  return val ? "on" : "off";
4284
0
}
4285
4286
4287
static char *
4288
pset_quoted_string(const char *str)
4289
0
{
4290
0
  char     *ret = pg_malloc(strlen(str) * 2 + 3);
4291
0
  char     *r = ret;
4292
4293
0
  *r++ = '\'';
4294
4295
0
  for (; *str; str++)
4296
0
  {
4297
0
    if (*str == '\n')
4298
0
    {
4299
0
      *r++ = '\\';
4300
0
      *r++ = 'n';
4301
0
    }
4302
0
    else if (*str == '\'')
4303
0
    {
4304
0
      *r++ = '\\';
4305
0
      *r++ = '\'';
4306
0
    }
4307
0
    else
4308
0
      *r++ = *str;
4309
0
  }
4310
4311
0
  *r++ = '\'';
4312
0
  *r = '\0';
4313
4314
0
  return ret;
4315
0
}
4316
4317
4318
/*
4319
 * Return a malloc'ed string for the \pset value.
4320
 *
4321
 * Note that for some string parameters, print.c distinguishes between unset
4322
 * and empty string, but for others it doesn't.  This function should produce
4323
 * output that produces the correct setting when fed back into \pset.
4324
 */
4325
static char *
4326
pset_value_string(const char *param, struct printQueryOpt *popt)
4327
0
{
4328
0
  Assert(param != NULL);
4329
4330
0
  if (strcmp(param, "border") == 0)
4331
0
    return psprintf("%d", popt->topt.border);
4332
0
  else if (strcmp(param, "columns") == 0)
4333
0
    return psprintf("%d", popt->topt.columns);
4334
0
  else if (strcmp(param, "expanded") == 0)
4335
0
    return pstrdup(popt->topt.expanded == 2
4336
0
             ? "auto"
4337
0
             : pset_bool_string(popt->topt.expanded));
4338
0
  else if (strcmp(param, "fieldsep") == 0)
4339
0
    return pset_quoted_string(popt->topt.fieldSep.separator
4340
0
                  ? popt->topt.fieldSep.separator
4341
0
                  : "");
4342
0
  else if (strcmp(param, "fieldsep_zero") == 0)
4343
0
    return pstrdup(pset_bool_string(popt->topt.fieldSep.separator_zero));
4344
0
  else if (strcmp(param, "footer") == 0)
4345
0
    return pstrdup(pset_bool_string(popt->topt.default_footer));
4346
0
  else if (strcmp(param, "format") == 0)
4347
0
    return psprintf("%s", _align2string(popt->topt.format));
4348
0
  else if (strcmp(param, "linestyle") == 0)
4349
0
    return psprintf("%s", get_line_style(&popt->topt)->name);
4350
0
  else if (strcmp(param, "null") == 0)
4351
0
    return pset_quoted_string(popt->nullPrint
4352
0
                  ? popt->nullPrint
4353
0
                  : "");
4354
0
  else if (strcmp(param, "numericlocale") == 0)
4355
0
    return pstrdup(pset_bool_string(popt->topt.numericLocale));
4356
0
  else if (strcmp(param, "pager") == 0)
4357
0
    return psprintf("%d", popt->topt.pager);
4358
0
  else if (strcmp(param, "pager_min_lines") == 0)
4359
0
    return psprintf("%d", popt->topt.pager_min_lines);
4360
0
  else if (strcmp(param, "recordsep") == 0)
4361
0
    return pset_quoted_string(popt->topt.recordSep.separator
4362
0
                  ? popt->topt.recordSep.separator
4363
0
                  : "");
4364
0
  else if (strcmp(param, "recordsep_zero") == 0)
4365
0
    return pstrdup(pset_bool_string(popt->topt.recordSep.separator_zero));
4366
0
  else if (strcmp(param, "tableattr") == 0)
4367
0
    return popt->topt.tableAttr ? pset_quoted_string(popt->topt.tableAttr) : pstrdup("");
4368
0
  else if (strcmp(param, "title") == 0)
4369
0
    return popt->title ? pset_quoted_string(popt->title) : pstrdup("");
4370
0
  else if (strcmp(param, "tuples_only") == 0)
4371
0
    return pstrdup(pset_bool_string(popt->topt.tuples_only));
4372
0
  else if (strcmp(param, "unicode_border_linestyle") == 0)
4373
0
    return pstrdup(_unicode_linestyle2string(popt->topt.unicode_border_linestyle));
4374
0
  else if (strcmp(param, "unicode_column_linestyle") == 0)
4375
0
    return pstrdup(_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
4376
0
  else if (strcmp(param, "unicode_header_linestyle") == 0)
4377
0
    return pstrdup(_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
4378
0
  else
4379
0
    return pstrdup("ERROR");
4380
0
}
4381
4382
4383
4384
#ifndef WIN32
4385
0
#define DEFAULT_SHELL "/bin/sh"
4386
#else
4387
/*
4388
 *  CMD.EXE is in different places in different Win32 releases so we
4389
 *  have to rely on the path to find it.
4390
 */
4391
#define DEFAULT_SHELL "cmd.exe"
4392
#endif
4393
4394
static bool
4395
do_shell(const char *command)
4396
0
{
4397
0
  int     result;
4398
4399
0
  if (!command)
4400
0
  {
4401
0
    char     *sys;
4402
0
    const char *shellName;
4403
4404
0
    shellName = getenv("SHELL");
4405
#ifdef WIN32
4406
    if (shellName == NULL)
4407
      shellName = getenv("COMSPEC");
4408
#endif
4409
0
    if (shellName == NULL)
4410
0
      shellName = DEFAULT_SHELL;
4411
4412
    /* See EDITOR handling comment for an explanation */
4413
0
#ifndef WIN32
4414
0
    sys = psprintf("exec %s", shellName);
4415
#else
4416
    sys = psprintf("\"%s\"", shellName);
4417
#endif
4418
0
    result = system(sys);
4419
0
    free(sys);
4420
0
  }
4421
0
  else
4422
0
    result = system(command);
4423
4424
0
  if (result == 127 || result == -1)
4425
0
  {
4426
0
    psql_error("\\!: failed\n");
4427
0
    return false;
4428
0
  }
4429
0
  return true;
4430
0
}
4431
4432
/*
4433
 * do_watch -- handler for \watch
4434
 *
4435
 * We break this out of exec_command to avoid having to plaster "volatile"
4436
 * onto a bunch of exec_command's variables to silence stupider compilers.
4437
 */
4438
static bool
4439
do_watch(PQExpBuffer query_buf, double sleep)
4440
0
{
4441
0
  long    sleep_ms = (long) (sleep * 1000);
4442
0
  printQueryOpt myopt = pset.popt;
4443
0
  const char *strftime_fmt;
4444
0
  const char *user_title;
4445
0
  char     *title;
4446
0
  int     title_len;
4447
0
  int     res = 0;
4448
4449
0
  if (!query_buf || query_buf->len <= 0)
4450
0
  {
4451
0
    psql_error(_("\\watch cannot be used with an empty query\n"));
4452
0
    return false;
4453
0
  }
4454
4455
  /*
4456
   * Choose format for timestamps.  We might eventually make this a \pset
4457
   * option.  In the meantime, using a variable for the format suppresses
4458
   * overly-anal-retentive gcc warnings about %c being Y2K sensitive.
4459
   */
4460
0
  strftime_fmt = "%c";
4461
4462
  /*
4463
   * Set up rendering options, in particular, disable the pager, because
4464
   * nobody wants to be prompted while watching the output of 'watch'.
4465
   */
4466
0
  myopt.topt.pager = 0;
4467
4468
  /*
4469
   * If there's a title in the user configuration, make sure we have room
4470
   * for it in the title buffer.  Allow 128 bytes for the timestamp plus 128
4471
   * bytes for the rest.
4472
   */
4473
0
  user_title = myopt.title;
4474
0
  title_len = (user_title ? strlen(user_title) : 0) + 256;
4475
0
  title = pg_malloc(title_len);
4476
4477
0
  for (;;)
4478
0
  {
4479
0
    time_t    timer;
4480
0
    char    timebuf[128];
4481
0
    long    i;
4482
4483
    /*
4484
     * Prepare title for output.  Note that we intentionally include a
4485
     * newline at the end of the title; this is somewhat historical but it
4486
     * makes for reasonably nicely formatted output in simple cases.
4487
     */
4488
0
    timer = time(NULL);
4489
0
    strftime(timebuf, sizeof(timebuf), strftime_fmt, localtime(&timer));
4490
4491
0
    if (user_title)
4492
0
      snprintf(title, title_len, _("%s\t%s (every %gs)\n"),
4493
0
           user_title, timebuf, sleep);
4494
0
    else
4495
0
      snprintf(title, title_len, _("%s (every %gs)\n"),
4496
0
           timebuf, sleep);
4497
0
    myopt.title = title;
4498
4499
    /* Run the query and print out the results */
4500
0
    res = PSQLexecWatch(query_buf->data, &myopt);
4501
4502
    /*
4503
     * PSQLexecWatch handles the case where we can no longer repeat the
4504
     * query, and returns 0 or -1.
4505
     */
4506
0
    if (res <= 0)
4507
0
      break;
4508
4509
    /*
4510
     * Set up cancellation of 'watch' via SIGINT.  We redo this each time
4511
     * through the loop since it's conceivable something inside
4512
     * PSQLexecWatch could change sigint_interrupt_jmp.
4513
     */
4514
0
    if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
4515
0
      break;
4516
4517
    /*
4518
     * Enable 'watch' cancellations and wait a while before running the
4519
     * query again.  Break the sleep into short intervals (at most 1s)
4520
     * since pg_usleep isn't interruptible on some platforms.
4521
     */
4522
0
    sigint_interrupt_enabled = true;
4523
0
    i = sleep_ms;
4524
0
    while (i > 0)
4525
0
    {
4526
0
      long    s = Min(i, 1000L);
4527
4528
0
      pg_usleep(s * 1000L);
4529
0
      if (cancel_pressed)
4530
0
        break;
4531
0
      i -= s;
4532
0
    }
4533
0
    sigint_interrupt_enabled = false;
4534
0
  }
4535
4536
0
  pg_free(title);
4537
0
  return (res >= 0);
4538
0
}
4539
4540
/*
4541
 * a little code borrowed from PSQLexec() to manage ECHO_HIDDEN output.
4542
 * returns true unless we have ECHO_HIDDEN_NOEXEC.
4543
 */
4544
static bool
4545
echo_hidden_command(const char *query)
4546
0
{
4547
0
  if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
4548
0
  {
4549
0
    printf(_("********* QUERY **********\n"
4550
0
         "%s\n"
4551
0
         "**************************\n\n"), query);
4552
0
    fflush(stdout);
4553
0
    if (pset.logfile)
4554
0
    {
4555
0
      fprintf(pset.logfile,
4556
0
          _("********* QUERY **********\n"
4557
0
            "%s\n"
4558
0
            "**************************\n\n"), query);
4559
0
      fflush(pset.logfile);
4560
0
    }
4561
4562
0
    if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
4563
0
      return false;
4564
0
  }
4565
0
  return true;
4566
0
}
4567
4568
/*
4569
 * Look up the object identified by obj_type and desc.  If successful,
4570
 * store its OID in *obj_oid and return true, else return false.
4571
 *
4572
 * Note that we'll fail if the object doesn't exist OR if there are multiple
4573
 * matching candidates OR if there's something syntactically wrong with the
4574
 * object description; unfortunately it can be hard to tell the difference.
4575
 */
4576
static bool
4577
lookup_object_oid(EditableObjectType obj_type, const char *desc,
4578
          Oid *obj_oid)
4579
0
{
4580
0
  bool    result = true;
4581
0
  PQExpBuffer query = createPQExpBuffer();
4582
0
  PGresult   *res;
4583
4584
0
  switch (obj_type)
4585
0
  {
4586
0
    case EditableFunction:
4587
4588
      /*
4589
       * We have a function description, e.g. "x" or "x(int)".  Issue a
4590
       * query to retrieve the function's OID using a cast to regproc or
4591
       * regprocedure (as appropriate).
4592
       */
4593
0
      appendPQExpBufferStr(query, "SELECT ");
4594
0
      appendStringLiteralConn(query, desc, pset.db);
4595
0
      appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
4596
0
                strchr(desc, '(') ? "regprocedure" : "regproc");
4597
0
      break;
4598
4599
0
    case EditableView:
4600
4601
      /*
4602
       * Convert view name (possibly schema-qualified) to OID.  Note:
4603
       * this code doesn't check if the relation is actually a view.
4604
       * We'll detect that in get_create_object_cmd().
4605
       */
4606
0
      appendPQExpBufferStr(query, "SELECT ");
4607
0
      appendStringLiteralConn(query, desc, pset.db);
4608
0
      appendPQExpBuffer(query, "::pg_catalog.regclass::pg_catalog.oid");
4609
0
      break;
4610
0
  }
4611
4612
0
  if (!echo_hidden_command(query->data))
4613
0
  {
4614
0
    destroyPQExpBuffer(query);
4615
0
    return false;
4616
0
  }
4617
0
  res = PQexec(pset.db, query->data);
4618
0
  if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
4619
0
    *obj_oid = atooid(PQgetvalue(res, 0, 0));
4620
0
  else
4621
0
  {
4622
0
    minimal_error_message(res);
4623
0
    result = false;
4624
0
  }
4625
4626
0
  PQclear(res);
4627
0
  destroyPQExpBuffer(query);
4628
4629
0
  return result;
4630
0
}
4631
4632
/*
4633
 * Construct a "CREATE OR REPLACE ..." command that describes the specified
4634
 * database object.  If successful, the result is stored in buf.
4635
 */
4636
static bool
4637
get_create_object_cmd(EditableObjectType obj_type, Oid oid,
4638
            PQExpBuffer buf)
4639
0
{
4640
0
  bool    result = true;
4641
0
  PQExpBuffer query = createPQExpBuffer();
4642
0
  PGresult   *res;
4643
4644
0
  switch (obj_type)
4645
0
  {
4646
0
    case EditableFunction:
4647
0
      printfPQExpBuffer(query,
4648
0
                "SELECT pg_catalog.pg_get_functiondef(%u)",
4649
0
                oid);
4650
0
      break;
4651
4652
0
    case EditableView:
4653
4654
      /*
4655
       * pg_get_viewdef() just prints the query, so we must prepend
4656
       * CREATE for ourselves.  We must fully qualify the view name to
4657
       * ensure the right view gets replaced.  Also, check relation kind
4658
       * to be sure it's a view.
4659
       *
4660
       * Starting with 9.2, views may have reloptions (security_barrier)
4661
       * and from 9.4 onwards they may also have WITH [LOCAL|CASCADED]
4662
       * CHECK OPTION.  These are not part of the view definition
4663
       * returned by pg_get_viewdef() and so need to be retrieved
4664
       * separately.  Materialized views (introduced in 9.3) may have
4665
       * arbitrary storage parameter reloptions.
4666
       */
4667
0
      if (pset.sversion >= 90400)
4668
0
      {
4669
0
        printfPQExpBuffer(query,
4670
0
                  "SELECT nspname, relname, relkind, "
4671
0
                  "pg_catalog.pg_get_viewdef(c.oid, true), "
4672
0
                  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
4673
0
                  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4674
0
                  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption "
4675
0
                  "FROM pg_catalog.pg_class c "
4676
0
                  "LEFT JOIN pg_catalog.pg_namespace n "
4677
0
                  "ON c.relnamespace = n.oid WHERE c.oid = %u",
4678
0
                  oid);
4679
0
      }
4680
0
      else if (pset.sversion >= 90200)
4681
0
      {
4682
0
        printfPQExpBuffer(query,
4683
0
                  "SELECT nspname, relname, relkind, "
4684
0
                  "pg_catalog.pg_get_viewdef(c.oid, true), "
4685
0
                  "c.reloptions AS reloptions, "
4686
0
                  "NULL AS checkoption "
4687
0
                  "FROM pg_catalog.pg_class c "
4688
0
                  "LEFT JOIN pg_catalog.pg_namespace n "
4689
0
                  "ON c.relnamespace = n.oid WHERE c.oid = %u",
4690
0
                  oid);
4691
0
      }
4692
0
      else
4693
0
      {
4694
0
        printfPQExpBuffer(query,
4695
0
                  "SELECT nspname, relname, relkind, "
4696
0
                  "pg_catalog.pg_get_viewdef(c.oid, true), "
4697
0
                  "NULL AS reloptions, "
4698
0
                  "NULL AS checkoption "
4699
0
                  "FROM pg_catalog.pg_class c "
4700
0
                  "LEFT JOIN pg_catalog.pg_namespace n "
4701
0
                  "ON c.relnamespace = n.oid WHERE c.oid = %u",
4702
0
                  oid);
4703
0
      }
4704
0
      break;
4705
0
  }
4706
4707
0
  if (!echo_hidden_command(query->data))
4708
0
  {
4709
0
    destroyPQExpBuffer(query);
4710
0
    return false;
4711
0
  }
4712
0
  res = PQexec(pset.db, query->data);
4713
0
  if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
4714
0
  {
4715
0
    resetPQExpBuffer(buf);
4716
0
    switch (obj_type)
4717
0
    {
4718
0
      case EditableFunction:
4719
0
        appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
4720
0
        break;
4721
4722
0
      case EditableView:
4723
0
        {
4724
0
          char     *nspname = PQgetvalue(res, 0, 0);
4725
0
          char     *relname = PQgetvalue(res, 0, 1);
4726
0
          char     *relkind = PQgetvalue(res, 0, 2);
4727
0
          char     *viewdef = PQgetvalue(res, 0, 3);
4728
0
          char     *reloptions = PQgetvalue(res, 0, 4);
4729
0
          char     *checkoption = PQgetvalue(res, 0, 5);
4730
4731
          /*
4732
           * If the backend ever supports CREATE OR REPLACE
4733
           * MATERIALIZED VIEW, allow that here; but as of today it
4734
           * does not, so editing a matview definition in this way
4735
           * is impossible.
4736
           */
4737
0
          switch (relkind[0])
4738
0
          {
4739
#ifdef NOT_USED
4740
            case RELKIND_MATVIEW:
4741
              appendPQExpBufferStr(buf, "CREATE OR REPLACE MATERIALIZED VIEW ");
4742
              break;
4743
#endif
4744
0
            case RELKIND_VIEW:
4745
0
              appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
4746
0
              break;
4747
0
            default:
4748
0
              psql_error("\"%s.%s\" is not a view\n",
4749
0
                     nspname, relname);
4750
0
              result = false;
4751
0
              break;
4752
0
          }
4753
0
          appendPQExpBuffer(buf, "%s.", fmtId(nspname));
4754
0
          appendPQExpBufferStr(buf, fmtId(relname));
4755
4756
          /* reloptions, if not an empty array "{}" */
4757
0
          if (reloptions != NULL && strlen(reloptions) > 2)
4758
0
          {
4759
0
            appendPQExpBufferStr(buf, "\n WITH (");
4760
0
            if (!appendReloptionsArray(buf, reloptions, "",
4761
0
                           pset.encoding,
4762
0
                           standard_strings()))
4763
0
            {
4764
0
              psql_error("could not parse reloptions array\n");
4765
0
              result = false;
4766
0
            }
4767
0
            appendPQExpBufferChar(buf, ')');
4768
0
          }
4769
4770
          /* View definition from pg_get_viewdef (a SELECT query) */
4771
0
          appendPQExpBuffer(buf, " AS\n%s", viewdef);
4772
4773
          /* Get rid of the semicolon that pg_get_viewdef appends */
4774
0
          if (buf->len > 0 && buf->data[buf->len - 1] == ';')
4775
0
            buf->data[--(buf->len)] = '\0';
4776
4777
          /* WITH [LOCAL|CASCADED] CHECK OPTION */
4778
0
          if (checkoption && checkoption[0] != '\0')
4779
0
            appendPQExpBuffer(buf, "\n WITH %s CHECK OPTION",
4780
0
                      checkoption);
4781
0
        }
4782
0
        break;
4783
0
    }
4784
    /* Make sure result ends with a newline */
4785
0
    if (buf->len > 0 && buf->data[buf->len - 1] != '\n')
4786
0
      appendPQExpBufferChar(buf, '\n');
4787
0
  }
4788
0
  else
4789
0
  {
4790
0
    minimal_error_message(res);
4791
0
    result = false;
4792
0
  }
4793
4794
0
  PQclear(res);
4795
0
  destroyPQExpBuffer(query);
4796
4797
0
  return result;
4798
0
}
4799
4800
/*
4801
 * If the given argument of \ef or \ev ends with a line number, delete the line
4802
 * number from the argument string and return it as an integer.  (We need
4803
 * this kluge because we're too lazy to parse \ef's function or \ev's view
4804
 * argument carefully --- we just slop it up in OT_WHOLE_LINE mode.)
4805
 *
4806
 * Returns -1 if no line number is present, 0 on error, or a positive value
4807
 * on success.
4808
 */
4809
static int
4810
strip_lineno_from_objdesc(char *obj)
4811
0
{
4812
0
  char     *c;
4813
0
  int     lineno;
4814
4815
0
  if (!obj || obj[0] == '\0')
4816
0
    return -1;
4817
4818
0
  c = obj + strlen(obj) - 1;
4819
4820
  /*
4821
   * This business of parsing backwards is dangerous as can be in a
4822
   * multibyte environment: there is no reason to believe that we are
4823
   * looking at the first byte of a character, nor are we necessarily
4824
   * working in a "safe" encoding.  Fortunately the bitpatterns we are
4825
   * looking for are unlikely to occur as non-first bytes, but beware of
4826
   * trying to expand the set of cases that can be recognized.  We must
4827
   * guard the <ctype.h> macros by using isascii() first, too.
4828
   */
4829
4830
  /* skip trailing whitespace */
4831
0
  while (c > obj && isascii((unsigned char) *c) && isspace((unsigned char) *c))
4832
0
    c--;
4833
4834
  /* must have a digit as last non-space char */
4835
0
  if (c == obj || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
4836
0
    return -1;
4837
4838
  /* find start of digit string */
4839
0
  while (c > obj && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
4840
0
    c--;
4841
4842
  /* digits must be separated from object name by space or closing paren */
4843
  /* notice also that we are not allowing an empty object name ... */
4844
0
  if (c == obj || !isascii((unsigned char) *c) ||
4845
0
    !(isspace((unsigned char) *c) || *c == ')'))
4846
0
    return -1;
4847
4848
  /* parse digit string */
4849
0
  c++;
4850
0
  lineno = atoi(c);
4851
0
  if (lineno < 1)
4852
0
  {
4853
0
    psql_error("invalid line number: %s\n", c);
4854
0
    return 0;
4855
0
  }
4856
4857
  /* strip digit string from object name */
4858
0
  *c = '\0';
4859
4860
0
  return lineno;
4861
0
}
4862
4863
/*
4864
 * Count number of lines in the buffer.
4865
 * This is used to test if pager is needed or not.
4866
 */
4867
static int
4868
count_lines_in_buf(PQExpBuffer buf)
4869
0
{
4870
0
  int     lineno = 0;
4871
0
  const char *lines = buf->data;
4872
4873
0
  while (*lines != '\0')
4874
0
  {
4875
0
    lineno++;
4876
    /* find start of next line */
4877
0
    lines = strchr(lines, '\n');
4878
0
    if (!lines)
4879
0
      break;
4880
0
    lines++;
4881
0
  }
4882
4883
0
  return lineno;
4884
0
}
4885
4886
/*
4887
 * Write text at *lines to output with line numbers.
4888
 *
4889
 * If header_keyword isn't NULL, then line 1 should be the first line beginning
4890
 * with header_keyword; lines before that are unnumbered.
4891
 *
4892
 * Caution: this scribbles on *lines.
4893
 */
4894
static void
4895
print_with_linenumbers(FILE *output, char *lines,
4896
             const char *header_keyword)
4897
0
{
4898
0
  bool    in_header = (header_keyword != NULL);
4899
0
  size_t    header_sz = in_header ? strlen(header_keyword) : 0;
4900
0
  int     lineno = 0;
4901
4902
0
  while (*lines != '\0')
4903
0
  {
4904
0
    char     *eol;
4905
4906
0
    if (in_header && strncmp(lines, header_keyword, header_sz) == 0)
4907
0
      in_header = false;
4908
4909
    /* increment lineno only for body's lines */
4910
0
    if (!in_header)
4911
0
      lineno++;
4912
4913
    /* find and mark end of current line */
4914
0
    eol = strchr(lines, '\n');
4915
0
    if (eol != NULL)
4916
0
      *eol = '\0';
4917
4918
    /* show current line as appropriate */
4919
0
    if (in_header)
4920
0
      fprintf(output, "        %s\n", lines);
4921
0
    else
4922
0
      fprintf(output, "%-7d %s\n", lineno, lines);
4923
4924
    /* advance to next line, if any */
4925
0
    if (eol == NULL)
4926
0
      break;
4927
0
    lines = ++eol;
4928
0
  }
4929
0
}
4930
4931
/*
4932
 * Report just the primary error; this is to avoid cluttering the output
4933
 * with, for instance, a redisplay of the internally generated query
4934
 */
4935
static void
4936
minimal_error_message(PGresult *res)
4937
0
{
4938
0
  PQExpBuffer msg;
4939
0
  const char *fld;
4940
4941
0
  msg = createPQExpBuffer();
4942
4943
0
  fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
4944
0
  if (fld)
4945
0
    printfPQExpBuffer(msg, "%s:  ", fld);
4946
0
  else
4947
0
    printfPQExpBuffer(msg, "ERROR:  ");
4948
0
  fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
4949
0
  if (fld)
4950
0
    appendPQExpBufferStr(msg, fld);
4951
0
  else
4952
0
    appendPQExpBufferStr(msg, "(not available)");
4953
0
  appendPQExpBufferChar(msg, '\n');
4954
4955
0
  psql_error("%s", msg->data);
4956
4957
0
  destroyPQExpBuffer(msg);
4958
0
}