]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/jsonpath_scan.l
Fix initialization of fake LSN for unlogged relations
[postgresql] / src / backend / utils / adt / jsonpath_scan.l
index 110ea2160d952c4faac301539d17a829607b2b29..9650226f507cee86d49e3f843684a185a1c66845 100644 (file)
@@ -1,8 +1,12 @@
+%{
 /*-------------------------------------------------------------------------
  *
  * jsonpath_scan.l
  *     Lexical parser for jsonpath datatype
  *
+ * Splits jsonpath string into tokens represented as JsonPathString structs.
+ * Decodes unicode and hex escaped strings.
+ *
  * Copyright (c) 2019, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
  *-------------------------------------------------------------------------
  */
 
-%{
 #include "postgres.h"
 
 #include "mb/pg_wchar.h"
 #include "nodes/pg_list.h"
-#include "utils/jsonpath_scanner.h"
 
-static string scanstring;
-
-/* No reason to constrain amount of data slurped */
-/* #define YY_READ_BUF_SIZE 16777216 */
+static JsonPathString scanstring;
 
 /* Handles to the buffer that the lexer uses internally */
 static YY_BUFFER_STATE scanbufhandle;
@@ -30,11 +29,9 @@ static int   scanbuflen;
 
 static void addstring(bool init, char *s, int l);
 static void addchar(bool init, char s);
-static int checkSpecialVal(void); /* examine scanstring for the special
-                                                                  * value */
-
+static enum yytokentype checkKeyword(void);
 static void parseUnicode(char *s, int l);
-static void parseHexChars(char *s, int l);
+static void parseHexChar(char *s);
 
 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
 #undef fprintf
@@ -46,7 +43,6 @@ fprintf_to_ereport(const char *fmt, const char *msg)
        ereport(ERROR, (errmsg_internal("%s", msg)));
 }
 
-#define yyerror jsonpath_yyerror
 %}
 
 %option 8bit
@@ -62,202 +58,216 @@ fprintf_to_ereport(const char *fmt, const char *msg)
 %option noyyrealloc
 %option noyyfree
 
-%x xQUOTED
-%x xNONQUOTED
-%x xVARQUOTED
-%x xSINGLEQUOTED
-%x xCOMMENT
+/*
+ * We use exclusive states for quoted and non-quoted strings,
+ * quoted variable names and C-style comments.
+ * Exclusive states:
+ *  <xq> - quoted strings
+ *  <xnq> - non-quoted strings
+ *  <xvq> - quoted variable names
+ *  <xc> - C-style comment
+ */
 
