~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/bin/psql/command.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * psql - the PostgreSQL interactive terminal
 
3
 *
 
4
 * Copyright (c) 2000-2011, PostgreSQL Global Development Group
 
5
 *
 
6
 * src/bin/psql/command.c
 
7
 */
 
8
#include "postgres_fe.h"
 
9
#include "command.h"
 
10
 
 
11
#ifdef __BORLANDC__                             /* needed for BCC */
 
12
#undef mkdir
 
13
#endif
 
14
 
 
15
#include <ctype.h>
 
16
#ifdef HAVE_PWD_H
 
17
#include <pwd.h>
 
18
#endif
 
19
#ifndef WIN32
 
20
#include <sys/types.h>                  /* for umask() */
 
21
#include <sys/stat.h>                   /* for stat() */
 
22
#include <fcntl.h>                              /* open() flags */
 
23
#include <unistd.h>                             /* for geteuid(), getpid(), stat() */
 
24
#else
 
25
#include <win32.h>
 
26
#include <io.h>
 
27
#include <fcntl.h>
 
28
#include <direct.h>
 
29
#include <sys/types.h>                  /* for umask() */
 
30
#include <sys/stat.h>                   /* for stat() */
 
31
#endif
 
32
#ifdef USE_SSL
 
33
#include <openssl/ssl.h>
 
34
#endif
 
35
 
 
36
#include "portability/instr_time.h"
 
37
 
 
38
#include "libpq-fe.h"
 
39
#include "pqexpbuffer.h"
 
40
#include "dumputils.h"
 
41
 
 
42
#include "common.h"
 
43
#include "copy.h"
 
44
#include "describe.h"
 
45
#include "help.h"
 
46
#include "input.h"
 
47
#include "large_obj.h"
 
48
#include "mainloop.h"
 
49
#include "print.h"
 
50
#include "psqlscan.h"
 
51
#include "settings.h"
 
52
#include "variables.h"
 
53
 
 
54
 
 
55
/* functions for use in this file */
 
56
static backslashResult exec_command(const char *cmd,
 
57
                         PsqlScanState scan_state,
 
58
                         PQExpBuffer query_buf);
 
59
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
60
                int lineno, bool *edited);
 
61
static bool do_connect(char *dbname, char *user, char *host, char *port);
 
62
static bool do_shell(const char *command);
 
63
static bool lookup_function_oid(PGconn *conn, const char *desc, Oid *foid);
 
64
static bool get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf);
 
65
static int      strip_lineno_from_funcdesc(char *func);
 
66
static void minimal_error_message(PGresult *res);
 
67
 
 
68
static void printSSLInfo(void);
 
69
 
 
70
#ifdef WIN32
 
71
static void checkWin32Codepage(void);
 
72
#endif
 
73
 
 
74
 
 
75
 
 
76
/*----------
 
77
 * HandleSlashCmds:
 
78
 *
 
79
 * Handles all the different commands that start with '\'.
 
80
 * Ordinarily called by MainLoop().
 
81
 *
 
82
 * scan_state is a lexer working state that is set to continue scanning
 
83
 * just after the '\'.  The lexer is advanced past the command and all
 
84
 * arguments on return.
 
85
 *
 
86
 * 'query_buf' contains the query-so-far, which may be modified by
 
87
 * execution of the backslash command (for example, \r clears it).
 
88
 * query_buf can be NULL if there is no query so far.
 
89
 *
 
90
 * Returns a status code indicating what action is desired, see command.h.
 
91
 *----------
 
92
 */
 
93
 
 
94
backslashResult
 
95
HandleSlashCmds(PsqlScanState scan_state,
 
96
                                PQExpBuffer query_buf)
 
97
{
 
98
        backslashResult status = PSQL_CMD_SKIP_LINE;
 
99
        char       *cmd;
 
100
        char       *arg;
 
101
 
 
102
        psql_assert(scan_state);
 
103
 
 
104
        /* Parse off the command name */
 
105
        cmd = psql_scan_slash_command(scan_state);
 
106
 
 
107
        /* And try to execute it */
 
108
        status = exec_command(cmd, scan_state, query_buf);
 
109
 
 
110
        if (status == PSQL_CMD_UNKNOWN)
 
111
        {
 
112
                if (pset.cur_cmd_interactive)
 
113
                        fprintf(stderr, _("Invalid command \\%s. Try \\? for help.\n"), cmd);
 
114
                else
 
115
                        psql_error("invalid command \\%s\n", cmd);
 
116
                status = PSQL_CMD_ERROR;
 
117
        }
 
118
 
 
119
        if (status != PSQL_CMD_ERROR)
 
120
        {
 
121
                /* eat any remaining arguments after a valid command */
 
122
                /* note we suppress evaluation of backticks here */
 
123
                while ((arg = psql_scan_slash_option(scan_state,
 
124
                                                                                         OT_VERBATIM, NULL, false)))
 
125
                {
 
126
                        psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
 
127
                        free(arg);
 
128
                }
 
129
        }
 
130
        else
 
131
        {
 
132
                /* silently throw away rest of line after an erroneous command */
 
133
                while ((arg = psql_scan_slash_option(scan_state,
 
134
                                                                                         OT_WHOLE_LINE, NULL, false)))
 
135
                        free(arg);
 
136
        }
 
137
 
 
138
        /* if there is a trailing \\, swallow it */
 
139
        psql_scan_slash_command_end(scan_state);
 
140
 
 
141
        free(cmd);
 
142
 
 
143
        /* some commands write to queryFout, so make sure output is sent */
 
144
        fflush(pset.queryFout);
 
145
 
 
146
        return status;
 
147
}
 
148
 
 
149
/*
 
150
 * Read and interpret an argument to the \connect slash command.
 
151
 */
 
152
static char *
 
153
read_connect_arg(PsqlScanState scan_state)
 
154
{
 
155
        char       *result;
 
156
        char            quote;
 
157
 
 
158
        /*
 
159
         * Ideally we should treat the arguments as SQL identifiers.  But for
 
160
         * backwards compatibility with 7.2 and older pg_dump files, we have to
 
161
         * take unquoted arguments verbatim (don't downcase them). For now,
 
162
         * double-quoted arguments may be stripped of double quotes (as if SQL
 
163
         * identifiers).  By 7.4 or so, pg_dump files can be expected to
 
164
         * double-quote all mixed-case \connect arguments, and then we can get rid
 
165
         * of OT_SQLIDHACK.
 
166
         */
 
167
        result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, &quote, true);
 
168
 
 
169
        if (!result)
 
170
                return NULL;
 
171
 
 
172
        if (quote)
 
173
                return result;
 
174
 
 
175
        if (*result == '\0' || strcmp(result, "-") == 0)
 
176
                return NULL;
 
177
 
 
178
        return result;
 
179
}
 
180
 
 
181
 
 
182
/*
 
183
 * Subroutine to actually try to execute a backslash command.
 
184
 */
 
185
static backslashResult
 
186
exec_command(const char *cmd,
 
187
                         PsqlScanState scan_state,
 
188
                         PQExpBuffer query_buf)
 
189
{
 
190
        bool            success = true; /* indicate here if the command ran ok or
 
191
                                                                 * failed */
 
192
        backslashResult status = PSQL_CMD_SKIP_LINE;
 
193
 
 
194
        /*
 
195
         * \a -- toggle field alignment This makes little sense but we keep it
 
196
         * around.
 
197
         */
 
198
        if (strcmp(cmd, "a") == 0)
 
199
        {
 
200
                if (pset.popt.topt.format != PRINT_ALIGNED)
 
201
                        success = do_pset("format", "aligned", &pset.popt, pset.quiet);
 
202
                else
 
203
                        success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
 
204
        }
 
205
 
 
206
        /* \C -- override table title (formerly change HTML caption) */
 
207
        else if (strcmp(cmd, "C") == 0)
 
208
        {
 
209
                char       *opt = psql_scan_slash_option(scan_state,
 
210
                                                                                                 OT_NORMAL, NULL, true);
 
211
 
 
212
                success = do_pset("title", opt, &pset.popt, pset.quiet);
 
213
                free(opt);
 
214
        }
 
215
 
 
216
        /*
 
217
         * \c or \connect -- connect to database using the specified parameters.
 
218
         *
 
219
         * \c dbname user host port
 
220
         *
 
221
         * If any of these parameters are omitted or specified as '-', the current
 
222
         * value of the parameter will be used instead. If the parameter has no
 
223
         * current value, the default value for that parameter will be used. Some
 
224
         * examples:
 
225
         *
 
226
         * \c - - hst           Connect to current database on current port of host
 
227
         * "hst" as current user. \c - usr - prt   Connect to current database on
 
228
         * "prt" port of current host as user "usr". \c dbs                       Connect to
 
229
         * "dbs" database on current port of current host as current user.
 
230
         */
 
231
        else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
 
232
        {
 
233
                char       *opt1,
 
234
                                   *opt2,
 
235
                                   *opt3,
 
236
                                   *opt4;
 
237
 
 
238
                opt1 = read_connect_arg(scan_state);
 
239
                opt2 = read_connect_arg(scan_state);
 
240
                opt3 = read_connect_arg(scan_state);
 
241
                opt4 = read_connect_arg(scan_state);
 
242
 
 
243
                success = do_connect(opt1, opt2, opt3, opt4);
 
244
 
 
245
                free(opt1);
 
246
                free(opt2);
 
247
                free(opt3);
 
248
                free(opt4);
 
249
        }
 
250
 
 
251
        /* \cd */
 
252
        else if (strcmp(cmd, "cd") == 0)
 
253
        {
 
254
                char       *opt = psql_scan_slash_option(scan_state,
 
255
                                                                                                 OT_NORMAL, NULL, true);
 
256
                char       *dir;
 
257
 
 
258
                if (opt)
 
259
                        dir = opt;
 
260
                else
 
261
                {
 
262
#ifndef WIN32
 
263
                        struct passwd *pw;
 
264
 
 
265
                        pw = getpwuid(geteuid());
 
266
                        if (!pw)
 
267
                        {
 
268
                                psql_error("could not get home directory: %s\n", strerror(errno));
 
269
                                exit(EXIT_FAILURE);
 
270
                        }
 
271
                        dir = pw->pw_dir;
 
272
#else                                                   /* WIN32 */
 
273
 
 
274
                        /*
 
275
                         * On Windows, 'cd' without arguments prints the current
 
276
                         * directory, so if someone wants to code this here instead...
 
277
                         */
 
278
                        dir = "/";
 
279
#endif   /* WIN32 */
 
280
                }
 
281
 
 
282
                if (chdir(dir) == -1)
 
283
                {
 
284
                        psql_error("\\%s: could not change directory to \"%s\": %s\n",
 
285
                                           cmd, dir, strerror(errno));
 
286
                        success = false;
 
287
                }
 
288
 
 
289
                if (pset.dirname)
 
290
                        free(pset.dirname);
 
291
                pset.dirname = pg_strdup(dir);
 
292
                canonicalize_path(pset.dirname);
 
293
 
 
294
                if (opt)
 
295
                        free(opt);
 
296
        }
 
297
 
 
298
        /* \conninfo -- display information about the current connection */
 
299
        else if (strcmp(cmd, "conninfo") == 0)
 
300
        {
 
301
                char       *db = PQdb(pset.db);
 
302
                char       *host = PQhost(pset.db);
 
303
 
 
304
                if (db == NULL)
 
305
                        printf(_("You are not connected.\n"));
 
306
                else
 
307
                {
 
308
                        if (host == NULL)
 
309
                                host = DEFAULT_PGSOCKET_DIR;
 
310
                        /* If the host is an absolute path, the connection is via socket */
 
311
                        if (is_absolute_path(host))
 
312
                                printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
 
313
                                           db, PQuser(pset.db), host, PQport(pset.db));
 
314
                        else
 
315
                                printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
 
316
                                           db, PQuser(pset.db), host, PQport(pset.db));
 
317
                }
 
