pgsql-4927

Version:

8.4.0

Bug Link:

http://archives.postgresql.org/pgsql-bugs/2009-07/msg00224.php

Symptom:

in psql doing \copy(select...) and a numeric literal with dot is contained in select will result in syntax error.

Is there any log message?:

Yes! The error message itself is quite sufficient for diagnosing the failure.

How it is diagnosed:

Reproduced!

How to reproduce?

postgres=# \copy ( select 1.23::numeric as num ) to 'out.csv' with csv header

ERROR:  syntax error at or near "."

LINE 1: COPY ( select 1 . 23::numeric as num ) TO STDOUT CSV HEADER

                        ^

\copy: ERROR:  syntax error at or near "."

LINE 1: COPY ( select 1 . 23::numeric as num ) TO STDOUT CSV HEADER

In 8.4.4+ version, the error will disappear.

Root Cause:

psql will add spaces around a dot(due to the strtok with dot as one of the delimeter) within “\copy ( select 1.23::numeric as num ) to 'out.csv' with csv header”,

If this dot is a decimal point in a numeric literal, the additional of spaces will result in syntax error.

bin/psql/copy.c

static struct copy_options *parse_slash_copy(const char *args)

{

...

        // Here, line = “( select 1.23::numeric as num )” 

        token = strtokx(line, whitespace, ".,()", "\"",

                                        0, false, false, pset.encoding);

        /* Handle COPY (SELECT) case */

        if (token[0] == '(')

        {

                int parens = 1;

                while (parens > 0)

                {

-                        token = strtokx(NULL, whitespace, ".,()", "\"'",

+                        token = strtokx(NULL, whitespace, ",()", "\"'",

                                        nonstd_backslash, true, false, pset.encoding);

// modification: does not use dot as delimiters here!

                        if (!token)

                                goto error;

                        if (token[0] == '(')

                                parens++;

                        else if (token[0] == ')')

                                parens--;

                        xstrcat(&result->table, " "); // add space between parsed tokens!

                        xstrcat(&result->table, token);

                }

        }

        ...

}

/* Splits a string into tokens, returning one token per call, then NULL

 * when no more tokens exist in the given string.

 * s -                        string to parse, if NULL continue parsing the last string

 * whitespace - set of whitespace characters that separate tokens

 * delim -                set of non-whitespace separator characters (or NULL)

  … ...

 * Characters in 'delim', if any, will be returned as single-character

 * tokens unless part of a quoted token.

*/

char *

strtokx(const char *s, const char *whitespace, const char *delim,

                const char *quote,

                char escape,

                bool e_strings,

                bool del_quotes,

                int encoding)

{

...

}

-----------------------------------------------------------------------------

Where the error message was printed:

#line 1350 "gram.y"

    {

        ...

        int        tok;

        ...        

                tok = yylex();

                if (tok != ';' && tok != K_USING)

                        yyerror("syntax error");                

        ...

;}

What is the pattern of the error message:

input check.

ret = yylex();

  if (ret != XXX)

     log;