3
3
*
4
4
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
5
5
*
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 $
7
7
*/
8
8
#include "postgres_fe.h"
9
9
#include "copy.h"
@@ -127,23 +127,23 @@ parse_slash_copy(const char *args)
127
127
result = pg_calloc (1 , sizeof (struct copy_options ));
128
128
129
129
token = strtokx (line , whitespace , ".,()" , "\"" ,
130
- 0 , false, pset .encoding );
130
+ 0 , false, false, pset .encoding );
131
131
if (!token )
132
132
goto error ;
133
133
134
134
if (pg_strcasecmp (token , "binary" ) == 0 )
135
135
{
136
136
result -> binary = true;
137
137
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
138
- 0 , false, pset .encoding );
138
+ 0 , false, false, pset .encoding );
139
139
if (!token )
140
140
goto error ;
141
141
}
142
142
143
143
result -> table = pg_strdup (token );
144
144
145
145
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
146
- 0 , false, pset .encoding );
146
+ 0 , false, false, pset .encoding );
147
147
if (!token )
148
148
goto error ;
149
149
@@ -156,12 +156,12 @@ parse_slash_copy(const char *args)
156
156
/* handle schema . table */
157
157
xstrcat (& result -> table , token );
158
158
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
159
- 0 , false, pset .encoding );
159
+ 0 , false, false, pset .encoding );
160
160
if (!token )
161
161
goto error ;
162
162
xstrcat (& result -> table , token );
163
163
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
164
- 0 , false, pset .encoding );
164
+ 0 , false, false, pset .encoding );
165
165
if (!token )
166
166
goto error ;
167
167
}
@@ -173,12 +173,12 @@ parse_slash_copy(const char *args)
173
173
for (;;)
174
174
{
175
175
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
176
- 0 , false, pset .encoding );
176
+ 0 , false, false, pset .encoding );
177
177
if (!token || strchr (".,()" , token [0 ]))
178
178
goto error ;
179
179
xstrcat (& result -> column_list , token );
180
180
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
181
- 0 , false, pset .encoding );
181
+ 0 , false, false, pset .encoding );
182
182
if (!token )
183
183
goto error ;
184
184
xstrcat (& result -> column_list , token );
@@ -188,7 +188,7 @@ parse_slash_copy(const char *args)
188
188
goto error ;
189
189
}
190
190
token = strtokx (NULL , whitespace , ".,()" , "\"" ,
191
- 0 , false, pset .encoding );
191
+ 0 , false, false, pset .encoding );
192
192
if (!token )
193
193
goto error ;
194
194
}
@@ -199,13 +199,13 @@ parse_slash_copy(const char *args)
199
199
if (pg_strcasecmp (token , "with" ) == 0 )
200
200
{
201
201
token = strtokx (NULL , whitespace , NULL , NULL ,
202
- 0 , false, pset .encoding );
202
+ 0 , false, false, pset .encoding );
203
203
if (!token || pg_strcasecmp (token , "oids" ) != 0 )
204
204
goto error ;
205
205
result -> oids = true;
206
206
207
207
token = strtokx (NULL , whitespace , NULL , NULL ,
208
- 0 , false, pset .encoding );
208
+ 0 , false, false, pset .encoding );
209
209
if (!token )
210
210
goto error ;
211
211
}
@@ -218,7 +218,7 @@ parse_slash_copy(const char *args)
218
218
goto error ;
219
219
220
220
token = strtokx (NULL , whitespace , NULL , "'" ,
221
- nonstd_backslash , true, pset .encoding );
221
+ 0 , false , true, pset .encoding );
222
222
if (!token )
223
223
goto error ;
224
224
@@ -242,27 +242,27 @@ parse_slash_copy(const char *args)
242
242
}
243
243
244
244
token = strtokx (NULL , whitespace , NULL , NULL ,
245
- 0 , false, pset .encoding );
245
+ 0 , false, false, pset .encoding );
246
246
247
247
/*
248
248
* Allows old COPY syntax for backward compatibility 2002-06-19
249
249
*/
250
250
if (token && pg_strcasecmp (token , "using" ) == 0 )
251
251
{
252
252
token = strtokx (NULL , whitespace , NULL , NULL ,
253
- 0 , false, pset .encoding );
253
+ 0 , false, false, pset .encoding );
254
254
if (!(token && pg_strcasecmp (token , "delimiters" ) == 0 ))
255
255
goto error ;
256
256
}
257
257
if (token && pg_strcasecmp (token , "delimiters" ) == 0 )
258
258
{
259
259
token = strtokx (NULL , whitespace , NULL , "'" ,
260
- nonstd_backslash , false, pset .encoding );
260
+ nonstd_backslash , true, false, pset .encoding );
261
261
if (!token )
262
262
goto error ;
263
263
result -> delim = pg_strdup (token );
264
264
token = strtokx (NULL , whitespace , NULL , NULL ,
265
- 0 , false, pset .encoding );
265
+ 0 , false, false, pset .encoding );
266
266
}
267
267
268
268
if (token )
@@ -273,7 +273,7 @@ parse_slash_copy(const char *args)
273
273
*/
274
274
if (pg_strcasecmp (token , "with" ) == 0 )
275
275
token = strtokx (NULL , whitespace , NULL , NULL ,
276
- 0 , false, pset .encoding );
276
+ 0 , false, false, pset .encoding );
277
277
278
278
while (token )
279
279
{
@@ -292,10 +292,10 @@ parse_slash_copy(const char *args)
292
292
else if (pg_strcasecmp (token , "delimiter" ) == 0 )
293
293
{
294
294
token = strtokx (NULL , whitespace , NULL , "'" ,
295
- nonstd_backslash , false, pset .encoding );
295
+ nonstd_backslash , true, false, pset .encoding );
296
296
if (token && pg_strcasecmp (token , "as" ) == 0 )
297
297
token = strtokx (NULL , whitespace , NULL , "'" ,
298
- nonstd_backslash , false, pset .encoding );
298
+ nonstd_backslash , true, false, pset .encoding );
299
299
if (token )
300
300
result -> delim = pg_strdup (token );
301
301
else
@@ -304,10 +304,10 @@ parse_slash_copy(const char *args)
304
304
else if (pg_strcasecmp (token , "null" ) == 0 )
305
305
{
306
306
token = strtokx (NULL , whitespace , NULL , "'" ,
307
- nonstd_backslash , false, pset .encoding );
307
+ nonstd_backslash , true, false, pset .encoding );
308
308
if (token && pg_strcasecmp (token , "as" ) == 0 )
309
309
token = strtokx (NULL , whitespace , NULL , "'" ,
310
- nonstd_backslash , false, pset .encoding );
310
+ nonstd_backslash , true, false, pset .encoding );
311
311
if (token )
312
312
result -> null = pg_strdup (token );
313
313
else
@@ -316,10 +316,10 @@ parse_slash_copy(const char *args)
316
316
else if (pg_strcasecmp (token , "quote" ) == 0 )
317
317
{
318
318
token = strtokx (NULL , whitespace , NULL , "'" ,
319
- nonstd_backslash , false, pset .encoding );
319
+ nonstd_backslash , true, false, pset .encoding );
320
320
if (token && pg_strcasecmp (token , "as" ) == 0 )
321
321
token = strtokx (NULL , whitespace , NULL , "'" ,
322
- nonstd_backslash , false, pset .encoding );
322
+ nonstd_backslash , true, false, pset .encoding );
323
323
if (token )
324
324
result -> quote = pg_strdup (token );
325
325
else
@@ -328,10 +328,10 @@ parse_slash_copy(const char *args)
328
328
else if (pg_strcasecmp (token , "escape" ) == 0 )
329
329
{
330
330
token = strtokx (NULL , whitespace , NULL , "'" ,
331
- nonstd_backslash , false, pset .encoding );
331
+ nonstd_backslash , true, false, pset .encoding );
332
332
if (token && pg_strcasecmp (token , "as" ) == 0 )
333
333
token = strtokx (NULL , whitespace , NULL , "'" ,
334
- nonstd_backslash , false, pset .encoding );
334
+ nonstd_backslash , true, false, pset .encoding );
335
335
if (token )
336
336
result -> escape = pg_strdup (token );
337
337
else
@@ -340,23 +340,23 @@ parse_slash_copy(const char *args)
340
340
else if (pg_strcasecmp (token , "force" ) == 0 )
341
341
{
342
342
token = strtokx (NULL , whitespace , "," , "\"" ,
343
- 0 , false, pset .encoding );
343
+ 0 , false, false, pset .encoding );
344
344
if (pg_strcasecmp (token , "quote" ) == 0 )
345
345
{
346
346
/* handle column list */
347
347
fetch_next = false;
348
348
for (;;)
349
349
{
350
350
token = strtokx (NULL , whitespace , "," , "\"" ,
351
- 0 , false, pset .encoding );
351
+ 0 , false, false, pset .encoding );
352
352
if (!token || strchr ("," , token [0 ]))
353
353
goto error ;
354
354
if (!result -> force_quote_list )
355
355
result -> force_quote_list = pg_strdup (token );
356
356
else
357
357
xstrcat (& result -> force_quote_list , token );
358
358
token = strtokx (NULL , whitespace , "," , "\"" ,
359
- 0 , false, pset .encoding );
359
+ 0 , false, false, pset .encoding );
360
360
if (!token || token [0 ] != ',' )
361
361
break ;
362
362
xstrcat (& result -> force_quote_list , token );
@@ -365,23 +365,23 @@ parse_slash_copy(const char *args)
365
365
else if (pg_strcasecmp (token , "not" ) == 0 )
366
366
{
367
367
token = strtokx (NULL , whitespace , "," , "\"" ,
368
- 0 , false, pset .encoding );
368
+ 0 , false, false, pset .encoding );
369
369
if (pg_strcasecmp (token , "null" ) != 0 )
370
370
goto error ;
371
371
/* handle column list */
372
372
fetch_next = false;
373
373
for (;;)
374
374
{
375
375
token = strtokx (NULL , whitespace , "," , "\"" ,
376
- 0 , false, pset .encoding );
376
+ 0 , false, false, pset .encoding );
377
377
if (!token || strchr ("," , token [0 ]))
378
378
goto error ;
379
379
if (!result -> force_notnull_list )
380
380
result -> force_notnull_list = pg_strdup (token );
381
381
else
382
382
xstrcat (& result -> force_notnull_list , token );
383
383
token = strtokx (NULL , whitespace , "," , "\"" ,
384
- 0 , false, pset .encoding );
384
+ 0 , false, false, pset .encoding );
385
385
if (!token || token [0 ] != ',' )
386
386
break ;
387
387
xstrcat (& result -> force_notnull_list , token );
@@ -395,7 +395,7 @@ parse_slash_copy(const char *args)
395
395
396
396
if (fetch_next )
397
397
token = strtokx (NULL , whitespace , NULL , NULL ,
398
- 0 , false, pset .encoding );
398
+ 0 , false, false, pset .encoding );
399
399
}
400
400
}
401
401
@@ -415,6 +415,22 @@ parse_slash_copy(const char *args)
415
415
}
416
416
417
417
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
+
418
434
419
435
/*
420
436
* Execute a \copy command (frontend copy). We have to open a file, then
@@ -462,29 +478,11 @@ do_copy(const char *args)
462
478
463
479
/* Uses old COPY syntax for backward compatibility 2002-06-19 */
464
480
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 );
475
482
476
483
/* There is no backward-compatible CSV syntax */
477
484
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 );
488
486
489
487
if (options -> csv_mode )
490
488
appendPQExpBuffer (& query , " CSV" );
@@ -493,28 +491,10 @@ do_copy(const char *args)
493
491
appendPQExpBuffer (& query , " HEADER" );
494
492
495
493
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 );
506
495
507
496
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 );
518
498
519
499
if (options -> force_quote_list )
520
500
appendPQExpBuffer (& query , " FORCE QUOTE %s" , options -> force_quote_list );
0 commit comments