318
        }
 
319
 
 
320
        /* \copy */
 
321
        else if (pg_strcasecmp(cmd, "copy") == 0)
 
322
        {
 
323
                /* Default fetch-it-all-and-print mode */
 
324
                instr_time      before,
 
325
                                        after;
 
326
 
 
327
                char       *opt = psql_scan_slash_option(scan_state,
 
328
                                                                                                 OT_WHOLE_LINE, NULL, false);
 
329
 
 
330
                if (pset.timing)
 
331
                        INSTR_TIME_SET_CURRENT(before);
 
332
 
 
333
                success = do_copy(opt);
 
334
 
 
335
                if (pset.timing && success)
 
336
                {
 
337
                        INSTR_TIME_SET_CURRENT(after);
 
338
                        INSTR_TIME_SUBTRACT(after, before);
 
339
                        printf(_("Time: %.3f ms\n"), INSTR_TIME_GET_MILLISEC(after));
 
340
                }
 
341
 
 
342
                free(opt);
 
343
        }
 
344
 
 
345
        /* \copyright */
 
346
        else if (strcmp(cmd, "copyright") == 0)
 
347
                print_copyright();
 
348
 
 
349
        /* \d* commands */
 
350
        else if (cmd[0] == 'd')
 
351
        {
 
352
                char       *pattern;
 
353
                bool            show_verbose,
 
354
                                        show_system;
 
355
 
 
356
                /* We don't do SQLID reduction on the pattern yet */
 
357
                pattern = psql_scan_slash_option(scan_state,
 
358
                                                                                 OT_NORMAL, NULL, true);
 
359
 
 
360
                show_verbose = strchr(cmd, '+') ? true : false;
 
361
                show_system = strchr(cmd, 'S') ? true : false;
 
362
 
 
363
                switch (cmd[1])
 
364
                {
 
365
                        case '\0':
 
366
                        case '+':
 
367
                        case 'S':
 
368
                                if (pattern)
 
369
                                        success = describeTableDetails(pattern, show_verbose, show_system);
 
370
                                else
 
371
                                        /* standard listing of interesting things */
 
372
                                        success = listTables("tvsE", NULL, show_verbose, show_system);
 
373
                                break;
 
374
                        case 'a':
 
375
                                success = describeAggregates(pattern, show_verbose, show_system);
 
376
                                break;
 
377
                        case 'b':
 
378
                                success = describeTablespaces(pattern, show_verbose);
 
379
                                break;
 
380
                        case 'c':
 
381
                                success = listConversions(pattern, show_system);
 
382
                                break;
 
383
                        case 'C':
 
384
                                success = listCasts(pattern);
 
385
                                break;
 
386
                        case 'd':
 
387
                                if (strncmp(cmd, "ddp", 3) == 0)
 
388
                                        success = listDefaultACLs(pattern);
 
389
                                else
 
390
                                        success = objectDescription(pattern, show_system);
 
391
                                break;
 
392
                        case 'D':
 
393
                                success = listDomains(pattern, show_system);
 
394
                                break;
 
395
                        case 'f':                       /* function subsystem */
 
396
                                switch (cmd[2])
 
397
                                {
 
398
                                        case '\0':
 
399
                                        case '+':
 
400
                                        case 'S':
 
401
                                        case 'a':
 
402
                                        case 'n':
 
403
                                        case 't':
 
404
                                        case 'w':
 
405
                                                success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
 
406
                                                break;
 
407
                                        default:
 
408
                                                status = PSQL_CMD_UNKNOWN;
 
409
                                                break;
 
410
                                }
 
411
                                break;
 
412
                        case 'g':
 
413
                                /* no longer distinct from \du */
 
414
                                success = describeRoles(pattern, show_verbose);
 
415
                                break;
 
416
                        case 'l':
 
417
                                success = do_lo_list();
 
418
                                break;
 
419
                        case 'L':
 
420
                                success = listLanguages(pattern, show_verbose, show_system);
 
421
                                break;
 
422
                        case 'n':
 
423
                                success = listSchemas(pattern, show_verbose, show_system);
 
424
                                break;
 
425
                        case 'o':
 
426
                                success = describeOperators(pattern, show_system);
 
427
                                break;
 
428
                        case 'O':
 
429
                                success = listCollations(pattern, show_verbose, show_system);
 
430
                                break;
 
431
                        case 'p':
 
432
                                success = permissionsList(pattern);
 
433
                                break;
 
434
                        case 'T':
 
435
                                success = describeTypes(pattern, show_verbose, show_system);
 
436
                                break;
 
437
                        case 't':
 
438
                        case 'v':
 
439
                        case 'i':
 
440
                        case 's':
 
441
                        case 'E':
 
442
                                success = listTables(&cmd[1], pattern, show_verbose, show_system);
 
443
                                break;
 
444
                        case 'r':
 
445
                                if (cmd[2] == 'd' && cmd[3] == 's')
 
446
                                {
 
447
                                        char       *pattern2 = NULL;
 
448
 
 
449
                                        if (pattern)
 
450
                                                pattern2 = psql_scan_slash_option(scan_state,
 
451
                                                                                                          OT_NORMAL, NULL, true);
 
452
                                        success = listDbRoleSettings(pattern, pattern2);
 
453
                                }
 
454
                                else
 
455
                                        success = PSQL_CMD_UNKNOWN;
 
456
                                break;
 
457
                        case 'u':
 
458
                                success = describeRoles(pattern, show_verbose);
 
459
                                break;
 
460
                        case 'F':                       /* text search subsystem */
 
461
                                switch (cmd[2])
 
462
                                {
 
463
                                        case '\0':
 
464
                                        case '+':
 
465
                                                success = listTSConfigs(pattern, show_verbose);
 
466
                                                break;
 
467
                                        case 'p':
 
468
                                                success = listTSParsers(pattern, show_verbose);
 
469
                                                break;
 
470
                                        case 'd':
 
471
                                                success = listTSDictionaries(pattern, show_verbose);
 
472
                                                break;
 
473
                                        case 't':
 
474
                                                success = listTSTemplates(pattern, show_verbose);
 
475
                                                break;
 
476
                                        default:
 
477
                                                status = PSQL_CMD_UNKNOWN;
 
478
                                                break;
 
479
                                }
 
480
                                break;
 
481
                        case 'e':                       /* SQL/MED subsystem */
 
482
                                switch (cmd[2])
 
483
                                {
 
484
                                        case 's':
 
485
                                                success = listForeignServers(pattern, show_verbose);
 
486
                                                break;
 
487
                                        case 'u':
 
488
                                                success = listUserMappings(pattern, show_verbose);
 
489
                                                break;
 
490
                                        case 'w':
 
491
                                                success = listForeignDataWrappers(pattern, show_verbose);
 
492
                                                break;
 
493
                                        case 't':
 
494
                                                success = listForeignTables(pattern, show_verbose);
 
495
                                                break;
 
496
                                        default:
 
497
                                                status = PSQL_CMD_UNKNOWN;
 
498
                                                break;
 
499
                                }
 
500
                                break;
 
501
                        case 'x':                       /* Extensions */
 
502
                                if (show_verbose)
 
503
                                        success = listExtensionContents(pattern);
 
504
                                else
 
505
                                        success = listExtensions(pattern);
 
506
                                break;
 
507
                        default:
 
508
                                status = PSQL_CMD_UNKNOWN;
 
509
                }
 
510
 
 
511
                if (pattern)
 
512
                        free(pattern);
 
513
        }
 
514
 
 
515
 
 
516
        /*
 
517
         * \e or \edit -- edit the current query buffer, or edit a file and make
 
518
         * it the query buffer
 
519
         */
 
520
        else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
 
521
        {
 
522
                if (!query_buf)
 
523
                {
 
524
                        psql_error("no query buffer\n");
 
525
                        status = PSQL_CMD_ERROR;
 
526
                }
 
527
                else
 
528
                {
 
529
                        char       *fname;
 
530
                        char       *ln = NULL;
 
531
                        int                     lineno = -1;
 
532
 
 
533
                        fname = psql_scan_slash_option(scan_state,
 
534
                                                                                   OT_NORMAL, NULL, true);
 
535
                        if (fname)
 
536
                        {
 
537
                                /* try to get separate lineno arg */
 
538
                                ln = psql_scan_slash_option(scan_state,
 
539
                                                                                        OT_NORMAL, NULL, true);
 
540
                                if (ln == NULL)
 
541
                                {
 
542
                                        /* only one arg; maybe it is lineno not fname */
 
543
                                        if (fname[0] &&
 
544
                                                strspn(fname, "0123456789") == strlen(fname))
 
545
                                        {
 
546
                                                /* all digits, so assume it is lineno */
 
547
                                                ln = fname;
 
548
                                                fname = NULL;
 
549
                                        }
 
550
                                }
 
551
                        }
 
552
                        if (ln)
 
553
                        {
 
554
                                lineno = atoi(ln);
 
555
                                if (lineno < 1)
 
556
                                {
 
557
                                        psql_error("invalid line number: %s\n", ln);
 
558
                                        status = PSQL_CMD_ERROR;
 
559
                                }
 
560
                        }
 
561
                        if (status != PSQL_CMD_ERROR)
 
562
                        {
 
563
                                expand_tilde(&fname);
 
564
                                if (fname)
 
565
                                        canonicalize_path(fname);
 
566
                                if (do_edit(fname, query_buf, lineno, NULL))
 
567
                                        status = PSQL_CMD_NEWEDIT;
 
568
                                else
 
569
                                        status = PSQL_CMD_ERROR;
 
570
                        }
 
571
                        if (fname)
 
572
                                free(fname);
 
573
                        if (ln)
 
574
                                free(ln);
 
575
                }
 
576
        }
 
577
 
 
578
        /*
 
579
         * \ef -- edit the named function, or present a blank CREATE FUNCTION
 
580
         * template if no argument is given
 
581
         */
 
582
        else if (strcmp(cmd, "ef") == 0)
 
583
        {
 
584
                int                     lineno = -1;
 
585
 
 
586
                if (!query_buf)
 
587
                {
 
588
                        psql_error("no query buffer\n");
 
589
                        status = PSQL_CMD_ERROR;
 
590
                }
 
591
                else
 
592
                {
 
593
                        char       *func;
 
594
                        Oid                     foid = InvalidOid;
 
595
 
 
596
                        func = psql_scan_slash_option(scan_state,
 
597
                                                                                  OT_WHOLE_LINE, NULL, true);
 
598
                        lineno = strip_lineno_from_funcdesc(func);
 
599
                        if (lineno == 0)
 
600
                        {
 
601
                                /* error already reported */
 
602
                                status = PSQL_CMD_ERROR;
 
603
                        }
 
604
                        else if (!func)
 
605
                        {
 
606
                                /* set up an empty command to fill in */
 
607
                                printfPQExpBuffer(query_buf,
 
608
                                                                  "CREATE FUNCTION ( )\n"
 
609
                                                                  " RETURNS \n"
 
610
                                                                  " LANGUAGE \n"
 
611
                                                                  " -- common options:  IMMUTABLE  STABLE  STRICT  SECURITY DEFINER\n"
 
612
                                                                  "AS $function$\n"
 
613
                                                                  "\n$function$\n");
 
614
                        }
 
615
                        else if (!lookup_function_oid(pset.db, func, &foid))
 
616
                        {
 
617
                                /* error already reported */
 
618
                                status = PSQL_CMD_ERROR;
 
619
                        }
 
620
                        else if (!get_create_function_cmd(pset.db, foid, query_buf))
 
621
                        {
 
622
                                /* error already reported */
 
623
                                status = PSQL_CMD_ERROR;
 
624
                        }
 
625
                        else if (lineno > 0)
 
626
                        {
 
627
                                /*
 
628
                                 * lineno "1" should correspond to the first line of the
 
629
                                 * function body.  We expect that pg_get_functiondef() will
 
630
                                 * emit that on a line beginning with "AS ", and that there
 
631
                                 * can be no such line before the real start of the function
 
632
                                 * body.  Increment lineno by the number of lines before that
 
633
                                 * line, so that it becomes relative to the first line of the
 
634
                                 * function definition.
 
635
                                 */
 
636
                                const char *lines = query_buf->data;
 
637
 
 
638
                                while (*lines != '\0')
 
639
                                {
 
640
                                        if (strncmp(lines, "AS ", 3) == 0)
 
641
                                                break;
 
642
                                        lineno++;
 
643
                                        /* find start of next line */
 
644
                                        lines = strchr(lines, '\n');
 
645
                                        if (!lines)
 
646
                                                break;
 
647
                                        lines++;
 
648
                                }
 
649
                        }
 
650
 
 
651
                        if (func)
 
652
                                free(func);
 
653
                }
 
654
 
 
655
                if (status != PSQL_CMD_ERROR)
 
656
                {
 
657
                        bool            edited = false;
 
658
 
 
659
                        if (!do_edit(NULL, query_buf, lineno, &edited))
 
660
                                status = PSQL_CMD_ERROR;
 
661
                        else if (!edited)
 
662
                                puts(_("No changes"));
 
663
                        else
 
664
                                status = PSQL_CMD_NEWEDIT;
 
665
                }
 
666
        }
 
