* quote.c
* Functions for quoting identifiers and literals
*
- * Portions Copyright (c) 2000, PostgreSQL Global Development Group
+ * Portions Copyright (c) 2000-2017, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/quote.c,v 1.5 2001/10/25 05:49:45 momjian Exp $
+ * src/backend/utils/adt/quote.c
*
*-------------------------------------------------------------------------
*/
-#include <ctype.h>
-
#include "postgres.h"
-#include "mb/pg_wchar.h"
#include "utils/builtins.h"
-static bool quote_ident_required(text *iptr);
-static text *do_quote_ident(text *iptr);
-static text *do_quote_literal(text *iptr);
-
-
/*
* quote_ident -
* returns a properly quoted identifier
Datum
quote_ident(PG_FUNCTION_ARGS)
{
- text *t = PG_GETARG_TEXT_P(0);
- text *result;
-
- if (quote_ident_required(t))
- result = do_quote_ident(t);
- else
- {
- result = (text *) palloc(VARSIZE(t));
- memcpy(result, t, VARSIZE(t));
- }
-
- PG_FREE_IF_COPY(t, 0);
-
- PG_RETURN_TEXT_P(result);
-}
-
-/*
- * quote_literal -
- * returns a properly quoted literal
- */
-Datum
-quote_literal(PG_FUNCTION_ARGS)
-{
- text *t = PG_GETARG_TEXT_P(0);
- text *result;
+ text *t = PG_GETARG_TEXT_PP(0);
+ const char *qstr;
+ char *str;
- result = do_quote_literal(t);
-
- PG_FREE_IF_COPY(t, 0);
-
- PG_RETURN_TEXT_P(result);
+ str = text_to_cstring(t);
+ qstr = quote_identifier(str);
+ PG_RETURN_TEXT_P(cstring_to_text(qstr));
}
-
/*
- * MULTIBYTE dependant internal functions follow
+ * quote_literal_internal -
+ * helper function for quote_literal and quote_literal_cstr
*
+ * NOTE: think not to make this function's behavior change with
+ * standard_conforming_strings. We don't know where the result
+ * literal will be used, and so we must generate a result that
+ * will work with either setting. Take a look at what dblink
+ * uses this for before thinking you know better.
*/
-
-
-#ifndef MULTIBYTE
-
-/* Check if a given identifier needs quoting */
-static bool
-quote_ident_required(text *iptr)
+static size_t
+quote_literal_internal(char *dst, const char *src, size_t len)
{
- char *cp;
- char *ep;
+ const char *s;
+ char *savedst = dst;
- cp = VARDATA(iptr);
- ep = VARDATA(iptr) + VARSIZE(iptr) - VARHDRSZ;
-
- if (cp >= ep)
- return true;
-
- if (!(*cp == '_' || (*cp >= 'a' && *cp <= 'z')))
- return true;
-
- while ((++cp) < ep)
+ for (s = src; s < src + len; s++)
{
- if (*cp >= 'a' && *cp <= 'z')
- continue;
- if (*cp >= '0' && *cp <= '9')
- continue;
- if (*cp == '_')
- continue;
-
- return true;
+ if (*s == '\\')
+ {
+ *dst++ = ESCAPE_STRING_SYNTAX;
+ break;
+ }
}
- return false;
-}
-
-/* Return a properly quoted identifier */
-static text *
-do_quote_ident(text *iptr)
-{
- text *result;
- char *cp1;
- char *cp2;
- int len;
-
- len = VARSIZE(iptr) - VARHDRSZ;
- result = (text *) palloc(len * 2 + VARHDRSZ + 2);
-
- cp1 = VARDATA(iptr);
- cp2 = VARDATA(result);
-
- *cp2++ = '"';
+ *dst++ = '\'';
while (len-- > 0)
{
- if (*cp1 == '"')
- *cp2++ = '"';
- if (*cp1 == '\\')
- *cp2++ = '\\';
- *cp2++ = *cp1++;
+ if (SQL_STR_DOUBLE(*src, true))
+ *dst++ = *src;
+ *dst++ = *src++;
}
- *cp2++ = '"';
-
- VARATT_SIZEP(result) = cp2 - ((char *) result);
+ *dst++ = '\'';
- return result;
+ return dst - savedst;
}
-/* Return a properly quoted literal value */
-static text *
-do_quote_literal(text *lptr)
+/*
+ * quote_literal -
+ * returns a properly quoted literal
+ */
+Datum
+quote_literal(PG_FUNCTION_ARGS)
{
+ text *t = PG_GETARG_TEXT_PP(0);
text *result;
char *cp1;
char *cp2;
int len;
- len = VARSIZE(lptr) - VARHDRSZ;
- result = (text *) palloc(len * 2 + VARHDRSZ + 2);
+ len = VARSIZE_ANY_EXHDR(t);
+ /* We make a worst-case result area; wasting a little space is OK */
+ result = (text *) palloc(len * 2 + 3 + VARHDRSZ);
- cp1 = VARDATA(lptr);
+ cp1 = VARDATA_ANY(t);
cp2 = VARDATA(result);
- *cp2++ = '\'';
- while (len-- > 0)
- {
- if (*cp1 == '\'')
- *cp2++ = '\'';
- if (*cp1 == '\\')
- *cp2++ = '\\';
- *cp2++ = *cp1++;
- }
- *cp2++ = '\'';
-
- VARATT_SIZEP(result) = cp2 - ((char *) result);
-
- return result;
-}
-
-#else
-
-/* Check if a given identifier needs quoting (MULTIBYTE version) */
-static bool
-quote_ident_required(text *iptr)
-{
- char *cp;
- char *ep;
-
- cp = VARDATA(iptr);
- ep = VARDATA(iptr) + VARSIZE(iptr) - VARHDRSZ;
-
- if (cp >= ep)
- return true;
-
- if (pg_mblen(cp) != 1)
- return true;
- if (!(*cp == '_' || (*cp >= 'a' && *cp <= 'z')))
- return true;
-
- while ((++cp) < ep)
- {
- if (pg_mblen(cp) != 1)
- return true;
-
- if (*cp >= 'a' && *cp <= 'z')
- continue;
- if (*cp >= '0' && *cp <= '9')
- continue;
- if (*cp == '_')
- continue;
+ SET_VARSIZE(result, VARHDRSZ + quote_literal_internal(cp2, cp1, len));
- return true;
- }
-
- return false;
+ PG_RETURN_TEXT_P(result);
}
-/* Return a properly quoted identifier (MULTIBYTE version) */
-static text *
-do_quote_ident(text *iptr)
+/*
+ * quote_literal_cstr -
+ * returns a properly quoted literal
+ */
+char *
+quote_literal_cstr(const char *rawstr)
{
- text *result;
- char *cp1;
- char *cp2;
+ char *result;
int len;
- int wl;
+ int newlen;
- len = VARSIZE(iptr) - VARHDRSZ;
- result = (text *) palloc(len * 2 + VARHDRSZ + 2);
+ len = strlen(rawstr);
+ /* We make a worst-case result area; wasting a little space is OK */
+ result = palloc(len * 2 + 3 + 1);
- cp1 = VARDATA(iptr);
- cp2 = VARDATA(result);
-
- *cp2++ = '"';
- while (len > 0)
- {
- if ((wl = pg_mblen(cp1)) != 1)
- {
- len -= wl;
-
- while (wl-- > 0)
- *cp2++ = *cp1++;
- continue;
- }
-
- if (*cp1 == '"')
- *cp2++ = '"';
- if (*cp1 == '\\')
- *cp2++ = '\\';
- *cp2++ = *cp1++;
-
- len--;
- }
- *cp2++ = '"';
-
- VARATT_SIZEP(result) = cp2 - ((char *) result);
+ newlen = quote_literal_internal(result, rawstr, len);
+ result[newlen] = '\0';
return result;
}
-/* Return a properly quoted literal value (MULTIBYTE version) */
-static text *
-do_quote_literal(text *lptr)
+/*
+ * quote_nullable -
+ * Returns a properly quoted literal, with null values returned
+ * as the text string 'NULL'.
+ */
+Datum
+quote_nullable(PG_FUNCTION_ARGS)
{
- text *result;
- char *cp1;
- char *cp2;
- int len;
- int wl;
-
- len = VARSIZE(lptr) - VARHDRSZ;
- result = (text *) palloc(len * 2 + VARHDRSZ + 2);
-
- cp1 = VARDATA(lptr);
- cp2 = VARDATA(result);
-
- *cp2++ = '\'';
- while (len > 0)
- {
- if ((wl = pg_mblen(cp1)) != 1)
- {
- len -= wl;
-
- while (wl-- > 0)
- *cp2++ = *cp1++;
- continue;
- }
-
- if (*cp1 == '\'')
- *cp2++ = '\'';
- if (*cp1 == '\\')
- *cp2++ = '\\';
- *cp2++ = *cp1++;
-
- len--;
- }
- *cp2++ = '\'';
-
- VARATT_SIZEP(result) = cp2 - ((char *) result);
-
- return result;
+ if (PG_ARGISNULL(0))
+ PG_RETURN_TEXT_P(cstring_to_text("NULL"));
+ else
+ PG_RETURN_DATUM(DirectFunctionCall1(quote_literal,
+ PG_GETARG_DATUM(0)));
}
-#endif