-special                 [\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/]
-any                    [^\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/\\\"\' \t\n\r\f]
+%x xq
+%x xnq
+%x xvq
+%x xc
+
+special                [\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/]
 blank          [ \t\n\r\f]
+/* "other" means anything that's not special, blank, or '\' or '"' */
+other          [^\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/\\\" \t\n\r\f]
+
+digit          [0-9]
+integer                (0|[1-9]{digit}*)
+decimal                {integer}\.{digit}+
+decimalfail    {integer}\.
+real           ({integer}|{decimal})[Ee][-+]?{digit}+
+realfail1      ({integer}|{decimal})[Ee]
+realfail2      ({integer}|{decimal})[Ee][-+]
+
 hex_dig                [0-9A-Fa-f]
 unicode                \\u({hex_dig}{4}|\{{hex_dig}{1,6}\})
+unicodefail    \\u({hex_dig}{0,3}|\{{hex_dig}{0,6})
 hex_char       \\x{hex_dig}{2}
-
+hex_fail       \\x{hex_dig}{0,1}
 
 %%
 
-<INITIAL>\&\&                                  { return AND_P; }
-
-<INITIAL>\|\|                                  { return OR_P; }
-
-<INITIAL>\!                                            { return NOT_P; }
-
-<INITIAL>\*\*                                  { return ANY_P; }
-
-<INITIAL>\<                                            { return LESS_P; }
-
-<INITIAL>\<\=                                  { return LESSEQUAL_P; }
-
-<INITIAL>\=\=                                  { return EQUAL_P; }
-
-<INITIAL>\<\>                                  { return NOTEQUAL_P; }
-
-<INITIAL>\!\=                                  { return NOTEQUAL_P; }
-
-<INITIAL>\>\=                                  { return GREATEREQUAL_P; }
-
-<INITIAL>\>                                            { return GREATER_P; }
-
-<INITIAL>\${any}+                              {
-                                                                       addstring(true, yytext + 1, yyleng - 1);
-                                                                       addchar(false, '\0');
-                                                                       yylval->str = scanstring;
-                                                                       return VARIABLE_P;
-                                                               }
-
-<INITIAL>\$\"                                  {
-                                                                       addchar(true, '\0');
-                                                                       BEGIN xVARQUOTED;
-                                                               }
-
-<INITIAL>{special}                             { return *yytext; }
-
-<INITIAL>{blank}+                              { /* ignore */ }
-
-<INITIAL>\/\*                                  {
-                                                                       addchar(true, '\0');
-                                                                       BEGIN xCOMMENT;
+<xnq>{other}+                                  {
+                                                                       addstring(false, yytext, yyleng);
                                                                }
 
-<INITIAL>[0-9]+(\.[0-9]+)?[eE][+-]?[0-9]+  /* float */  {
-                                                                       addstring(true, yytext, yyleng);
-                                                                       addchar(false, '\0');
+<xnq>{blank}+                                  {
                                                                        yylval->str = scanstring;
-                                                                       return NUMERIC_P;
+                                                                       BEGIN INITIAL;
+                                                                       return checkKeyword();
                                                                }
 
-<INITIAL>\.[0-9]+[eE][+-]?[0-9]+  /* float */  {
-                                                                       addstring(true, yytext, yyleng);
-                                                                       addchar(false, '\0');
+<xnq>\/\*                                              {
                                                                        yylval->str = scanstring;
-                                                                       return NUMERIC_P;
+                                                                       BEGIN xc;
                                                                }
 
-<INITIAL>([0-9]+)?\.[0-9]+             {
-                                                                       addstring(true, yytext, yyleng);
-                                                                       addchar(false, '\0');
+<xnq>({special}|\")                            {
                                                                        yylval->str = scanstring;
-                                                                       return NUMERIC_P;
+                                                                       yyless(0);
+                                                                       BEGIN INITIAL;
+                                                                       return checkKeyword();
                                                                }
 
-<INITIAL>[0-9]+                                        {
-                                                                       addstring(true, yytext, yyleng);
-                                                                       addchar(false, '\0');
+<xnq><<EOF>>                                   {
                                                                        yylval->str = scanstring;
-                                                                       return INT_P;
+                                                                       BEGIN INITIAL;
+                                                                       return checkKeyword();
                                                                }
 
-<INITIAL>{any}+                                        {
-                                                                       addstring(true, yytext, yyleng);
-                                                                       BEGIN xNONQUOTED;
-                                                               }
+<xnq,xq,xvq>\\b                                { addchar(false, '\b'); }
 
-<INITIAL>\"                                            {
-                                                                       addchar(true, '\0');
-                                                                       BEGIN xQUOTED;
-                                                               }
+<xnq,xq,xvq>\\f                                { addchar(false, '\f'); }
 
-<INITIAL>\'                                            {
-                                                                       addchar(true, '\0');
-                                                                       BEGIN xSINGLEQUOTED;
-                                                               }
+<xnq,xq,xvq>\\n                                { addchar(false, '\n'); }
 
-<INITIAL>\\                                            {
-                                                                       yyless(0);
-                                                                       addchar(true, '\0');
-                                                                       BEGIN xNONQUOTED;
-                                                               }
+<xnq,xq,xvq>\\r                                { addchar(false, '\r'); }
 
-<xNONQUOTED>{any}+                             {
-                                                                       addstring(false, yytext, yyleng);
-                                                               }
+<xnq,xq,xvq>\\t                                { addchar(false, '\t'); }
 
-<xNONQUOTED>{blank}+                   {
-                                                                       yylval->str = scanstring;
-                                                                       BEGIN INITIAL;
-                                                                       return checkSpecialVal();
-                                                               }
+<xnq,xq,xvq>\\v                                { addchar(false, '\v'); }
 
+<xnq,xq,xvq>{unicode}+         { parseUnicode(yytext, yyleng); }
 
-<xNONQUOTED>\/\*                               {
-                                                                       yylval->str = scanstring;
-                                                                       BEGIN xCOMMENT;
-                                                               }
+<xnq,xq,xvq>{hex_char}         { parseHexChar(yytext); }
+
+<xnq,xq,xvq>{unicode}*{unicodefail}    { yyerror(NULL, "invalid unicode sequence"); }
+
+<xnq,xq,xvq>{hex_fail}         { yyerror(NULL, "invalid hex character sequence"); }
+
+<xnq,xq,xvq>{unicode}+\\       {
+                                                               /* throw back the \\, and treat as unicode */
+                                                               yyless(yyleng - 1);
+                                                               parseUnicode(yytext, yyleng);
+                                                       }
+
+<xnq,xq,xvq>\\.                                { addchar(false, yytext[1]); }
 
-<xNONQUOTED>({special}|\"|\')  {
+<xnq,xq,xvq>\\                         { yyerror(NULL, "unexpected end after backslash"); }
+
+<xq,xvq><<EOF>>                                { yyerror(NULL, "unexpected end of quoted string"); }
+
+<xq>\"                                                 {
                                                                        yylval->str = scanstring;
-                                                                       yyless(0);
                                                                        BEGIN INITIAL;
-                                                                       return checkSpecialVal();
+                                                                       return STRING_P;
                                                                }
 
-<xNONQUOTED><<EOF>>                            {
+<xvq>\"                                                        {
                                                                        yylval->str = scanstring;
                                                                        BEGIN INITIAL;
-                                                                       return checkSpecialVal();
+                                                                       return VARIABLE_P;
                                                                }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\[\"\'\\]        { addchar(false, yytext[1]); }
+<xq,xvq>[^\\\"]+                               { addstring(false, yytext, yyleng); }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\b       { addchar(false, '\b'); }
+<xc>\*\/                                               { BEGIN INITIAL; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\f       { addchar(false, '\f'); }
+<xc>[^\*]+                                             { }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\n       { addchar(false, '\n'); }
+<xc>\*                                                 { }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\r       { addchar(false, '\r'); }
+<xc><<EOF>>                                            { yyerror(NULL, "unexpected end of comment"); }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\t       { addchar(false, '\t'); }
+\&\&                                                   { return AND_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\v       { addchar(false, '\v'); }
+\|\|                                                   { return OR_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>{unicode}+                { parseUnicode(yytext, yyleng); }
+\!                                                             { return NOT_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>{hex_char}+       { parseHexChars(yytext, yyleng); }
+\*\*                                                   { return ANY_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\x       { yyerror(NULL, "Hex character sequence is invalid"); }
+\<                                                             { return LESS_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\u       { yyerror(NULL, "Unicode sequence is invalid"); }
+\<\=                                                   { return LESSEQUAL_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\.       { yyerror(NULL, "Escape sequence is invalid"); }
+\=\=                                                   { return EQUAL_P; }
 
-<xNONQUOTED,xQUOTED,xVARQUOTED,xSINGLEQUOTED>\\                { yyerror(NULL, "Unexpected end after backslash"); }
+\<\>                                                   { return NOTEQUAL_P; }
 
-<xQUOTED,xVARQUOTED,xSINGLEQUOTED><<EOF>>                      { yyerror(NULL, "Unexpected end of quoted string"); }
+\!\=                                                   { return NOTEQUAL_P; }
 
-<xQUOTED>\"                                            {
+\>\=                                                   { return GREATEREQUAL_P; }
+
+\>                                                             { return GREATER_P; }
+
+\${other}+                                             {
+                                                                       addstring(true, yytext + 1, yyleng - 1);
+                                                                       addchar(false, '\0');
                                                                        yylval->str = scanstring;
-                                                                       BEGIN INITIAL;
-                                                                       return STRING_P;
+                                                                       return VARIABLE_P;
+                                                               }
+
+\$\"                                                   {
+                                                                       addchar(true, '\0');
+                                                                       BEGIN xvq;
+                                                               }
+
+{special}                                              { return *yytext; }
+
+{blank}+                                               { /* ignore */ }
+
+\/\*                                                   {
+                                                                       addchar(true, '\0');
+                                                                       BEGIN xc;
                                                                }
 
-<xVARQUOTED>\"                                 {
+{real}                                                 {
+                                                                       addstring(true, yytext, yyleng);
+                                                                       addchar(false, '\0');
                                                                        yylval->str = scanstring;
-                                                                       BEGIN INITIAL;
-                                                                       return VARIABLE_P;
+                                                                       return NUMERIC_P;
                                                                }
 
-<xSINGLEQUOTED>\'                              {
+{decimal}                                              {
+                                                                       addstring(true, yytext, yyleng);
+                                                                       addchar(false, '\0');
                                                                        yylval->str = scanstring;
-                                                                       BEGIN INITIAL;
-                                                                       return STRING_P;
+                                                                       return NUMERIC_P;
                                                                }
 
-<xQUOTED,xVARQUOTED>[^\\\"]+   { addstring(false, yytext, yyleng); }
+{integer}                                              {
+                                                                       addstring(true, yytext, yyleng);
+                                                                       addchar(false, '\0');
+                                                                       yylval->str = scanstring;
+                                                                       return INT_P;
+                                                               }
 
-<xSINGLEQUOTED>[^\\\']+                        { addstring(false, yytext, yyleng); }
+{decimalfail}                                  {
+                                                                       /* throw back the ., and treat as integer */
+                                                                       yyless(yyleng - 1);
+                                                                       addstring(true, yytext, yyleng);
+                                                                       addchar(false, '\0');
+                                                                       yylval->str = scanstring;
+                                                                       return INT_P;
+                                                               }
 
-<INITIAL><<EOF>>                               { yyterminate(); }
+({realfail1}|{realfail2})              { yyerror(NULL, "invalid floating point number"); }
 
-<xCOMMENT>\*\/                                 { BEGIN INITIAL; }
+\"                                                             {
+                                                                       addchar(true, '\0');
+                                                                       BEGIN xq;
+                                                               }
 
-<xCOMMENT>[^\*]+                               { }
+\\                                                             {
+                                                                       yyless(0);
+                                                                       addchar(true, '\0');
+                                                                       BEGIN xnq;
+                                                               }
 
-<xCOMMENT>\*                                   { }
+{other}+                                               {
+                                                                       addstring(true, yytext, yyleng);
+                                                                       BEGIN xnq;
+                                                               }
 
-<xCOMMENT><<EOF>>                              { yyerror(NULL, "Unexpected end of comment"); }
+<<EOF>>                                                        { yyterminate(); }
 
 %%
 
@@ -268,34 +278,32 @@ jsonpath_yyerror(JsonPathParseResult **result, const char *message)
        {
                ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("bad jsonpath representation"),
                                 /* translator: %s is typically "syntax error" */
-                                errdetail("%s at end of input", message)));
+                                errmsg("%s at end of jsonpath input", _(message))));
        }
        else
        {
                ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("bad jsonpath representation"),
                                 /* translator: first %s is typically "syntax error" */
-                                errdetail("%s at or near \"%s\"", message, yytext)));
+                                errmsg("%s at or near \"%s\" of jsonpath input",
+                                               _(message), yytext)));
        }
 }
 
-typedef struct keyword
+typedef struct JsonPathKeyword
 {
-       int16   len;
-       bool    lowercase;
-       int             val;
-       char    *keyword;
-} keyword;
+       int16           len;
+       bool            lowercase;
+       int                     val;
+       const char *keyword;
+} JsonPathKeyword;
 
 /*
  * Array of key words should be sorted by length and then
  * alphabetical order
  */
-
-static keyword keywords[] = {
+static const JsonPathKeyword keywords[] = {
        { 2, false,     IS_P,           "is"},
        { 2, false,     TO_P,           "to"},
        { 3, false,     ABS_P,          "abs"},
@@ -315,23 +323,25 @@ static keyword keywords[] = {
        { 6, false,     STRICT_P,       "strict"},
        { 7, false,     CEILING_P,      "ceiling"},
        { 7, false,     UNKNOWN_P,      "unknown"},
+       { 8, false,     DATETIME_P,     "datetime"},
        { 8, false,     KEYVALUE_P,     "keyvalue"},
        { 10,false, LIKE_REGEX_P, "like_regex"},
 };
 
-static int
-checkSpecialVal()
+/* Check if current scanstring value is a keyword */
+static enum yytokentype
+checkKeyword()
 {
-       int                     res = IDENT_P;
-       int                     diff;
-       keyword         *StopLow = keywords,
-                               *StopHigh = keywords + lengthof(keywords),
-                               *StopMiddle;
+       int                                             res = IDENT_P;
+       int                                             diff;
+       const JsonPathKeyword  *StopLow = keywords,
+                                                  *StopHigh = keywords + lengthof(keywords),
+                                                  *StopMiddle;
 
        if (scanstring.len > keywords[lengthof(keywords) - 1].len)
                return res;
 
-       while(StopLow < StopHigh)
+       while (StopLow < StopHigh)
        {
                StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
 
@@ -399,49 +409,50 @@ jsonpath_scanner_finish(void)
        pfree(scanbuf);
 }
 
+/*
+ * Resize scanstring so that it can append string of given length.
+ * Reinitialize if required.
+ */
 static void
-addstring(bool init, char *s, int l)
+resizeString(bool init, int appendLen)
 {
        if (init)
        {
-               scanstring.total = 32;
-               scanstring.val = palloc(scanstring.total);
+               scanstring.total = Max(32, appendLen);
+               scanstring.val = (char *) palloc(scanstring.total);
                scanstring.len = 0;
        }
-
-       if (s && l)
+       else
        {
-               while(scanstring.len + l + 1 >= scanstring.total)
+               if (scanstring.len + appendLen >= scanstring.total)
                {
-                       scanstring.total *= 2;
+                       while (scanstring.len + appendLen >= scanstring.total)
+                               scanstring.total *= 2;
                        scanstring.val = repalloc(scanstring.val, scanstring.total);
                }
-
-               memcpy(scanstring.val + scanstring.len, s, l);
-               scanstring.len += l;
        }
 }
 
+/* Add set of bytes at "s" of length "l" to scanstring */
 static void
-addchar(bool init, char s)
+addstring(bool init, char *s, int l)
 {
-       if (init)
-       {
-               scanstring.total = 32;
-               scanstring.val = palloc(scanstring.total);
-               scanstring.len = 0;
-       }
-       else if(scanstring.len + 1 >= scanstring.total)
-       {
-               scanstring.total *= 2;
-               scanstring.val = repalloc(scanstring.val, scanstring.total);
-       }
+       resizeString(init, l + 1);
+       memcpy(scanstring.val + scanstring.len, s, l);
+       scanstring.len += l;
+}
 
-       scanstring.val[ scanstring.len ] = s;
-       if (s != '\0')
+/* Add single byte "c" to scanstring */
+static void
+addchar(bool init, char c)
+{
+       resizeString(init, 1);
+       scanstring.val[scanstring.len] = c;
+       if (c != '\0')
                scanstring.len++;
 }
 
+/* Interface to jsonpath parser */
 JsonPathParseResult *
 parsejsonpath(const char *str, int len)
 {
@@ -449,14 +460,15 @@ parsejsonpath(const char *str, int len)
 
        jsonpath_scanner_init(str, len);
 
-       if (jsonpath_yyparse((void*)&parseresult) != 0)
-               jsonpath_yyerror(NULL, "bugus input");
+       if (jsonpath_yyparse((void *) &parseresult) != 0)
+               jsonpath_yyerror(NULL, "bogus input"); /* shouldn't happen */
 
        jsonpath_scanner_finish();
 
        return parseresult;
 }
 
+/* Turn hex character into integer */
 static int
 hexval(char c)
 {
@@ -466,10 +478,11 @@ hexval(char c)
                return c - 'a' + 0xA;
        if (c >= 'A' && c <= 'F')
                return c - 'A' + 0xA;
-       elog(ERROR, "invalid hexadecimal digit");
+       jsonpath_yyerror(NULL, "invalid hexadecimal digit");
        return 0; /* not reached */
 }
 
+/* Add given unicode character to scanstring */
 static void
 addUnicodeChar(int ch)
 {
@@ -510,13 +523,14 @@ addUnicodeChar(int ch)
        {
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                                errmsg("invalid input syntax for type jsonpath"),
+                                errmsg("invalid input syntax for type %s", "jsonpath"),
                                 errdetail("Unicode escape values cannot be used for code "
                                                   "point values above 007F when the server encoding "
                                                   "is not UTF8.")));
        }
 }
 
+/* Add unicode character and process its hi surrogate */
 static void
 addUnicode(int ch, int *hi_surrogate)
 {
@@ -525,7 +539,7 @@ addUnicode(int ch, int *hi_surrogate)
                if (*hi_surrogate != -1)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                                        errmsg("invalid input syntax for type jsonpath"),
+                                        errmsg("invalid input syntax for type %s", "jsonpath"),
                                         errdetail("Unicode high surrogate must not follow "
                                                           "a high surrogate.")));
                *hi_surrogate = (ch & 0x3ff) << 10;
@@ -536,7 +550,7 @@ addUnicode(int ch, int *hi_surrogate)
                if (*hi_surrogate == -1)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                                        errmsg("invalid input syntax for type jsonpath"),
+                                        errmsg("invalid input syntax for type %s", "jsonpath"),
                                         errdetail("Unicode low surrogate must follow a high "
                                                           "surrogate.")));
                ch = 0x10000 + *hi_surrogate + (ch & 0x3ff);
@@ -546,7 +560,7 @@ addUnicode(int ch, int *hi_surrogate)
        {
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                                errmsg("invalid input syntax for type jsonpath"),
+                                errmsg("invalid input syntax for type %s", "jsonpath"),
                                 errdetail("Unicode low surrogate must follow a high "
                                                   "surrogate.")));
        }
