~ubuntu-branches/ubuntu/lucid/postgresql-8.4/lucid-security

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * psql - the PostgreSQL interactive terminal
 
3
 *
 
4
 * Copyright (c) 2000-2009, PostgreSQL Global Development Group
 
5
 *
 
6
 * $PostgreSQL$
 
7
 */
 
8
#include "postgres_fe.h"
 
9
 
 
10
#include "input.h"
 
11
#include "settings.h"
 
12
#include "tab-complete.h"
 
13
#include "common.h"
 
14
 
 
15
#ifndef WIN32
 
16
#define PSQLHISTORY ".psql_history"
 
17
#else
 
18
#define PSQLHISTORY "psql_history"
 
19
#endif
 
20
 
 
21
/* Runtime options for turning off readline and history */
 
22
/* (of course there is no runtime command for doing that :) */
 
23
#ifdef USE_READLINE
 
24
static bool useReadline;
 
25
static bool useHistory;
 
26
char       *psql_history;
 
27
 
 
28
/*
 
29
 *      Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
 
30
 *
 
31
 *      It is assumed NL_IN_HISTORY will never be entered by the user
 
32
 *      nor appear inside a multi-byte string.  0x00 is not properly
 
33
 *      handled by the readline routines so it can not be used
 
34
 *      for this purpose.
 
35
 */
 
36
#define NL_IN_HISTORY   0x01
 
37
#endif
 
38
 
 
39
#ifdef HAVE_ATEXIT
 
40
static void finishInput(void);
 
41
#else
 
42
/* designed for use with on_exit() */
 
43
static void finishInput(int, void *);
 
44
#endif
 
45
 
 
46
 
 
47
/*
 
48
 * gets_interactive()
 
49
 *
 
50
 * Gets a line of interactive input, using readline if desired.
 
51
 * The result is a malloc'd string.
 
52
 *
 
53
 * Caller *must* have set up sigint_interrupt_jmp before calling.
 
54
 */
 
55
char *
 
56
gets_interactive(const char *prompt)
 
57
{
 
58
#ifdef USE_READLINE
 
59
        if (useReadline)
 
60
        {
 
61
                char       *result;
 
62
 
 
63
                /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
 
64
                sigint_interrupt_enabled = true;
 
65
 
 
66
                /* On some platforms, readline is declared as readline(char *) */
 
67
                result = readline((char *) prompt);
 
68
 
 
69
                /* Disable SIGINT again */
 
70
                sigint_interrupt_enabled = false;
 
71
 
 
72
                return result;
 
73
        }
 
74
#endif
 
75
 
 
76
        fputs(prompt, stdout);
 
77
        fflush(stdout);
 
78
        return gets_fromFile(stdin);
 
79
}
 
80
 
 
81
 
 
82
/*
 
83
 * Append the line to the history buffer, making sure there is a trailing '\n'
 
84
 */
 
85
void
 
86
pg_append_history(const char *s, PQExpBuffer history_buf)
 
87
{
 
88
#ifdef USE_READLINE
 
89
        if (useHistory && s && s[0])
 
90
        {
 
91
                appendPQExpBufferStr(history_buf, s);
 
92
                if (s[strlen(s) - 1] != '\n')
 
93
                        appendPQExpBufferChar(history_buf, '\n');
 
94
        }
 
95
#endif
 
96
}
 
97
 
 
98
 
 
99
/*
 
100
 * Emit accumulated history entry to readline's history mechanism,
 
101
 * then reset the buffer to empty.
 
102
 *
 
103
 * Note: we write nothing if history_buf is empty, so extra calls to this
 
104
 * function don't hurt.  There must have been at least one line added by
 
105
 * pg_append_history before we'll do anything.
 
106
 */
 
107
void
 
108
pg_send_history(PQExpBuffer history_buf)
 
