Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 87e8014

Browse files
committed
Respond to Jeremy Drake's original gripe that \copy needs to recognize
E'...' syntax for strings in order to track the backend.
1 parent 6178762 commit 87e8014

File tree

3 files changed

+75
-78
lines changed

3 files changed

+75
-78
lines changed

src/bin/psql/copy.c

Lines changed: 52 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.63 2006/06/01 00:15:36 tgl Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.64 2006/06/01 01:28:00 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "copy.h"
@@ -127,23 +127,23 @@ parse_slash_copy(const char *args)
127127
result = pg_calloc(1, sizeof(struct copy_options));
128128

129129
token = strtokx(line, whitespace, ".,()", "\"",
130-
0, false, pset.encoding);
130+
0, false, false, pset.encoding);
131131
if (!token)
132132
goto error;
133133

134134
if (pg_strcasecmp(token, "binary") == 0)
135135
{
136136
result->binary = true;
137137
token = strtokx(NULL, whitespace, ".,()", "\"",
138-
0, false, pset.encoding);
138+
0, false, false, pset.encoding);
139139
if (!token)
140140
goto error;
141141
}
142142

143143
result->table = pg_strdup(token);
144144

145145
token = strtokx(NULL, whitespace, ".,()", "\"",
146-
0, false, pset.encoding);
146+
0, false, false, pset.encoding);
147147
if (!token)
148148
goto error;
149149

@@ -156,12 +156,12 @@ parse_slash_copy(const char *args)
156156
/* handle schema . table */
157157
xstrcat(&result->table, token);
158158
token = strtokx(NULL, whitespace, ".,()", "\"",
159-
0, false, pset.encoding);
159+
0, false, false, pset.encoding);
160160
if (!token)
161161
goto error;
162162
xstrcat(&result->table, token);
163163
token = strtokx(NULL, whitespace, ".,()", "\"",
164-
0, false, pset.encoding);
164+
0, false, false, pset.encoding);
165165
if (!token)
166166
goto error;
167167
}
@@ -173,12 +173,12 @@ parse_slash_copy(const char *args)
173173
for (;;)
174174
{
175175
token = strtokx(NULL, whitespace, ".,()", "\"",
176-
0, false, pset.encoding);
176+
0, false, false, pset.encoding);
177177
if (!token || strchr(".,()", token[0]))
178178
goto error;
179179
xstrcat(&result->column_list, token);
180180
token = strtokx(NULL, whitespace, ".,()", "\"",
181-
0, false, pset.encoding);
181+
0, false, false, pset.encoding);
182182
if (!token)
183183
goto error;
184184
xstrcat(&result->column_list, token);
@@ -188,7 +188,7 @@ parse_slash_copy(const char *args)
188188
goto error;
189189
}
190190
token = strtokx(NULL, whitespace, ".,()", "\"",
191-
0, false, pset.encoding);
191+
0, false, false, pset.encoding);
192192
if (!token)
193193
goto error;
194194
}
@@ -199,13 +199,13 @@ parse_slash_copy(const char *args)
199199
if (pg_strcasecmp(token, "with") == 0)
200200
{
201201
token = strtokx(NULL, whitespace, NULL, NULL,
202-
0, false, pset.encoding);
202+
0, false, false, pset.encoding);
203203
if (!token || pg_strcasecmp(token, "oids") != 0)
204204
goto error;
205205
result->oids = true;
206206

207207
token = strtokx(NULL, whitespace, NULL, NULL,
208-
0, false, pset.encoding);
208+
0, false, false, pset.encoding);
209209
if (!token)
210210
goto error;
211211
}
@@ -218,7 +218,7 @@ parse_slash_copy(const char *args)
218218
goto error;
219219

220220
token = strtokx(NULL, whitespace, NULL, "'",
221-
nonstd_backslash, true, pset.encoding);
221+
0, false, true, pset.encoding);
222222
if (!token)
223223
goto error;
224224

@@ -242,27 +242,27 @@ parse_slash_copy(const char *args)
242242
}
243243

244244
token = strtokx(NULL, whitespace, NULL, NULL,
245-
0, false, pset.encoding);
245+
0, false, false, pset.encoding);
246246

247247
/*
248248
* Allows old COPY syntax for backward compatibility 2002-06-19
249249
*/
250250
if (token && pg_strcasecmp(token, "using") == 0)
251251
{
252252
token = strtokx(NULL, whitespace, NULL, NULL,
253-
0, false, pset.encoding);
253+
0, false, false, pset.encoding);
254254
if (!(token && pg_strcasecmp(token, "delimiters") == 0))
255255
goto error;
256256
}
257257
if (token && pg_strcasecmp(token, "delimiters") == 0)
258258
{
259259
token = strtokx(NULL, whitespace, NULL, "'",
260-
nonstd_backslash, false, pset.encoding);
260+
nonstd_backslash, true, false, pset.encoding);
261261
if (!token)
262262
goto error;
263263
result->delim = pg_strdup(token);
264264
token = strtokx(NULL, whitespace, NULL, NULL,
265-
0, false, pset.encoding);
265+
0, false, false, pset.encoding);
266266
}
267267