@@ -561,7 +575,7 @@ addUnicode(int ch, int *hi_surrogate)
 static void
 parseUnicode(char *s, int l)
 {
-       int                     i;
+       int                     i = 2;
        int                     hi_surrogate = -1;
 
        for (i = 2; i < l; i += 2)      /* skip '\u' */
@@ -573,7 +587,7 @@ parseUnicode(char *s, int l)
                {
                        while (s[++i] != '}' && i < l)
                                ch = (ch << 4) | hexval(s[i]);
-                       i++;    /* ski p '}' */
+                       i++;    /* skip '}' */
                }
                else            /* parse '\uXXXX' */
                {
@@ -588,25 +602,20 @@ parseUnicode(char *s, int l)
        {
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                                errmsg("invalid input syntax for type jsonpath"),
+                                errmsg("invalid input syntax for type %s", "jsonpath"),
                                 errdetail("Unicode low surrogate must follow a high "
                                                   "surrogate.")));
        }
 }
 
+/* Parse sequence of hex-encoded characters */
 static void
-parseHexChars(char *s, int l)
+parseHexChar(char *s)
 {
-       int i;
-
-       Assert(l % 4 /* \xXX */ == 0);
-
-       for (i = 0; i < l / 4; i++)
-       {
-               int                     ch = (hexval(s[i * 4 + 2]) << 4) | hexval(s[i * 4 + 3]);
+       int                     ch = (hexval(s[2]) << 4) |
+                                         hexval(s[3]);
 
-               addUnicodeChar(ch);
-       }
+       addUnicodeChar(ch);
 }
 
 /*
@@ -635,4 +644,3 @@ jsonpath_yyfree(void *ptr)
        if (ptr)
                pfree(ptr);
 }
-