109
{
 
110
#ifdef USE_READLINE
 
111
        static char *prev_hist = NULL;
 
112
 
 
113
        char       *s = history_buf->data;
 
114
        int                     i;
 
115
 
 
116
        /* Trim any trailing \n's (OK to scribble on history_buf) */
 
117
        for (i = strlen(s) - 1; i >= 0 && s[i] == '\n'; i--)
 
118
                ;
 
119
        s[i + 1] = '\0';
 
120
 
 
121
        if (useHistory && s[0])
 
122
        {
 
123
                if (((pset.histcontrol & hctl_ignorespace) &&
 
124
                         s[0] == ' ') ||
 
125
                        ((pset.histcontrol & hctl_ignoredups) &&
 
126
                         prev_hist && strcmp(s, prev_hist) == 0))
 
127
                {
 
128
                        /* Ignore this line as far as history is concerned */
 
129
                }
 
130
                else
 
131
                {
 
132
                        /* Save each previous line for ignoredups processing */
 
133
                        if (prev_hist)
 
134
                                free(prev_hist);
 
135
                        prev_hist = pg_strdup(s);
 
136
                        /* And send it to readline */
 
137
                        add_history(s);
 
138
                }
 
139
        }
 
140
 
 
141
        resetPQExpBuffer(history_buf);
 
142
#endif
 
143
}
 
144
 
 
145
 
 
146
/*
 
147
 * gets_fromFile
 
148
 *
 
149
 * Gets a line of noninteractive input from a file (which could be stdin).
 
150
 * The result is a malloc'd string, or NULL on EOF or input error.
 
151
 *
 
152
 * Caller *must* have set up sigint_interrupt_jmp before calling.
 
153
 *
 
154
 * Note: we re-use a static PQExpBuffer for each call.  This is to avoid
 
155
 * leaking memory if interrupted by SIGINT.
 
156
 */
 
157
char *
 
158
gets_fromFile(FILE *source)
 
159
{
 
160
        static PQExpBuffer buffer = NULL;
 
161
 
 
162
        char            line[1024];
 
163
 
 
164
        if (buffer == NULL)                     /* first time through? */
 
165
                buffer = createPQExpBuffer();
 
166
        else
 
167
                resetPQExpBuffer(buffer);
 
168
 
 
169
        for (;;)
 
170
        {
 
171
                char       *result;
 
172
 
 
173
                /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
 
174
                sigint_interrupt_enabled = true;
 
175
 
 
176
                /* Get some data */
 
177
                result = fgets(line, sizeof(line), source);
 
178
 
 
179
                /* Disable SIGINT again */
 
180
                sigint_interrupt_enabled = false;
 
181
 
 
182
                /* EOF or error? */
 
183
                if (result == NULL)
 
184
                {
 
185
                        if (ferror(source))
 
186
                        {
 
187
                                psql_error("could not read from input file: %s\n",
 
188
                                                   strerror(errno));
 
189
                                return NULL;
 
190
                        }
 
191
                        break;
 
192
                }
 
193
 
 
194
                appendPQExpBufferStr(buffer, line);
 
195
 
 
196
                if (PQExpBufferBroken(buffer))
 
197
                {
 
198
                        psql_error("out of memory\n");
 
199
                        return NULL;
 
200
                }
 
201
 
 
202
                /* EOL? */
 
203
                if (buffer->data[buffer->len - 1] == '\n')
 
204
                {
 
205
                        buffer->data[buffer->len - 1] = '\0';
 
206
                        return pg_strdup(buffer->data);
 
207
                }
 
208
        }
 
209
 
 
210
        if (buffer->len > 0)            /* EOF after reading some bufferload(s) */
 
211
                return pg_strdup(buffer->data);
 
212
 
 
213
        /* EOF, so return null */
 
214
        return NULL;
 
215
}
 
216
 
 
217
 
 
218
#ifdef USE_READLINE
 
219
/*
 
220
 * Convert newlines to NL_IN_HISTORY for safe saving in readline history file
 
221
 */
 
222
static void
 
223
encode_history(void)
 
224
{
 
225
        HIST_ENTRY *cur_hist;
 
226
        char       *cur_ptr;
 
227
 
 
228
        history_set_pos(0);
 
229
        for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
 
230
        {
 
231
                /* some platforms declare HIST_ENTRY.line as const char * */
 
232
                for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
 
233
                        if (*cur_ptr == '\n')
 
234
                                *cur_ptr = NL_IN_HISTORY;
 
235
        }
 
236
}
 
237
 
 
238
/*
 
239
 * Reverse the above encoding
 
240
 */
 
241
static void
 
242
decode_history(void)
 
243
{
 
244
        HIST_ENTRY *cur_hist;
 
245
        char       *cur_ptr;
 
246
 
 
247
        history_set_pos(0);
 
248
        for (cur_hist = current_history(); cur_hist; cur_hist = next_history())
 
249
        {
 
250
                /* some platforms declare HIST_ENTRY.line as const char * */
 
251
                for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
 
252
                        if (*cur_ptr == NL_IN_HISTORY)
 
253
                                *cur_ptr = '\n';
 
254
        }
 
255
}
 