268268
if (token)
@@ -273,7 +273,7 @@ parse_slash_copy(const char *args)
273273
*/
274274
if (pg_strcasecmp(token, "with") == 0)
275275
token = strtokx(NULL, whitespace, NULL, NULL,
276-
0, false, pset.encoding);
276+
0, false, false, pset.encoding);
277277

278278
while (token)
279279
{
@@ -292,10 +292,10 @@ parse_slash_copy(const char *args)
292292
else if (pg_strcasecmp(token, "delimiter") == 0)
293293
{
294294
token = strtokx(NULL, whitespace, NULL, "'",
295-
nonstd_backslash, false, pset.encoding);
295+
nonstd_backslash, true, false, pset.encoding);
296296
if (token && pg_strcasecmp(token, "as") == 0)
297297
token = strtokx(NULL, whitespace, NULL, "'",
298-
nonstd_backslash, false, pset.encoding);
298+
nonstd_backslash, true, false, pset.encoding);
299299
if (token)
300300
result->delim = pg_strdup(token);
301301
else
@@ -304,10 +304,10 @@ parse_slash_copy(const char *args)
304304
else if (pg_strcasecmp(token, "null") == 0)
305305
{
306306
token = strtokx(NULL, whitespace, NULL, "'",
307-
nonstd_backslash, false, pset.encoding);
307+
nonstd_backslash, true, false, pset.encoding);
308308
if (token && pg_strcasecmp(token, "as") == 0)
309309
token = strtokx(NULL, whitespace, NULL, "'",
310-
nonstd_backslash, false, pset.encoding);
310+
nonstd_backslash, true, false, pset.encoding);
311311
if (token)
312312
result->null = pg_strdup(token);
313313
else
@@ -316,10 +316,10 @@ parse_slash_copy(const char *args)
316316
else if (pg_strcasecmp(token, "quote") == 0)
317317
{
318318
token = strtokx(NULL, whitespace, NULL, "'",
319-
nonstd_backslash, false, pset.encoding);
319+
nonstd_backslash, true, false, pset.encoding);
320320
if (token && pg_strcasecmp(token, "as") == 0)
321321
token = strtokx(NULL, whitespace, NULL, "'",
322-
nonstd_backslash, false, pset.encoding);
322+
nonstd_backslash, true, false, pset.encoding);
323323
if (token)
324324
result->quote = pg_strdup(token);
325325
else
@@ -328,10 +328,10 @@ parse_slash_copy(const char *args)
328328
else if (pg_strcasecmp(token, "escape") == 0)
329329
{
330330
token = strtokx(NULL, whitespace, NULL, "'",
331-
nonstd_backslash, false, pset.encoding);
331+
nonstd_backslash, true, false, pset.encoding);
332332
if (token && pg_strcasecmp(token, "as") == 0)
333333
token = strtokx(NULL, whitespace, NULL, "'",
334-
nonstd_backslash, false, pset.encoding);
334+
nonstd_backslash, true, false, pset.encoding);
335335
if (token)
336336
result->escape = pg_strdup(token);
337337
else
@@ -340,23 +340,23 @@ parse_slash_copy(const char *args)
340340
else if (pg_strcasecmp(token, "force") == 0)
341341
{
342342
token = strtokx(NULL, whitespace, ",", "\"",
343-
0, false, pset.encoding);
343+
0, false, false, pset.encoding);
344344
if (pg_strcasecmp(token, "quote") == 0)
345345
{
346346
/* handle column list */
347347
fetch_next = false;
348348
for (;;)
349349
{
350350
token = strtokx(NULL, whitespace, ",", "\"",
351-
0, false, pset.encoding);
351+
0, false, false, pset.encoding);
352352
if (!token || strchr(",", token[0]))
353353
goto error;
354354
if (!result->force_quote_list)
355355
result->force_quote_list = pg_strdup(token);
356356
else
357357
xstrcat(&result->force_quote_list, token);
358358
token = strtokx(NULL, whitespace, ",", "\"",
359-
0, false, pset.encoding);
359+
0, false, false, pset.encoding);
360360
if (!token || token[0] != ',')
361361
break;
362362
xstrcat(&result->force_quote_list, token);
@@ -365,23 +365,23 @@ parse_slash_copy(const char *args)
365365
else if (pg_strcasecmp(token, "not") == 0)
366366
{
367367
token = strtokx(NULL, whitespace, ",", "\"",
368-
0, false, pset.encoding);
368+
0, false, false, pset.encoding);
369369
if (pg_strcasecmp(token, "null") != 0)
370370
goto error;
371371
/* handle column list */
372372
fetch_next = false;
373373
for (;;)
374374
{
375375
token = strtokx(NULL, whitespace, ",", "\"",
376-
0, false, pset.encoding);
376+
0, false, false, pset.encoding);
377377
if (!token || strchr(",", token[0]))
378378
goto error;
379379
if (!result->force_notnull_list)
380380
result->force_notnull_list = pg_strdup(token);
381381
else
382382
xstrcat(&result->force_notnull_list, token);
383383
token = strtokx(NULL, whitespace, ",", "\"",
384-
0, false, pset.encoding);
384+
0, false, false, pset.encoding);
385385
if (!token || token[0] != ',')
386386
break;
387387
xstrcat(&result->force_notnull_list, token);
@@ -395,7 +395,7 @@ parse_slash_copy(const char *args)
395395

