* Convert an ordinary string (eg, an identifier) into a form that
* will be decoded back to a plain token by read.c's functions.
*
- * If a null or empty string is given, it is encoded as "<>".
+ * If a null string pointer is given, it is encoded as '<>'.
+ * An empty string is encoded as '""'. To avoid ambiguity, input
+ * strings beginning with '<' or '"' receive a leading backslash.
*/
void
outToken(StringInfo str, const char *s)
{
- if (s == NULL || *s == '\0')
+ if (s == NULL)
{
appendStringInfoString(str, "<>");
return;
}
+ if (*s == '\0')
+ {
+ appendStringInfoString(str, "\"\"");
+ return;
+ }
/*
* Look for characters or patterns that are treated specially by read.c
{
char in[2];
+ /* Traditionally, we've represented \0 as <>, so keep doing that */
+ if (c == '\0')
+ {
+ appendStringInfoString(str, "<>");
+ return;
+ }
+
in[0] = c;
in[1] = '\0';
{
/*
* We use outToken to provide escaping of the string's content, but we
- * don't want it to do anything with an empty string.
+ * don't want it to convert an empty string to '""', because we're putting
+ * double quotes around the string already.
*/
appendStringInfoChar(str, '"');
if (node->sval[0] != '\0')
#define strtobool(x) ((*(x) == 't') ? true : false)
-#define nullable_string(token,length) \
- ((length) == 0 ? NULL : debackslash(token, length))
+static char *
+nullable_string(const char *token, int length)
+{
+ /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
+ if (length == 0)
+ return NULL;
+ /* outToken emits "" for empty string */
+ if (length == 2 && token[0] == '"' && token[1] == '"')
+ return pstrdup("");
+ /* otherwise, we must remove protective backslashes added by outToken */
+ return debackslash(token, length);
+}
/*