667
 
 
668
        /* \echo and \qecho */
 
669
        else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
 
670
        {
 
671
                char       *value;
 
672
                char            quoted;
 
673
                bool            no_newline = false;
 
674
                bool            first = true;
 
675
                FILE       *fout;
 
676
 
 
677
                if (strcmp(cmd, "qecho") == 0)
 
678
                        fout = pset.queryFout;
 
679
                else
 
680
                        fout = stdout;
 
681
 
 
682
                while ((value = psql_scan_slash_option(scan_state,
 
683
                                                                                           OT_NORMAL, &quoted, false)))
 
684
                {
 
685
                        if (!quoted && strcmp(value, "-n") == 0)
 
686
                                no_newline = true;
 
687
                        else
 
688
                        {
 
689
                                if (first)
 
690
                                        first = false;
 
691
                                else
 
692
                                        fputc(' ', fout);
 
693
                                fputs(value, fout);
 
694
                        }
 
695
                        free(value);
 
696
                }
 
697
                if (!no_newline)
 
698
                        fputs("\n", fout);
 
699
        }
 
700
 
 
701
        /* \encoding -- set/show client side encoding */
 
702
        else if (strcmp(cmd, "encoding") == 0)
 
703
        {
 
704
                char       *encoding = psql_scan_slash_option(scan_state,
 
705
                                                                                                          OT_NORMAL, NULL, false);
 
706
 
 
707
                if (!encoding)
 
708
                {
 
709
                        /* show encoding */
 
710
                        puts(pg_encoding_to_char(pset.encoding));
 
711
                }
 
712
                else
 
713
                {
 
714
                        /* set encoding */
 
715
                        if (PQsetClientEncoding(pset.db, encoding) == -1)
 
716
                                psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
 
717
                        else
 
718
                        {
 
719
                                /* save encoding info into psql internal data */
 
720
                                pset.encoding = PQclientEncoding(pset.db);
 
721
                                pset.popt.topt.encoding = pset.encoding;
 
722
                                SetVariable(pset.vars, "ENCODING",
 
723
                                                        pg_encoding_to_char(pset.encoding));
 
724
                        }
 
725
                        free(encoding);
 
726
                }
 
727
        }
 
728
 
 
729
        /* \f -- change field separator */
 
730
        else if (strcmp(cmd, "f") == 0)
 
731
        {
 
732
                char       *fname = psql_scan_slash_option(scan_state,
 
733
                                                                                                   OT_NORMAL, NULL, false);
 
734
 
 
735
                success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
 
736
                free(fname);
 
737
        }
 
738
 
 
739
        /* \g means send query */
 
740
        else if (strcmp(cmd, "g") == 0)
 
741
        {
 
742
                char       *fname = psql_scan_slash_option(scan_state,
 
743
                                                                                                   OT_FILEPIPE, NULL, false);
 
744
 
 
745
                if (!fname)
 
746
                        pset.gfname = NULL;
 
747
                else
 
748
                {
 
749
                        expand_tilde(&fname);
 
750
                        pset.gfname = pg_strdup(fname);
 
751
                }
 
752
                free(fname);
 
753
                status = PSQL_CMD_SEND;
 
754
        }
 
755
 
 
756
        /* help */
 
757
        else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
 
758
        {
 
759
                char       *opt = psql_scan_slash_option(scan_state,
 
760
                                                                                                 OT_WHOLE_LINE, NULL, false);
 
761
                size_t          len;
 
762
 
 
763
                /* strip any trailing spaces and semicolons */
 
764
                if (opt)
 
765
                {
 
766
                        len = strlen(opt);
 
767
                        while (len > 0 &&
 
768
                                   (isspace((unsigned char) opt[len - 1])
 
769
                                        || opt[len - 1] == ';'))
 
770
                                opt[--len] = '\0';
 
771
                }
 
772
 
 
773
                helpSQL(opt, pset.popt.topt.pager);
 
774
                free(opt);
 
775
        }
 
776
 
 
777
        /* HTML mode */
 
778
        else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
 
779
        {
 
780
                if (pset.popt.topt.format != PRINT_HTML)
 
781
                        success = do_pset("format", "html", &pset.popt, pset.quiet);
 
782
                else
 
783
                        success = do_pset("format", "aligned", &pset.popt, pset.quiet);
 
784
        }
 
785
 
 
786
 
 
787
        /* \i is include file */
 
788
        else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
 
789
        {
 
790
                char       *fname = psql_scan_slash_option(scan_state,
 
791
                                                                                                   OT_NORMAL, NULL, true);
 
792
 
 
793
                if (!fname)
 
794
                {
 
795
                        psql_error("\\%s: missing required argument\n", cmd);
 
796
                        success = false;
 
797
                }
 
798
                else
 
799
                {
 
800
                        expand_tilde(&fname);
 
801
                        success = (process_file(fname, false) == EXIT_SUCCESS);
 
802
                        free(fname);
 
803
                }
 
804
        }
 
805
 
 
806
        /* \l is list databases */
 
807
        else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
 
808
                success = listAllDbs(false);
 
809
        else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
 
810
                success = listAllDbs(true);
 
811
 
 
812
        /*
 
813
         * large object things
 
814
         */
 
815
        else if (strncmp(cmd, "lo_", 3) == 0)
 
816
        {
 
817
                char       *opt1,
 
818
                                   *opt2;
 
819
 
 
820
                opt1 = psql_scan_slash_option(scan_state,
 
821
                                                                          OT_NORMAL, NULL, true);
 
822
                opt2 = psql_scan_slash_option(scan_state,
 
823
                                                                          OT_NORMAL, NULL, true);
 
824
 
 
825
                if (strcmp(cmd + 3, "export") == 0)
 
826
                {
 
827
                        if (!opt2)
 
828
                        {
 
829
                                psql_error("\\%s: missing required argument\n", cmd);
 
830
                                success = false;
 
831
                        }
 
832
                        else
 
833
                        {
 
834
                                expand_tilde(&opt2);
 
835
                                success = do_lo_export(opt1, opt2);
 
836
                        }
 
837
                }
 
838
 
 
839
                else if (strcmp(cmd + 3, "import") == 0)
 
840
                {
 
841
                        if (!opt1)
 
842
                        {
 
843
                                psql_error("\\%s: missing required argument\n", cmd);
 
844
                                success = false;
 
845
                        }
 
846
                        else
 
847
                        {
 
848
                                expand_tilde(&opt1);
 
849
                                success = do_lo_import(opt1, opt2);
 
850
                        }
 
851
                }
 
852
 
 
853
                else if (strcmp(cmd + 3, "list") == 0)
 
854
                        success = do_lo_list();
 
855
 
 
856
                else if (strcmp(cmd + 3, "unlink") == 0)
 
857
                {
 
858
                        if (!opt1)
 
859
                        {
 
860
                                psql_error("\\%s: missing required argument\n", cmd);
 
861
                                success = false;
 
862
                        }
 
863
                        else
 
864
                                success = do_lo_unlink(opt1);
 
865
                }
 
866
 
 
867
                else
 
868
                        status = PSQL_CMD_UNKNOWN;
 
869
 
 
870
                free(opt1);
 
871
                free(opt2);
 
872
        }
 
873
 
 
874
 
 
875
        /* \o -- set query output */
 
876
        else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
 
877
        {
 
878
                char       *fname = psql_scan_slash_option(scan_state,
 
879
                                                                                                   OT_FILEPIPE, NULL, true);
 
880
 
 
881
                expand_tilde(&fname);
 
882
                success = setQFout(fname);
 
883
                free(fname);
 
884
        }
 
885
 
 
886
        /* \p prints the current query buffer */
 
887
        else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
 
888
        {
 
889
                if (query_buf && query_buf->len > 0)
 
890
                        puts(query_buf->data);
 
891
                else if (!pset.quiet)
 
892
                        puts(_("Query buffer is empty."));
 
893
                fflush(stdout);
 
894
        }
 
895
 
 
896
        /* \password -- set user password */
 
897
        else if (strcmp(cmd, "password") == 0)
 
898
        {
 
899
                char       *pw1;
 
900
                char       *pw2;
 
901
 
 
902
                pw1 = simple_prompt("Enter new password: ", 100, false);
 
903
                pw2 = simple_prompt("Enter it again: ", 100, false);
 
904
 
 
905
                if (strcmp(pw1, pw2) != 0)
 
906
                {
 
907
                        fprintf(stderr, _("Passwords didn't match.\n"));
 
908
                        success = false;
 
909
                }
 
910
                else
 
911
                {
 
912
                        char       *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true);
 
913
                        char       *user;
 
914
                        char       *encrypted_password;
 
915
 
 
916
                        if (opt0)
 
917
                                user = opt0;
 
918
                        else
 
919
                                user = PQuser(pset.db);
 
920
 
 
921
                        encrypted_password = PQencryptPassword(pw1, user);
 
922
 
 
923
                        if (!encrypted_password)
 
924
                        {
 
925
                                fprintf(stderr, _("Password encryption failed.\n"));
 
926
                                success = false;
 
927
                        }
 
928
                        else
 
929
                        {
 
930
                                PQExpBufferData buf;
 
931
                                PGresult   *res;
 
932
 
 
933
                                initPQExpBuffer(&buf);
 
934
                                printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
 
935
                                                                  fmtId(user));
 
936
                                appendStringLiteralConn(&buf, encrypted_password, pset.db);
 
937
                                res = PSQLexec(buf.data, false);
 
938
                                termPQExpBuffer(&buf);
 
939
                                if (!res)
 
940
                                        success = false;
 
941
                                else
 
942
                                        PQclear(res);
 
943
                                PQfreemem(encrypted_password);
 
944
                        }
 
945
                }
 
946
 
 
947
                free(pw1);
 
948
                free(pw2);
 
949
        }
 
950
 
 
951
        /* \prompt -- prompt and set variable */
 
952
        else if (strcmp(cmd, "prompt") == 0)
 