396396
if (fetch_next)
397397
token = strtokx(NULL, whitespace, NULL, NULL,
398-
0, false, pset.encoding);
398+
0, false, false, pset.encoding);
399399
}
400400
}
401401

@@ -415,6 +415,22 @@ parse_slash_copy(const char *args)
415415
}
416416

417417

418+
/*
419+
* Handle one of the "string" options of COPY. If the user gave a quoted
420+
* string, pass it to the backend as-is; if it wasn't quoted then quote
421+
* and escape it.
422+
*/
423+
static void
424+
emit_copy_option(PQExpBuffer query, const char *keyword, const char *option)
425+
{
426+
appendPQExpBufferStr(query, keyword);
427+
if (option[0] == '\'' ||
428+
((option[0] == 'E' || option[0] == 'e') && option[1] == '\''))
429+
appendPQExpBufferStr(query, option);
430+
else
431+
appendStringLiteralConn(query, option, pset.db);
432+
}
433+
418434

419435
/*
420436
* Execute a \copy command (frontend copy). We have to open a file, then
@@ -462,29 +478,11 @@ do_copy(const char *args)
462478

463479
/* Uses old COPY syntax for backward compatibility 2002-06-19 */
464480
if (options->delim)
465-
{
466-
/* if user gave a quoted string, use it as-is */
467-
if (options->delim[0] == '\'')
468-
appendPQExpBuffer(&query, " USING DELIMITERS %s", options->delim);
469-
else
470-
{
471-
appendPQExpBuffer(&query, " USING DELIMITERS ");
472-
appendStringLiteralConn(&query, options->delim, pset.db);
473-
}
474-
}
481+
emit_copy_option(&query, " USING DELIMITERS ", options->delim);
475482

476483
/* There is no backward-compatible CSV syntax */
477484
if (options->null)
478-
{
479-
/* if user gave a quoted string, use it as-is */
480-
if (options->null[0] == '\'')
481-
appendPQExpBuffer(&query, " WITH NULL AS %s", options->null);
482-
else
483-
{
484-
appendPQExpBuffer(&query, " WITH NULL AS ");
485-
appendStringLiteralConn(&query, options->null, pset.db);
486-
}
487-
}
485+
emit_copy_option(&query, " WITH NULL AS ", options->null);
488486

489487
if (options->csv_mode)
490488
appendPQExpBuffer(&query, " CSV");
@@ -493,28 +491,10 @@ do_copy(const char *args)
493491
appendPQExpBuffer(&query, " HEADER");
494492

495493
if (options->quote)
496-
{
497-
/* if user gave a quoted string, use it as-is */
498-
if (options->quote[0] == '\'')
499-
appendPQExpBuffer(&query, " QUOTE AS %s", options->quote);
500-
else
501-
{
502-
appendPQExpBuffer(&query, " QUOTE AS ");
503-
appendStringLiteralConn(&query, options->quote, pset.db);
504-
}
505-
}
494+
emit_copy_option(&query, " QUOTE AS ", options->quote);
506495

507496
if (options->escape)
508-
{
509-
/* if user gave a quoted string, use it as-is */
510-
if (options->escape[0] == '\'')
511-
appendPQExpBuffer(&query, " ESCAPE AS %s", options->escape);
512-
else
513-
{
514-
appendPQExpBuffer(&query, " ESCAPE AS ");
515-
appendStringLiteralConn(&query, options->escape, pset.db);
516-
}
517-
}
497+
emit_copy_option(&query, " ESCAPE AS ", options->escape);
518498

519499
if (options->force_quote_list)
520500
appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list);

0 commit comments

Comments
 (0)