Thanks to visit codestin.com
Credit goes to github.com

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)