953
        {
 
954
                char       *opt,
 
955
                                   *prompt_text = NULL;
 
956
                char       *arg1,
 
957
                                   *arg2;
 
958
 
 
959
                arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
 
960
                arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
 
961
 
 
962
                if (!arg1)
 
963
                {
 
964
                        psql_error("\\%s: missing required argument\n", cmd);
 
965
                        success = false;
 
966
                }
 
967
                else
 
968
                {
 
969
                        char       *result;
 
970
 
 
971
                        if (arg2)
 
972
                        {
 
973
                                prompt_text = arg1;
 
974
                                opt = arg2;
 
975
                        }
 
976
                        else
 
977
                                opt = arg1;
 
978
 
 
979
                        if (!pset.inputfile)
 
980
                                result = simple_prompt(prompt_text, 4096, true);
 
981
                        else
 
982
                        {
 
983
                                if (prompt_text)
 
984
                                {
 
985
                                        fputs(prompt_text, stdout);
 
986
                                        fflush(stdout);
 
987
                                }
 
988
                                result = gets_fromFile(stdin);
 
989
                        }
 
990
 
 
991
                        if (!SetVariable(pset.vars, opt, result))
 
992
                        {
 
993
                                psql_error("\\%s: error\n", cmd);
 
994
                                success = false;
 
995
                        }
 
996
 
 
997
                        free(result);
 
998
                        if (prompt_text)
 
999
                                free(prompt_text);
 
1000
                        free(opt);
 
1001
                }
 
1002
        }
 
1003
 
 
1004
        /* \pset -- set printing parameters */
 
1005
        else if (strcmp(cmd, "pset") == 0)
 
1006
        {
 
1007
                char       *opt0 = psql_scan_slash_option(scan_state,
 
1008
                                                                                                  OT_NORMAL, NULL, false);
 
1009
                char       *opt1 = psql_scan_slash_option(scan_state,
 
1010
                                                                                                  OT_NORMAL, NULL, false);
 
1011
 
 
1012
                if (!opt0)
 
1013
                {
 
1014
                        psql_error("\\%s: missing required argument\n", cmd);
 
1015
                        success = false;
 
1016
                }
 
1017
                else
 
1018
                        success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
 
1019
 
 
1020
                free(opt0);
 
1021
                free(opt1);
 
1022
        }
 
1023
 
 
1024
        /* \q or \quit */
 
1025
        else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
 
1026
                status = PSQL_CMD_TERMINATE;
 
1027
 
 
1028
        /* reset(clear) the buffer */
 
1029
        else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
 
1030
        {
 
1031
                resetPQExpBuffer(query_buf);
 
1032
                psql_scan_reset(scan_state);
 
1033
                if (!pset.quiet)
 
1034
                        puts(_("Query buffer reset (cleared)."));
 
1035
        }
 
1036
 
 
1037
        /* \s save history in a file or show it on the screen */
 
1038
        else if (strcmp(cmd, "s") == 0)
 
1039
        {
 
1040
                char       *fname = psql_scan_slash_option(scan_state,
 
1041
                                                                                                   OT_NORMAL, NULL, true);
 
1042
 
 
1043
                expand_tilde(&fname);
 
1044
                /* This scrolls off the screen when using /dev/tty */
 
1045
                success = saveHistory(fname ? fname : DEVTTY, -1, false, false);
 
1046
                if (success && !pset.quiet && fname)
 
1047
                        printf(gettext("Wrote history to file \"%s/%s\".\n"),
 
1048
                                   pset.dirname ? pset.dirname : ".", fname);
 
1049
                if (!fname)
 
1050
                        putchar('\n');
 
1051
                free(fname);
 
1052
        }
 
1053
 
 
1054
        /* \set -- generalized set variable/option command */
 
1055
        else if (strcmp(cmd, "set") == 0)
 
1056
        {
 
1057
                char       *opt0 = psql_scan_slash_option(scan_state,
 
1058
                                                                                                  OT_NORMAL, NULL, false);
 
1059
 
 
1060
                if (!opt0)
 
1061
                {
 
1062
                        /* list all variables */
 
1063
                        PrintVariables(pset.vars);
 
1064
                        success = true;
 
1065
                }
 
1066
                else
 
1067
                {
 
1068
                        /*
 
1069
                         * Set variable to the concatenation of the arguments.
 
1070
                         */
 
1071
                        char       *newval;
 
1072
                        char       *opt;
 
1073
 
 
1074
                        opt = psql_scan_slash_option(scan_state,
 
1075
                                                                                 OT_NORMAL, NULL, false);
 
1076
                        newval = pg_strdup(opt ? opt : "");
 
1077
                        free(opt);
 
1078
 
 
1079
                        while ((opt = psql_scan_slash_option(scan_state,
 
1080
                                                                                                 OT_NORMAL, NULL, false)))
 
1081
                        {
 
1082
                                newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
 
1083
                                if (!newval)
 
1084
                                {
 
1085
                                        psql_error("out of memory\n");
 
1086
                                        exit(EXIT_FAILURE);
 
1087
                                }
 
1088
                                strcat(newval, opt);
 
1089
                                free(opt);
 
1090
                        }
 
1091
 
 
1092
                        if (!SetVariable(pset.vars, opt0, newval))
 
1093
                        {
 
1094
                                psql_error("\\%s: error\n", cmd);
 
1095
                                success = false;
 
1096
                        }
 
1097
                        free(newval);
 
1098
                }
 
1099
                free(opt0);
 
1100
        }
 
1101
 
 
1102
        /* \sf -- show a function's source code */
 
1103
        else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
 
1104
        {
 
1105
                bool            show_linenumbers = (strcmp(cmd, "sf+") == 0);
 
1106
                PQExpBuffer func_buf;
 
1107
                char       *func;
 
1108
                Oid                     foid = InvalidOid;
 
1109
 
 
1110
                func_buf = createPQExpBuffer();
 
1111
                func = psql_scan_slash_option(scan_state,
 
1112
                                                                          OT_WHOLE_LINE, NULL, true);
 
1113
                if (!func)
 
1114
                {
 
1115
                        psql_error("function name is required\n");
 
1116
                        status = PSQL_CMD_ERROR;
 
1117
                }
 
1118
                else if (!lookup_function_oid(pset.db, func, &foid))
 
1119
                {
 
1120
                        /* error already reported */
 
1121
                        status = PSQL_CMD_ERROR;
 
1122
                }
 
1123
                else if (!get_create_function_cmd(pset.db, foid, func_buf))
 
1124
                {
 
1125
                        /* error already reported */
 
1126
                        status = PSQL_CMD_ERROR;
 
1127
                }
 
1128
                else
 
1129
                {
 
1130
                        FILE       *output;
 
1131
                        bool            is_pager;
 
1132
 
 
1133
                        /* Select output stream: stdout, pager, or file */
 
1134
                        if (pset.queryFout == stdout)
 
1135
                        {
 
1136
                                /* count lines in function to see if pager is needed */
 
1137
                                int                     lineno = 0;
 
1138
                                const char *lines = func_buf->data;
 
1139
 
 
1140
                                while (*lines != '\0')
 
1141
                                {
 
1142
                                        lineno++;
 
1143
                                        /* find start of next line */
 
1144
                                        lines = strchr(lines, '\n');
 
1145
                                        if (!lines)
 
1146
                                                break;
 
1147
                                        lines++;
 
1148
                                }
 
1149
 
 
1150
                                output = PageOutput(lineno, pset.popt.topt.pager);
 
1151
                                is_pager = true;
 
1152
                        }
 
1153
                        else
 
1154
                        {
 
1155
                                /* use previously set output file, without pager */
 
1156
                                output = pset.queryFout;
 
1157
                                is_pager = false;
 
1158
                        }
 
1159
 
 
1160
                        if (show_linenumbers)
 
1161
                        {
 
1162
                                bool            in_header = true;
 
1163
                                int                     lineno = 0;
 
1164
                                char       *lines = func_buf->data;
 
1165
 
 
1166
                                /*
 
1167
                                 * lineno "1" should correspond to the first line of the
 
1168
                                 * function body.  We expect that pg_get_functiondef() will
 
1169
                                 * emit that on a line beginning with "AS ", and that there
 
1170
                                 * can be no such line before the real start of the function
 
1171
                                 * body.
 
1172
                                 *
 
1173
                                 * Note that this loop scribbles on func_buf.
 
1174
                                 */
 
1175
                                while (*lines != '\0')
 
1176
                                {
 
1177
                                        char       *eol;
 
1178
 
 
1179
                                        if (in_header && strncmp(lines, "AS ", 3) == 0)
 
1180
                                                in_header = false;
 
1181
                                        /* increment lineno only for body's lines */
 
1182
                                        if (!in_header)
 
1183
                                                lineno++;
 
1184
 
 
1185
                                        /* find and mark end of current line */
 
1186
                                        eol = strchr(lines, '\n');
 
1187
                                        if (eol != NULL)
 
1188
                                                *eol = '\0';
 
1189
 
 
1190
                                        /* show current line as appropriate */
 
1191
                                        if (in_header)
 
1192
                                                fprintf(output, "        %s\n", lines);
 
1193
                                        else
 
1194
                                                fprintf(output, "%-7d %s\n", lineno, lines);
 
1195
 
 
1196
                                        /* advance to next line, if any */
 
1197
                                        if (eol == NULL)
 
1198
                                                break;
 
1199
                                        lines = ++eol;
 
1200
                                }
 
1201
                        }
 
1202
                        else
 
1203
                        {
 
1204
                                /* just send the function definition to output */
 
1205
                                fputs(func_buf->data, output);
 
1206
                        }
 
1207
 
 
1208
                        if (is_pager)
 
1209
                                ClosePager(output);
 
1210
                }
 
1211
 
 
1212
                if (func)
 
1213
                        free(func);
 
1214
                destroyPQExpBuffer(func_buf);
 
1215
        }
 
1216
 
 
1217
        /* \t -- turn off headers and row count */
 
1218
        else if (strcmp(cmd, "t") == 0)
 
1219
        {
 
1220
                char       *opt = psql_scan_slash_option(scan_state,
 
1221
                                                                                                 OT_NORMAL, NULL, true);
 
1222
 
 
1223
                success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
 
1224
                free(opt);
 
1225
        }
 
1226
 
 
1227
        /* \T -- define html <table ...> attributes */
 
1228
        else if (strcmp(cmd, "T") == 0)
 
1229
        {
 
1230
                char       *value = psql_scan_slash_option(scan_state,
 
1231
                                                                                                   OT_NORMAL, NULL, false);
 
1232
 
 
1233
                success = do_pset("tableattr", value, &pset.popt, pset.quiet);
 
1234
                free(value);
 
1235
        }
 
1236
 
 
1237
        /* \timing -- toggle timing of queries */
 
1238
        else if (strcmp(cmd, "timing") == 0)
 
1239
        {
 
1240
                char       *opt = psql_scan_slash_option(scan_state,
 
1241
                                                                                                 OT_NORMAL, NULL, false);
 
1242
 
 
1243
                if (opt)
 
1244
                        pset.timing = ParseVariableBool(opt);
 
1245
                else
 
1246
                        pset.timing = !pset.timing;
 
1247
                if (!pset.quiet)
 
1248
                {
 
1249
                        if (pset.timing)
 
1250
                                puts(_("Timing is on."));
 
1251
                        else
 
1252
                                puts(_("Timing is off."));
 
1253
                }
 
1254
                free(opt);
 
1255
        }
 
1256
 
 
1257
        /* \unset */
 
1258
        else if (strcmp(cmd, "unset") == 0)
 
1259
        {
 
1260
                char       *opt = psql_scan_slash_option(scan_state,
 
1261
                                                                                                 OT_NORMAL, NULL, false);
 
1262
 
 
1263
                if (!opt)
 
1264
                {
 
1265
                        psql_error("\\%s: missing required argument\n", cmd);
 
1266
                        success = false;
 
1267
                }
 
1268
                else if (!SetVariable(pset.vars, opt, NULL))
 
1269
                {
 
1270
                        psql_error("\\%s: error\n", cmd);
 
1271
                        success = false;
 
1272
                }
 
1273
                free(opt);
 
1274
        }
 