256
#endif   /* USE_READLINE */
 
257
 
 
258
 
 
259
/*
 
260
 * Put any startup stuff related to input in here. It's good to maintain
 
261
 * abstraction this way.
 
262
 *
 
263
 * The only "flag" right now is 1 for use readline & history.
 
264
 */
 
265
void
 
266
initializeInput(int flags)
 
267
{
 
268
#ifdef USE_READLINE
 
269
        if (flags & 1)
 
270
        {
 
271
                const char *histfile;
 
272
                char            home[MAXPGPATH];
 
273
 
 
274
                useReadline = true;
 
275
                initialize_readline();
 
276
 
 
277
                useHistory = true;
 
278
                using_history();
 
279
 
 
280
                histfile = GetVariable(pset.vars, "HISTFILE");
 
281
                if (histfile == NULL)
 
282
                {
 
283
                        if (get_home_path(home))
 
284
                        {
 
285
                                psql_history = pg_malloc(strlen(home) + 1 +
 
286
                                                                                 strlen(PSQLHISTORY) + 1);
 
287
                                snprintf(psql_history, MAXPGPATH, "%s/%s", home, PSQLHISTORY);
 
288
                        }
 
289
                }
 
290
                else
 
291
                {
 
292
                        psql_history = pg_strdup(histfile);
 
293
                        expand_tilde(&psql_history);
 
294
                }
 
295
 
 
296
                if (psql_history)
 
297
                {
 
298
                        read_history(psql_history);
 
299
                        decode_history();
 
300
                }
 
301
        }
 
302
#endif
 
303
 
 
304
#ifdef HAVE_ATEXIT
 
305
        atexit(finishInput);
 
306
#else
 
307
        on_exit(finishInput, NULL);
 
308
#endif
 
309
}
 
310
 
 
311
 
 
312
/*
 
313
 * This function is for saving the readline history when user
 
314
 * runs \s command or when psql finishes.
 
315
 *
 
316
 * We have an argument named encodeFlag to handle the cases differently.
 
317
 * In case of call via \s we don't really need to encode \n as \x01,
 
318
 * but when we save history for Readline we must do that conversion.
 
319
 */
 
320
bool
 
321
saveHistory(char *fname, bool encodeFlag)
 
322
{
 
323
#ifdef USE_READLINE
 
324
 
 
325
        /*
 
326
         * Suppressing the write attempt when HISTFILE is set to /dev/null may
 
327
         * look like a negligible optimization, but it's necessary on e.g. Darwin,
 
328
         * where write_history will fail because it tries to chmod the target
 
329
         * file.
 
330
         */
 
331
        if (useHistory && fname &&
 
332
                strcmp(fname, DEVNULL) != 0)
 
333
        {
 
334
                if (encodeFlag)
 
335
                        encode_history();
 
336
 
 
337
                /*
 
338
                 * return value of write_history is not standardized across GNU
 
339
                 * readline and libedit.  Therefore, check for errno becoming set to
 
340
                 * see if the write failed.
 
341
                 */
 
342
                errno = 0;
 
343
                (void) write_history(fname);
 
344
                if (errno == 0)
 
345
                        return true;
 
346
 
 
347
                psql_error("could not save history to file \"%s\": %s\n",
 
348
                                   fname, strerror(errno));
 
349
        }
 
350
#else
 
351
        /* only get here in \s case, so complain */
 
352
        psql_error("history is not supported by this installation\n");
 
353
#endif
 
354
 
 
355
        return false;
 
356
}
 
357
 
 
358
 
 
359
static void
 
360
#ifdef HAVE_ATEXIT
 
361
finishInput(void)
 
362
#else
 
363
finishInput(int exitstatus, void *arg)
 
364
#endif
 
365
{
 
366
#ifdef USE_READLINE
 
367
        if (useHistory && psql_history)
 
368
        {
 
369
                int                     hist_size;
 
370
 
 
371
                hist_size = GetVariableNum(pset.vars, "HISTSIZE", 500, -1, true);
 
372
                if (hist_size >= 0)
 
373
                        stifle_history(hist_size);
 
374
 
 
375
                saveHistory(psql_history, true);
 
376
                free(psql_history);
 
377
                psql_history = NULL;
 
378
        }
 
379
#endif
 
380
}