1275
 
 
1276
        /* \w -- write query buffer to file */
 
1277
        else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
 
1278
        {
 
1279
                FILE       *fd = NULL;
 
1280
                bool            is_pipe = false;
 
1281
                char       *fname = NULL;
 
1282
 
 
1283
                if (!query_buf)
 
1284
                {
 
1285
                        psql_error("no query buffer\n");
 
1286
                        status = PSQL_CMD_ERROR;
 
1287
                }
 
1288
                else
 
1289
                {
 
1290
                        fname = psql_scan_slash_option(scan_state,
 
1291
                                                                                   OT_FILEPIPE, NULL, true);
 
1292
                        expand_tilde(&fname);
 
1293
 
 
1294
                        if (!fname)
 
1295
                        {
 
1296
                                psql_error("\\%s: missing required argument\n", cmd);
 
1297
                                success = false;
 
1298
                        }
 
1299
                        else
 
1300
                        {
 
1301
                                if (fname[0] == '|')
 
1302
                                {
 
1303
                                        is_pipe = true;
 
1304
                                        fd = popen(&fname[1], "w");
 
1305
                                }
 
1306
                                else
 
1307
                                {
 
1308
                                        canonicalize_path(fname);
 
1309
                                        fd = fopen(fname, "w");
 
1310
                                }
 
1311
                                if (!fd)
 
1312
                                {
 
1313
                                        psql_error("%s: %s\n", fname, strerror(errno));
 
1314
                                        success = false;
 
1315
                                }
 
1316
                        }
 
1317
                }
 
1318
 
 
1319
                if (fd)
 
1320
                {
 
1321
                        int                     result;
 
1322
 
 
1323
                        if (query_buf && query_buf->len > 0)
 
1324
                                fprintf(fd, "%s\n", query_buf->data);
 
1325
 
 
1326
                        if (is_pipe)
 
1327
                                result = pclose(fd);
 
1328
                        else
 
1329
                                result = fclose(fd);
 
1330
 
 
1331
                        if (result == EOF)
 
1332
                        {
 
1333
                                psql_error("%s: %s\n", fname, strerror(errno));
 
1334
                                success = false;
 
1335
                        }
 
1336
                }
 
1337
 
 
1338
                free(fname);
 
1339
        }
 
1340
 
 
1341
        /* \x -- toggle expanded table representation */
 
1342
        else if (strcmp(cmd, "x") == 0)
 
1343
        {
 
1344
                char       *opt = psql_scan_slash_option(scan_state,
 
1345
                                                                                                 OT_NORMAL, NULL, true);
 
1346
 
 
1347
                success = do_pset("expanded", opt, &pset.popt, pset.quiet);
 
1348
                free(opt);
 
1349
        }
 
1350
 
 
1351
        /* \z -- list table rights (equivalent to \dp) */
 
1352
        else if (strcmp(cmd, "z") == 0)
 
1353
        {
 
1354
                char       *pattern = psql_scan_slash_option(scan_state,
 
1355
                                                                                                         OT_NORMAL, NULL, true);
 
1356
 
 
1357
                success = permissionsList(pattern);
 
1358
                if (pattern)
 
1359
                        free(pattern);
 
1360
        }
 
1361
 
 
1362
        /* \! -- shell escape */
 
1363
        else if (strcmp(cmd, "!") == 0)
 
1364
        {
 
1365
                char       *opt = psql_scan_slash_option(scan_state,
 
1366
                                                                                                 OT_WHOLE_LINE, NULL, false);
 
1367
 
 
1368
                success = do_shell(opt);
 
1369
                free(opt);
 
1370
        }
 
1371
 
 
1372
        /* \? -- slash command help */
 
1373
        else if (strcmp(cmd, "?") == 0)
 
1374
                slashUsage(pset.popt.topt.pager);
 
1375
 
 
1376
#if 0
 
1377
 
 
1378
        /*
 
1379
         * These commands don't do anything. I just use them to test the parser.
 
1380
         */
 
1381
        else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
 
1382
        {
 
1383
                int                     i = 0;
 
1384
                char       *value;
 
1385
 
 
1386
                while ((value = psql_scan_slash_option(scan_state,
 
1387
                                                                                           OT_NORMAL, NULL, true)))
 
1388
                {
 
1389
                        fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
 
1390
                        free(value);
 
1391
                }
 
1392
        }
 
1393
#endif
 
1394
 
 
1395
        else
 
1396
                status = PSQL_CMD_UNKNOWN;
 
1397
 
 
1398
        if (!success)
 
1399
                status = PSQL_CMD_ERROR;
 
1400
 
 
1401
        return status;
 
1402
}
 
1403
 
 
1404
/*
 
1405
 * Ask the user for a password; 'username' is the username the
 
1406
 * password is for, if one has been explicitly specified. Returns a
 
1407
 * malloc'd string.
 
1408
 */
 
1409
static char *
 
1410
prompt_for_password(const char *username)
 
1411
{
 
1412
        char       *result;
 
1413
 
 
1414
        if (username == NULL)
 
1415
                result = simple_prompt("Password: ", 100, false);
 
1416
        else
 
1417
        {
 
1418
                char       *prompt_text;
 
1419
 
 
1420
                prompt_text = malloc(strlen(username) + 100);
 
1421
                snprintf(prompt_text, strlen(username) + 100,
 
1422
                                 _("Password for user %s: "), username);
 
1423
                result = simple_prompt(prompt_text, 100, false);
 
1424
                free(prompt_text);
 
1425
        }
 
1426
 
 
1427
        return result;
 
1428
}
 
1429
 
 
1430
static bool
 
1431
param_is_newly_set(const char *old_val, const char *new_val)
 
1432
{
 
1433
        if (new_val == NULL)
 
1434
                return false;
 
1435
 
 
1436
        if (old_val == NULL || strcmp(old_val, new_val) != 0)
 
1437
                return true;
 
1438
 
 
1439
        return false;
 
1440
}
 
1441
 
 
1442
/*
 
1443
 * do_connect -- handler for \connect
 
1444
 *
 
1445
 * Connects to a database with given parameters. If there exists an
 
1446
 * established connection, NULL values will be replaced with the ones
 
1447
 * in the current connection. Otherwise NULL will be passed for that
 
1448
 * parameter to PQconnectdbParams(), so the libpq defaults will be used.
 
1449
 *
 
1450
 * In interactive mode, if connection fails with the given parameters,
 
1451
 * the old connection will be kept.
 
1452
 */
 
1453
static bool
 
1454
do_connect(char *dbname, char *user, char *host, char *port)
 
1455
{
 
1456
        PGconn     *o_conn = pset.db,
 
1457
                           *n_conn;
 
1458
        char       *password = NULL;
 
1459
 
 
1460
        if (!dbname)
 
1461
                dbname = PQdb(o_conn);
 
1462
        if (!user)
 
1463
                user = PQuser(o_conn);
 
1464
        if (!host)
 
1465
                host = PQhost(o_conn);
 
1466
        if (!port)
 
1467
                port = PQport(o_conn);
 
1468
 
 
1469
        /*
 
1470
         * If the user asked to be prompted for a password, ask for one now. If
 
1471
         * not, use the password from the old connection, provided the username
 
1472
         * has not changed. Otherwise, try to connect without a password first,
 
1473
         * and then ask for a password if needed.
 
1474
         *
 
1475
         * XXX: this behavior leads to spurious connection attempts recorded in
 
1476
         * the postmaster's log.  But libpq offers no API that would let us obtain
 
1477
         * a password and then continue with the first connection attempt.
 
1478
         */
 
1479
        if (pset.getPassword == TRI_YES)
 
1480
        {
 
1481
                password = prompt_for_password(user);
 
1482
        }
 
1483
        else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0)
 
1484
        {
 
1485
                password = strdup(PQpass(o_conn));
 
1486
        }
 
1487
 
 
1488
        while (true)
 
1489
        {
 
1490
#define PARAMS_ARRAY_SIZE       8
 
1491
                const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
 
1492
                const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
 
1493
 
 
1494
                keywords[0] = "host";
 
1495
                values[0] = host;
 
1496
                keywords[1] = "port";
 
1497
                values[1] = port;
 
1498
                keywords[2] = "user";
 
1499
                values[2] = user;
 
1500
                keywords[3] = "password";
 
1501
                values[3] = password;
 
1502
                keywords[4] = "dbname";
 
1503
                values[4] = dbname;
 
1504
                keywords[5] = "fallback_application_name";
 
1505
                values[5] = pset.progname;
 
1506
                keywords[6] = "client_encoding";
 
1507
                values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
 
1508
                keywords[7] = NULL;
 
1509
                values[7] = NULL;
 
1510
 
 
1511
                n_conn = PQconnectdbParams(keywords, values, true);
 
1512
 
 
1513
                free(keywords);
 
1514
                free(values);
 
1515
 
 
1516
                /* We can immediately discard the password -- no longer needed */
 
1517
                if (password)
 
1518
                        free(password);
 
1519
 
 
1520
                if (PQstatus(n_conn) == CONNECTION_OK)
 
1521
                        break;
 
1522
 
 
1523
                /*
 
1524
                 * Connection attempt failed; either retry the connection attempt with
 
1525
                 * a new password, or give up.
 
1526
                 */
 
1527
                if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
 
1528
                {
 
1529
                        PQfinish(n_conn);
 
1530
                        password = prompt_for_password(user);
 
1531
                        continue;
 
1532
                }
 
1533
 
 
1534
                /*
 
1535
                 * Failed to connect to the database. In interactive mode, keep the
 
1536
                 * previous connection to the DB; in scripting mode, close our
 
1537
                 * previous connection as well.
 
1538
                 */
 
1539
                if (pset.cur_cmd_interactive)
 
1540
                {
 
1541
                        psql_error("%s", PQerrorMessage(n_conn));
 
1542
 
 
1543
                        /* pset.db is left unmodified */
 
1544
                        if (o_conn)
 
1545
                                fputs(_("Previous connection kept\n"), stderr);
 
1546
                }
 
1547
                else
 
1548
                {
 
1549
                        psql_error("\\connect: %s", PQerrorMessage(n_conn));
 
1550
                        if (o_conn)
 
1551
                        {
 
1552
                                PQfinish(o_conn);
 
1553
                                pset.db = NULL;
 
1554
                        }
 
1555
                }
 
1556
 
 
1557
                PQfinish(n_conn);
 
1558
                return false;
 
1559
        }
 
1560
 
 
1561
        /*
 
1562
         * Replace the old connection with the new one, and update
 
1563
         * connection-dependent variables.
 
1564
         */
 
1565
        PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
 
1566
        pset.db = n_conn;
 
1567
        SyncVariables();
 
1568
        connection_warnings(false); /* Must be after SyncVariables */
 
1569
 
 
1570
        /* Tell the user about the new connection */
 
1571
        if (!pset.quiet)
 
1572
        {
 
1573
                if (param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
 
1574
                        param_is_newly_set(PQport(o_conn), PQport(pset.db)))
 
1575
                {
 
1576
                        char       *host = PQhost(pset.db);
 
1577
 
 
1578
                        if (host == NULL)
 
1579
                                host = DEFAULT_PGSOCKET_DIR;
 
1580
                        /* If the host is an absolute path, the connection is via socket */
 
1581
                        if (is_absolute_path(host))
 
1582
                                printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
 
1583
                                           PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
 
1584
                        else
 
1585
                                printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
 
1586
                                           PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
 
1587
                }
 
1588
                else
 
1589
                        printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
 
1590
                                   PQdb(pset.db), PQuser(pset.db));
 
1591
        }
 
1592
 
 
1593
        if (o_conn)
 
1594
                PQfinish(o_conn);
 
1595
        return true;
 
1596
}
 
1597
 
 
1598
 
 
1599
void
 
1600
connection_warnings(bool in_startup)
 
1601
{
 
1602
        if (!pset.quiet && !pset.notty)
 
1603
        {
 
1604
                int                     client_ver = parse_version(PG_VERSION);
 
1605
 
 
1606
                if (pset.sversion != client_ver)
 
1607
                {
 
1608
                        const char *server_version;
 
1609
                        char            server_ver_str[16];
 
1610
 
 
1611
                        /* Try to get full text form, might include "devel" etc */
 
1612
                        server_version = PQparameterStatus(pset.db, "server_version");
 
1613
                        if (!server_version)
 
1614
                        {
 
1615
                                snprintf(server_ver_str, sizeof(server_ver_str),
 
1616
                                                 "%d.%d.%d",
 
1617
                                                 pset.sversion / 10000,
 
1618
                                                 (pset.sversion / 100) % 100,
 
1619
                                                 pset.sversion % 100);
 
1620
                                server_version = server_ver_str;
 
1621
                        }
 
1622
 
 
1623
                        printf(_("%s (%s, server %s)\n"),
 
1624
                                   pset.progname, PG_VERSION, server_version);
 
1625
                }
 
1626
                /* For version match, only print psql banner on startup. */
 
1627
                else if (in_startup)
 
1628
                        printf("%s (%s)\n", pset.progname, PG_VERSION);
 
1629
 
 
1630
                if (pset.sversion / 100 != client_ver / 100)
 
1631
                        printf(_("WARNING: %s version %d.%d, server version %d.%d.\n"
 
1632
                                         "         Some psql features might not work.\n"),
 
1633
                                 pset.progname, client_ver / 10000, (client_ver / 100) % 100,
 
1634
                                   pset.sversion / 10000, (pset.sversion / 100) % 100);
 
1635
 
 
1636
#ifdef WIN32
 
1637
                checkWin32Codepage();
 
1638
#endif
 
1639
                printSSLInfo();
 
1640
        }
 
1641
}
 
1642
 
 
1643
 
 
1644
/*
 
1645
 * printSSLInfo
 
1646
 *
 
1647
 * Prints information about the current SSL connection, if SSL is in use
 
1648
 */
 
1649
static void
 
1650
printSSLInfo(void)
 
1651
{
 
1652
#ifdef USE_SSL
 
1653
        int                     sslbits = -1;
 
1654
        SSL                *ssl;
 
1655
 
 
1656
        ssl = PQgetssl(pset.db);
 
1657
        if (!ssl)
 
1658
                return;                                 /* no SSL */
 
1659
 
 
1660
        SSL_get_cipher_bits(ssl, &sslbits);
 
1661
        printf(_("SSL connection (cipher: %s, bits: %i)\n"),
 
1662
                   SSL_get_cipher(ssl), sslbits);
 
1663
#else
 
1664
 
 
1665
        /*
 
1666
         * If psql is compiled without SSL but is using a libpq with SSL, we
 
1667
         * cannot figure out the specifics about the connection. But we know it's
 
1668
         * SSL secured.
 
1669
         */
 
1670
        if (PQgetssl(pset.db))
 
1671
                printf(_("SSL connection (unknown cipher)\n"));
 
1672
#endif
 
1673
}
 
1674
 
 
1675
 
 
1676
/*
 
1677
 * checkWin32Codepage
 
1678
 *
 
1679
 * Prints a warning when win32 console codepage differs from Windows codepage
 
1680
 */
 
1681
#ifdef WIN32
 
1682
static void
 
1683
checkWin32Codepage(void)
 
1684
{
 
1685
        unsigned int wincp,
 
1686
                                concp;
 
1687
 
 
1688
        wincp = GetACP();
 
1689
        concp = GetConsoleCP();
 
1690
        if (wincp != concp)
 
1691
        {
 
1692
                printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
 
1693
                                 "         8-bit characters might not work correctly. See psql reference\n"
 
1694
                                 "         page \"Notes for Windows users\" for details.\n"),
 
1695
                           concp, wincp);
 
1696
        }
 
1697
}
 
1698
#endif
 
1699
 
 
1700
 
 
1701
/*
 
1702
 * SyncVariables
 
1703
 *
 
1704
 * Make psql's internal variables agree with connection state upon
 
1705
 * establishing a new connection.
 
1706
 */
 
1707
void
 
1708
SyncVariables(void)
 
1709
{
 
1710
        /* get stuff from connection */
 
1711
        pset.encoding = PQclientEncoding(pset.db);
 
1712
        pset.popt.topt.encoding = pset.encoding;
 
1713
        pset.sversion = PQserverVersion(pset.db);
 
1714
 
 
1715
        SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
 
1716
        SetVariable(pset.vars, "USER", PQuser(pset.db));
 
1717
        SetVariable(pset.vars, "HOST", PQhost(pset.db));
 
1718
        SetVariable(pset.vars, "PORT", PQport(pset.db));
 
1719
        SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
 
1720
 
 
1721
        /* send stuff to it, too */
 
1722
        PQsetErrorVerbosity(pset.db, pset.verbosity);
 
1723
}
 
1724
 
 
1725
/*
 
1726
 * UnsyncVariables
 
1727
 *
 
1728
 * Clear variables that should be not be set when there is no connection.
 
1729
 */
 
1730
void
 
1731
UnsyncVariables(void)
 
1732
{
 
1733
        SetVariable(pset.vars, "DBNAME", NULL);
 
1734
        SetVariable(pset.vars, "USER", NULL);
 
1735
        SetVariable(pset.vars, "HOST", NULL);
 
1736
        SetVariable(pset.vars, "PORT", NULL);
 
1737
        SetVariable(pset.vars, "ENCODING", NULL);
 
1738
}
 
1739
 
 
1740
 
 
1741
/*
 
1742
 * do_edit -- handler for \e
 
1743
 *
 
1744
 * If you do not specify a filename, the current query buffer will be copied
 
1745
 * into a temporary one.
 
1746
 */
 
1747
static bool
 
1748
editFile(const char *fname, int lineno)
 
1749
{
 
1750
        const char *editorName;
 
1751
        const char *editor_lineno_switch = NULL;
 
1752
        char       *sys;
 
1753
        int                     result;
 
1754
 
 
1755
        psql_assert(fname);
 
1756
 
 
1757
        /* Find an editor to use */
 
1758
        editorName = getenv("PSQL_EDITOR");
 
1759
        if (!editorName)
 
1760
                editorName = getenv("EDITOR");
 
1761
        if (!editorName)
 
1762
                editorName = getenv("VISUAL");
 
1763
        if (!editorName)
 
1764
                editorName = DEFAULT_EDITOR;
 
1765
 
 
1766
        /* Get line number switch, if we need it. */
 
1767
        if (lineno > 0)
 
1768
        {
 
1769
                editor_lineno_switch = GetVariable(pset.vars,
 
1770
                                                                                   "EDITOR_LINENUMBER_SWITCH");
 
1771
                if (editor_lineno_switch == NULL)
 
1772
                {
 
1773
                        psql_error("EDITOR_LINENUMBER_SWITCH variable must be set to specify a line number\n");
 
1774
                        return false;
 
1775
                }
 
1776
        }
 
1777
 
 
1778
        /* Allocate sufficient memory for command line. */
 
1779
        if (lineno > 0)
 
1780
                sys = pg_malloc(strlen(editorName)
 
1781
                                                + strlen(editor_lineno_switch) + 10             /* for integer */
 
1782
                                                + 1 + strlen(fname) + 10 + 1);
 
1783
        else
 
1784
                sys = pg_malloc(strlen(editorName) + strlen(fname) + 10 + 1);
 
1785
 
 
1786
        /*
 
1787
         * On Unix the EDITOR value should *not* be quoted, since it might include
 
1788
         * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
 
1789
         * if necessary.  But this policy is not very workable on Windows, due to
 
1790
         * severe brain damage in their command shell plus the fact that standard
 
1791
         * program paths include spaces.
 
1792
         */
 
1793
#ifndef WIN32
 
1794
        if (lineno > 0)
 
1795
                sprintf(sys, "exec %s %s%d '%s'",
 
1796
                                editorName, editor_lineno_switch, lineno, fname);
 
1797
        else
 
1798
                sprintf(sys, "exec %s '%s'",
 
1799
                                editorName, fname);
 
1800
#else
 
1801
        if (lineno > 0)
 
1802
                sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
 
1803
                                editorName, editor_lineno_switch, lineno, fname);
 
1804
        else
 
1805
                sprintf(sys, SYSTEMQUOTE "\"%s\" \"%s\"" SYSTEMQUOTE,
 
1806
                                editorName, fname);
 
1807
#endif
 
1808
        result = system(sys);
 
1809
        if (result == -1)
 
1810
                psql_error("could not start editor \"%s\"\n", editorName);
 
1811
        else if (result == 127)
 
1812
                psql_error("could not start /bin/sh\n");
 
1813
        free(sys);
 
1814
 
 
1815
        return result == 0;
 
1816
}
 
1817
 
 
1818
 
 
1819
/* call this one */
 
1820
static bool
 
1821
do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
1822
                int lineno, bool *edited)
 
1823
{
 
1824
        char            fnametmp[MAXPGPATH];
 
1825
        FILE       *stream = NULL;
 
1826
        const char *fname;
 
1827
        bool            error = false;
 
1828
        int                     fd;
 
1829
 
 
1830
        struct stat before,
 
1831
                                after;
 
1832
 
 
1833
        if (filename_arg)
 
1834
                fname = filename_arg;
 
1835
        else
 
1836
        {
 
1837
                /* make a temp file to edit */
 
1838
#ifndef WIN32
 
1839
                const char *tmpdir = getenv("TMPDIR");
 
1840
 
 
1841
                if (!tmpdir)
 
1842
                        tmpdir = "/tmp";
 
1843
#else
 
1844
                char            tmpdir[MAXPGPATH];
 
1845
                int                     ret;
 
1846
 
 
1847
                ret = GetTempPath(MAXPGPATH, tmpdir);
 
1848
                if (ret == 0 || ret > MAXPGPATH)
 
1849
                {
 
1850
                        psql_error("cannot locate temporary directory: %s",
 
1851
                                           !ret ? strerror(errno) : "");
 
1852
                        return false;
 
1853
                }
 
1854
 
 
1855
                /*
 
1856
                 * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
 
1857
                 * current directory to the supplied path unless we use only
 
1858
                 * backslashes, so we do that.
 
1859
                 */
 
1860
#endif
 
1861
#ifndef WIN32
 
1862
                snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
 
1863
                                 "/", (int) getpid());
 
1864
#else
 
1865
                snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
 
1866
                           "" /* trailing separator already present */ , (int) getpid());
 
1867
#endif
 
1868
 
 
1869
                fname = (const char *) fnametmp;
 
1870
 
 
1871
                fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
 
1872
                if (fd != -1)
 
1873
                        stream = fdopen(fd, "w");
 
1874
 
 
1875
                if (fd == -1 || !stream)
 
1876
                {
 
1877
                        psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
 
1878
                        error = true;
 
1879
                }
 
1880
                else
 
1881
                {
 
1882
                        unsigned int ql = query_buf->len;
 
1883
 
 
1884
                        if (ql == 0 || query_buf->data[ql - 1] != '\n')
 
1885
                        {
 
1886
                                appendPQExpBufferChar(query_buf, '\n');
 
1887
                                ql++;
 
1888
                        }
 
1889
 
 
1890
                        if (fwrite(query_buf->data, 1, ql, stream) != ql)
 
1891
                        {
 
1892
                                psql_error("%s: %s\n", fname, strerror(errno));
 
1893
                                fclose(stream);
 
1894
                                remove(fname);
 
1895
                                error = true;
 
1896
                        }
 
1897
                        else if (fclose(stream) != 0)
 
1898
                        {
 
1899
                                psql_error("%s: %s\n", fname, strerror(errno));
 
1900
                                remove(fname);
 
1901
                                error = true;
 
1902
                        }
 
1903
                }
 
1904
        }
 
1905
 
 
1906
        if (!error && stat(fname, &before) != 0)
 
1907
        {
 
1908
                psql_error("%s: %s\n", fname, strerror(errno));
 
1909
                error = true;
 
1910
        }
 
1911
 
 
1912
        /* call editor */
 
1913
        if (!error)
 
1914
                error = !editFile(fname, lineno);
 
1915
 
 
1916
        if (!error && stat(fname, &after) != 0)
 
1917
        {
 
1918
                psql_error("%s: %s\n", fname, strerror(errno));
 
1919
                error = true;
 
1920
        }
 
1921
 
 
1922
        if (!error && before.st_mtime != after.st_mtime)
 
1923
        {
 
1924
                stream = fopen(fname, PG_BINARY_R);
 
1925
                if (!stream)
 
1926
                {
 
1927
                        psql_error("%s: %s\n", fname, strerror(errno));
 
1928
                        error = true;
 
1929
                }
 
1930
                else
 
1931
                {
 
1932
                        /* read file back into query_buf */
 
1933
                        char            line[1024];
 
1934
 
 
1935
                        resetPQExpBuffer(query_buf);
 
1936
                        while (fgets(line, sizeof(line), stream) != NULL)
 
1937
                                appendPQExpBufferStr(query_buf, line);
 
1938
 
 
1939
                        if (ferror(stream))
 
1940
                        {
 
1941
                                psql_error("%s: %s\n", fname, strerror(errno));
 
1942
                                error = true;
 
1943
                        }
 
1944
                        else if (edited)
 
1945
                        {
 
1946
                                *edited = true;
 
1947
                        }
 
1948
 
 
1949
                        fclose(stream);
 
1950
                }
 
1951
        }
 
1952
 
 
1953
        /* remove temp file */
 
1954
        if (!filename_arg)
 
1955
        {
 
1956
                if (remove(fname) == -1)
 
1957
                {
 
1958
                        psql_error("%s: %s\n", fname, strerror(errno));
 
1959
                        error = true;
 
1960
                }
 
1961
        }
 
1962
 
 
1963
        return !error;
 
1964
}
 
1965
 
 
1966
 
 
1967
 
 
1968
/*
 
1969
 * process_file
 
1970
 *
 
1971
 * Read commands from filename and then them to the main processing loop
 
1972
 * Handler for \i, but can be used for other things as well.  Returns
 
1973
 * MainLoop() error code.
 
1974
 */
 
1975
int
 
1976
process_file(char *filename, bool single_txn)
 
1977
{
 
1978
        FILE       *fd;
 
1979
        int                     result;
 
1980
        char       *oldfilename;
 
1981
        PGresult   *res;
 
1982
 
 
1983
        if (!filename)
 
1984
                return EXIT_FAILURE;
 
1985
 
 
1986
        if (strcmp(filename, "-") != 0)
 
1987
        {
 
1988
                canonicalize_path(filename);
 
1989
                fd = fopen(filename, PG_BINARY_R);
 
1990
        }
 
1991
        else
 
1992
                fd = stdin;
 
1993
 
 
1994
        if (!fd)
 
1995
        {
 
1996
                psql_error("%s: %s\n", filename, strerror(errno));
 
1997
                return EXIT_FAILURE;
 
1998
        }
 
1999
 
 
2000
        oldfilename = pset.inputfile;
 
2001
        pset.inputfile = filename;
 
2002
 
 
2003
        if (single_txn)
 
2004
        {
 
2005
                if ((res = PSQLexec("BEGIN", false)) == NULL)
 
2006
                {
 
2007
                        if (pset.on_error_stop)
 
2008
                        {
 
2009
                                result = EXIT_USER;
 
2010
                                goto error;
 
2011
                        }
 
2012
                }
 
2013
                else
 
2014
                        PQclear(res);
 
2015
        }
 
2016
 
 
2017
        result = MainLoop(fd);
 
2018
 
 
2019
        if (single_txn)
 
2020
        {
 
2021
                if ((res = PSQLexec("COMMIT", false)) == NULL)
 
2022
                {
 
2023
                        if (pset.on_error_stop)
 
2024
                        {
 
2025
                                result = EXIT_USER;
 
2026
                                goto error;
 
2027
                        }
 
2028
                }
 
2029
                else
 
2030
                        PQclear(res);
 
2031
        }
 
2032
 
 
2033
error:
 
2034
        if (fd != stdin)
 
2035
                fclose(fd);
 
2036
 
 
2037
        pset.inputfile = oldfilename;
 
2038
        return result;
 
2039
}
 
2040
 
 
2041
 
 
2042
 
 
2043
/*
 
2044
 * do_pset
 
2045
 *
 
2046
 */
 
2047
static const char *
 
2048
_align2string(enum printFormat in)
 
2049
{
 
2050
        switch (in)
 
2051
        {
 
2052
                case PRINT_NOTHING:
 
2053
                        return "nothing";
 
2054
                        break;
 
2055
                case PRINT_UNALIGNED:
 
2056
                        return "unaligned";
 
2057
                        break;
 
2058
                case PRINT_ALIGNED:
 
2059
                        return "aligned";
 
2060
                        break;
 
2061
                case PRINT_WRAPPED:
 
2062
                        return "wrapped";
 
2063
                        break;
 
2064
                case PRINT_HTML:
 
2065
                        return "html";
 
2066
                        break;
 
2067
                case PRINT_LATEX:
 
2068
                        return "latex";
 
2069
                        break;
 
2070
                case PRINT_TROFF_MS:
 
2071
                        return "troff-ms";
 
2072
                        break;
 
2073
        }
 
2074
        return "unknown";
 
2075
}
 
2076
 
 
2077
 
 
2078
bool
 
2079
do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 
2080
{
 
2081
        size_t          vallen = 0;
 
2082
 
 
2083
        psql_assert(param);
 
2084
 
 
2085
        if (value)
 
2086
                vallen = strlen(value);
 
2087
 
 
2088
        /* set format */
 
2089
        if (strcmp(param, "format") == 0)
 
2090
        {
 
2091
                if (!value)
 
2092
                        ;
 
2093
                else if (pg_strncasecmp("unaligned", value, vallen) == 0)
 
2094
                        popt->topt.format = PRINT_UNALIGNED;
 
2095
                else if (pg_strncasecmp("aligned", value, vallen) == 0)
 
2096
                        popt->topt.format = PRINT_ALIGNED;
 
2097
                else if (pg_strncasecmp("wrapped", value, vallen) == 0)
 
2098
                        popt->topt.format = PRINT_WRAPPED;
 
2099
                else if (pg_strncasecmp("html", value, vallen) == 0)
 
2100
                        popt->topt.format = PRINT_HTML;
 
2101
                else if (pg_strncasecmp("latex", value, vallen) == 0)
 
2102
                        popt->topt.format = PRINT_LATEX;
 
2103
                else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
 
2104
                        popt->topt.format = PRINT_TROFF_MS;
 
2105
                else
 
2106
                {
 
2107
                        psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n");
 
2108
                        return false;
 
2109
                }
 
2110
 
 
2111
                if (!quiet)
 
2112
                        printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
 
2113
        }
 
2114
 
 
2115
        /* set table line style */
 
2116
        else if (strcmp(param, "linestyle") == 0)
 
2117
        {
 
2118
                if (!value)
 
2119
                        ;
 
2120
                else if (pg_strncasecmp("ascii", value, vallen) == 0)
 
2121
                        popt->topt.line_style = &pg_asciiformat;
 
2122
                else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
 
2123
                        popt->topt.line_style = &pg_asciiformat_old;
 
2124
                else if (pg_strncasecmp("unicode", value, vallen) == 0)
 
2125
                        popt->topt.line_style = &pg_utf8format;
 
2126
                else
 
2127
                {
 
2128
                        psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
 
2129
                        return false;
 
2130
                }
 
2131
 
 
2132
                if (!quiet)
 
2133
                        printf(_("Line style is %s.\n"),
 
2134
                                   get_line_style(&popt->topt)->name);
 
2135
        }
 
2136
 
 
2137
        /* set border style/width */
 
2138
        else if (strcmp(param, "border") == 0)
 
2139
        {
 
2140
                if (value)
 
2141
                        popt->topt.border = atoi(value);
 
2142
 
 
2143
                if (!quiet)
 
2144
                        printf(_("Border style is %d.\n"), popt->topt.border);
 
2145
        }
 
2146
 
 
2147
        /* set expanded/vertical mode */
 
2148
        else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
 
2149
        {
 
2150
                if (value)
 
2151
                        popt->topt.expanded = ParseVariableBool(value);
 
2152
                else
 
2153
                        popt->topt.expanded = !popt->topt.expanded;
 
2154
                if (!quiet)
 
2155
                        printf(popt->topt.expanded
 
2156
                                   ? _("Expanded display is on.\n")
 
2157
                                   : _("Expanded display is off.\n"));
 
2158
        }
 
2159
 
 
2160
        /* locale-aware numeric output */
 
2161
        else if (strcmp(param, "numericlocale") == 0)
 
2162
        {
 
2163
                if (value)
 
2164
                        popt->topt.numericLocale = ParseVariableBool(value);
 
2165
                else
 
2166
                        popt->topt.numericLocale = !popt->topt.numericLocale;
 
2167
                if (!quiet)
 
2168
                {
 
2169
                        if (popt->topt.numericLocale)
 
2170
                                puts(_("Showing locale-adjusted numeric output."));
 
2171
                        else
 
2172
                                puts(_("Locale-adjusted numeric output is off."));
 
2173
                }
 
2174
        }
 
2175
 
 
2176
        /* null display */
 
2177
        else if (strcmp(param, "null") == 0)
 
2178
        {
 
2179
                if (value)
 
2180
                {
 
2181
                        free(popt->nullPrint);
 
2182
                        popt->nullPrint = pg_strdup(value);
 
2183
                }
 
2184
                if (!quiet)
 
2185
                        printf(_("Null display is \"%s\".\n"), popt->nullPrint ? popt->nullPrint : "");
 
2186
        }
 
2187
 
 
2188
        /* field separator for unaligned text */
 
2189
        else if (strcmp(param, "fieldsep") == 0)
 
2190
        {
 
2191
                if (value)
 
2192
                {
 
2193
                        free(popt->topt.fieldSep);
 
2194
                        popt->topt.fieldSep = pg_strdup(value);
 
2195
                }
 
2196
                if (!quiet)
 
2197
                        printf(_("Field separator is \"%s\".\n"), popt->topt.fieldSep);
 
2198
        }
 
2199
 
 
2200
        /* record separator for unaligned text */
 
2201
        else if (strcmp(param, "recordsep") == 0)
 
2202
        {
 
2203
                if (value)
 
2204
                {
 
2205
                        free(popt->topt.recordSep);
 
2206
                        popt->topt.recordSep = pg_strdup(value);
 
2207
                }
 
2208
                if (!quiet)
 
2209
                {
 
2210
                        if (strcmp(popt->topt.recordSep, "\n") == 0)
 
2211
                                printf(_("Record separator is <newline>."));
 
2212
                        else
 
2213
                                printf(_("Record separator is \"%s\".\n"), popt->topt.recordSep);
 
2214
                }
 
2215
        }
 
2216
 
 
2217
        /* toggle between full and tuples-only format */
 
2218
        else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
 
2219
        {
 
2220
                if (value)
 
2221
                        popt->topt.tuples_only = ParseVariableBool(value);
 
2222
                else
 
2223
                        popt->topt.tuples_only = !popt->topt.tuples_only;
 
2224
                if (!quiet)
 
2225
                {
 
2226
                        if (popt->topt.tuples_only)
 
2227
                                puts(_("Showing only tuples."));
 
2228
                        else
 
2229
                                puts(_("Tuples only is off."));
 
2230
                }
 
2231
        }
 
2232
 
 
2233
        /* set title override */
 
2234
        else if (strcmp(param, "title") == 0)
 
2235
        {
 
2236
                free(popt->title);
 
2237
                if (!value)
 
2238
                        popt->title = NULL;
 
2239
                else
 
2240
                        popt->title = pg_strdup(value);
 
2241
 
 
2242
                if (!quiet)
 
2243
                {
 
2244
                        if (popt->title)
 
2245
                                printf(_("Title is \"%s\".\n"), popt->title);
 
2246
                        else
 
2247
                                printf(_("Title is unset.\n"));
 
2248
                }
 
2249
        }
 
2250
 
 
2251
        /* set HTML table tag options */
 
2252
        else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
 
2253
        {
 
2254
                free(popt->topt.tableAttr);
 
2255
                if (!value)
 
2256
                        popt->topt.tableAttr = NULL;
 
2257
                else
 
2258
                        popt->topt.tableAttr = pg_strdup(value);
 
2259
 
 
2260
                if (!quiet)
 
2261
                {
 
2262
                        if (popt->topt.tableAttr)
 
2263
                                printf(_("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
 
2264
                        else
 
2265
                                printf(_("Table attributes unset.\n"));
 
2266
                }
 
2267
        }
 
2268
 
 
2269
        /* toggle use of pager */
 
2270
        else if (strcmp(param, "pager") == 0)
 
2271
        {
 
2272
                if (value && pg_strcasecmp(value, "always") == 0)
 
2273
                        popt->topt.pager = 2;
 
2274
                else if (value)
 
2275
                        if (ParseVariableBool(value))
 
2276
                                popt->topt.pager = 1;
 
2277
                        else
 
2278
                                popt->topt.pager = 0;
 
2279
                else if (popt->topt.pager == 1)
 
2280
                        popt->topt.pager = 0;
 
2281
                else
 
2282
                        popt->topt.pager = 1;
 
2283
                if (!quiet)
 
2284
                {
 
2285
                        if (popt->topt.pager == 1)
 
2286
                                puts(_("Pager is used for long output."));
 
2287
                        else if (popt->topt.pager == 2)
 
2288
                                puts(_("Pager is always used."));
 
2289
                        else
 
2290
                                puts(_("Pager usage is off."));
 
2291
                }
 
2292
        }
 
2293
 
 
2294
        /* disable "(x rows)" footer */
 
2295
        else if (strcmp(param, "footer") == 0)
 
2296
        {
 
2297
                if (value)
 
2298
                        popt->default_footer = ParseVariableBool(value);
 
2299
                else
 
2300
                        popt->default_footer = !popt->default_footer;
 
2301
                if (!quiet)
 
2302
                {
 
2303
                        if (popt->default_footer)
 
2304
                                puts(_("Default footer is on."));
 
2305
                        else
 
2306
                                puts(_("Default footer is off."));
 
2307
                }
 
2308
        }
 
2309
 
 
2310
        /* set border style/width */
 
2311
        else if (strcmp(param, "columns") == 0)
 
2312
        {
 
2313
                if (value)
 
2314
                        popt->topt.columns = atoi(value);
 
2315
 
 
2316
                if (!quiet)
 
2317
                        printf(_("Target width for \"wrapped\" format is %d.\n"), popt->topt.columns);
 
2318
        }
 
2319
 
 
2320
        else
 
2321
        {
 
2322
                psql_error("\\pset: unknown option: %s\n", param);
 
2323
                return false;
 
2324
        }
 
2325
 
 
2326
        return true;
 
2327
}
 
2328
 
 
2329
 
 
2330
 
 
2331
#ifndef WIN32
 
2332
#define DEFAULT_SHELL "/bin/sh"
 
2333
#else
 
2334
/*
 
2335
 *      CMD.EXE is in different places in different Win32 releases so we
 
2336
 *      have to rely on the path to find it.
 
2337
 */
 
2338
#define DEFAULT_SHELL "cmd.exe"
 
2339
#endif
 
2340
 
 
2341
static bool
 
2342
do_shell(const char *command)
 
2343
{
 
2344
        int                     result;
 
2345
 
 
2346
        if (!command)
 
2347
        {
 
2348
                char       *sys;
 
2349
                const char *shellName;
 
2350
 
 
2351
                shellName = getenv("SHELL");
 
2352
#ifdef WIN32
 
2353
                if (shellName == NULL)
 
2354
                        shellName = getenv("COMSPEC");
 
2355
#endif
 
2356
                if (shellName == NULL)
 
2357
                        shellName = DEFAULT_SHELL;
 
2358
 
 
2359
                sys = pg_malloc(strlen(shellName) + 16);
 
2360
#ifndef WIN32
 
2361
                sprintf(sys,
 
2362
                /* See EDITOR handling comment for an explaination */
 
2363
                                "exec %s", shellName);
 
2364
#else
 
2365
                /* See EDITOR handling comment for an explaination */
 
2366
                sprintf(sys, SYSTEMQUOTE "\"%s\"" SYSTEMQUOTE, shellName);
 
2367
#endif
 
2368
                result = system(sys);
 
2369
                free(sys);
 
2370
        }
 
2371
        else
 
2372
                result = system(command);
 
2373
 
 
2374
        if (result == 127 || result == -1)
 
2375
        {
 
2376
                psql_error("\\!: failed\n");
 
2377
                return false;
 
2378
        }
 
2379
        return true;
 
2380
}
 
2381
 
 
2382
/*
 
2383
 * This function takes a function description, e.g. "x" or "x(int)", and
 
2384
 * issues a query on the given connection to retrieve the function's OID
 
2385
 * using a cast to regproc or regprocedure (as appropriate). The result,
 
2386
 * if there is one, is returned at *foid.  Note that we'll fail if the
 
2387
 * function doesn't exist OR if there are multiple matching candidates
 
2388
 * OR if there's something syntactically wrong with the function description;
 
2389
 * unfortunately it can be hard to tell the difference.
 
2390
 */
 
2391
static bool
 
2392
lookup_function_oid(PGconn *conn, const char *desc, Oid *foid)
 
2393
{
 
2394
        bool            result = true;
 
2395
        PQExpBuffer query;
 
2396
        PGresult   *res;
 
2397
 
 
2398
        query = createPQExpBuffer();
 
2399
        printfPQExpBuffer(query, "SELECT ");
 
2400
        appendStringLiteralConn(query, desc, conn);
 
2401
        appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
 
2402
                                          strchr(desc, '(') ? "regprocedure" : "regproc");
 
2403
 
 
2404
        res = PQexec(conn, query->data);
 
2405
        if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
 
2406
                *foid = atooid(PQgetvalue(res, 0, 0));
 
2407
        else
 
2408
        {
 
2409
                minimal_error_message(res);
 
2410
                result = false;
 
2411
        }
 
2412
 
 
2413
        PQclear(res);
 
2414
        destroyPQExpBuffer(query);
 
2415
 
 
2416
        return result;
 
2417
}
 
2418
 
 
2419
/*
 
2420
 * Fetches the "CREATE OR REPLACE FUNCTION ..." command that describes the
 
2421
 * function with the given OID.  If successful, the result is stored in buf.
 
2422
 */
 
2423
static bool
 
2424
get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf)
 
2425
{
 
2426
        bool            result = true;
 
2427
        PQExpBuffer query;
 
2428
        PGresult   *res;
 
2429
 
 
2430
        query = createPQExpBuffer();
 
2431
        printfPQExpBuffer(query, "SELECT pg_catalog.pg_get_functiondef(%u)", oid);
 
2432
 
 
2433
        res = PQexec(conn, query->data);
 
2434
        if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
 
2435
        {
 
2436
                resetPQExpBuffer(buf);
 
2437
                appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
 
2438
        }
 
2439
        else
 
2440
        {
 
2441
                minimal_error_message(res);
 
2442
                result = false;
 
2443
        }
 
2444
 
 
2445
        PQclear(res);
 
2446
        destroyPQExpBuffer(query);
 
2447
 
 
2448
        return result;
 
2449
}
 
2450
 
 
2451
/*
 
2452
 * If the given argument of \ef ends with a line number, delete the line
 
2453
 * number from the argument string and return it as an integer.  (We need
 
2454
 * this kluge because we're too lazy to parse \ef's function name argument
 
2455
 * carefully --- we just slop it up in OT_WHOLE_LINE mode.)
 
2456
 *
 
2457
 * Returns -1 if no line number is present, 0 on error, or a positive value
 
2458
 * on success.
 
2459
 */
 
2460
static int
 
2461
strip_lineno_from_funcdesc(char *func)
 
2462
{
 
2463
        char       *c;
 
2464
        int                     lineno;
 
2465
 
 
2466
        if (!func || func[0] == '\0')
 
2467
                return -1;
 
2468
 
 
2469
        c = func + strlen(func) - 1;
 
2470
 
 
2471
        /*
 
2472
         * This business of parsing backwards is dangerous as can be in a
 
2473
         * multibyte environment: there is no reason to believe that we are
 
2474
         * looking at the first byte of a character, nor are we necessarily
 
2475
         * working in a "safe" encoding.  Fortunately the bitpatterns we are
 
2476
         * looking for are unlikely to occur as non-first bytes, but beware of
 
2477
         * trying to expand the set of cases that can be recognized.  We must
 
2478
         * guard the <ctype.h> macros by using isascii() first, too.
 
2479
         */
 
2480
 
 
2481
        /* skip trailing whitespace */
 
2482
        while (c > func && isascii((unsigned char) *c) && isspace((unsigned char) *c))
 
2483
                c--;
 
2484
 
 
2485
        /* must have a digit as last non-space char */
 
2486
        if (c == func || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
 
2487
                return -1;
 
2488
 
 
2489
        /* find start of digit string */
 
2490
        while (c > func && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
 
2491
                c--;
 
2492
 
 
2493
        /* digits must be separated from func name by space or closing paren */
 
2494
        /* notice also that we are not allowing an empty func name ... */
 
2495
        if (c == func || !isascii((unsigned char) *c) ||
 
2496
                !(isspace((unsigned char) *c) || *c == ')'))
 
2497
                return -1;
 
2498
 
 
2499
        /* parse digit string */
 
2500
        c++;
 
2501
        lineno = atoi(c);
 
2502
        if (lineno < 1)
 
2503
        {
 
2504
                psql_error("invalid line number: %s\n", c);
 
2505
                return 0;
 
2506
        }
 
2507
 
 
2508
        /* strip digit string from func */
 
2509
        *c = '\0';
 
2510
 
 
2511
        return lineno;
 
2512
}
 
2513
 
 
2514
/*
 
2515
 * Report just the primary error; this is to avoid cluttering the output
 
2516
 * with, for instance, a redisplay of the internally generated query
 
2517
 */
 
2518
static void
 
2519
minimal_error_message(PGresult *res)
 
2520
{
 
2521
        PQExpBuffer msg;
 
2522
        const char *fld;
 
2523
 
 
2524
        msg = createPQExpBuffer();
 
2525
 
 
2526
        fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
 
2527
        if (fld)
 
2528
                printfPQExpBuffer(msg, "%s:  ", fld);
 
2529
        else
 
2530
                printfPQExpBuffer(msg, "ERROR:  ");
 
2531
        fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
 
2532
        if (fld)
 
2533
                appendPQExpBufferStr(msg, fld);
 
2534
        else
 
2535
                appendPQExpBufferStr(msg, "(not available)");
 
2536
        appendPQExpBufferStr(msg, "\n");
 
2537
 
 
2538
        psql_error("%s", msg->data);
 
2539
 
 
2540
        destroyPQExpBuffer(msg);
 
2541
}