| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * quote.c |
| 4 | * Functions for quoting identifiers and literals |
| 5 | * |
| 6 | * Portions Copyright (c) 2000-2019, PostgreSQL Global Development Group |
| 7 | * |
| 8 | * |
| 9 | * IDENTIFICATION |
| 10 | * src/backend/utils/adt/quote.c |
| 11 | * |
| 12 | *------------------------------------------------------------------------- |
| 13 | */ |
| 14 | #include "postgres.h" |
| 15 | |
| 16 | #include "utils/builtins.h" |
| 17 | |
| 18 | |
| 19 | /* |
| 20 | * quote_ident - |
| 21 | * returns a properly quoted identifier |
| 22 | */ |
| 23 | Datum |
| 24 | quote_ident(PG_FUNCTION_ARGS) |
| 25 | { |
| 26 | text *t = PG_GETARG_TEXT_PP(0); |
| 27 | const char *qstr; |
| 28 | char *str; |
| 29 | |
| 30 | str = text_to_cstring(t); |
| 31 | qstr = quote_identifier(str); |
| 32 | PG_RETURN_TEXT_P(cstring_to_text(qstr)); |
| 33 | } |
| 34 | |
| 35 | /* |
| 36 | * quote_literal_internal - |
| 37 | * helper function for quote_literal and quote_literal_cstr |
| 38 | * |
| 39 | * NOTE: think not to make this function's behavior change with |
| 40 | * standard_conforming_strings. We don't know where the result |
| 41 | * literal will be used, and so we must generate a result that |
| 42 | * will work with either setting. Take a look at what dblink |
| 43 | * uses this for before thinking you know better. |
| 44 | */ |
| 45 | static size_t |
| 46 | quote_literal_internal(char *dst, const char *src, size_t len) |
| 47 | { |
| 48 | const char *s; |
| 49 | char *savedst = dst; |
| 50 | |
| 51 | for (s = src; s < src + len; s++) |
| 52 | { |
| 53 | if (*s == '\\') |
| 54 | { |
| 55 | *dst++ = ESCAPE_STRING_SYNTAX; |
| 56 | break; |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | *dst++ = '\''; |
| 61 | while (len-- > 0) |
| 62 | { |
| 63 | if (SQL_STR_DOUBLE(*src, true)) |
| 64 | *dst++ = *src; |
| 65 | *dst++ = *src++; |
| 66 | } |
| 67 | *dst++ = '\''; |
| 68 | |
| 69 | return dst - savedst; |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | * quote_literal - |
| 74 | * returns a properly quoted literal |
| 75 | */ |
| 76 | Datum |
| 77 | quote_literal(PG_FUNCTION_ARGS) |
| 78 | { |
| 79 | text *t = PG_GETARG_TEXT_PP(0); |
| 80 | text *result; |
| 81 | char *cp1; |
| 82 | char *cp2; |
| 83 | int len; |
| 84 | |
| 85 | len = VARSIZE_ANY_EXHDR(t); |
| 86 | /* We make a worst-case result area; wasting a little space is OK */ |
| 87 | result = (text *) palloc(len * 2 + 3 + VARHDRSZ); |
| 88 | |
| 89 | cp1 = VARDATA_ANY(t); |
| 90 | cp2 = VARDATA(result); |
| 91 | |
| 92 | SET_VARSIZE(result, VARHDRSZ + quote_literal_internal(cp2, cp1, len)); |
| 93 | |
| 94 | PG_RETURN_TEXT_P(result); |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | * quote_literal_cstr - |
| 99 | * returns a properly quoted literal |
| 100 | */ |
| 101 | char * |
| 102 | quote_literal_cstr(const char *rawstr) |
| 103 | { |
| 104 | char *result; |
| 105 | int len; |
| 106 | int newlen; |
| 107 | |
| 108 | len = strlen(rawstr); |
| 109 | /* We make a worst-case result area; wasting a little space is OK */ |
| 110 | result = palloc(len * 2 + 3 + 1); |
| 111 | |
| 112 | newlen = quote_literal_internal(result, rawstr, len); |
| 113 | result[newlen] = '\0'; |
| 114 | |
| 115 | return result; |
| 116 | } |
| 117 | |
| 118 | /* |
| 119 | * quote_nullable - |
| 120 | * Returns a properly quoted literal, with null values returned |
| 121 | * as the text string 'NULL'. |
| 122 | */ |
| 123 | Datum |
| 124 | quote_nullable(PG_FUNCTION_ARGS) |
| 125 | { |
| 126 | if (PG_ARGISNULL(0)) |
| 127 | PG_RETURN_TEXT_P(cstring_to_text("NULL" )); |
| 128 | else |
| 129 | PG_RETURN_DATUM(DirectFunctionCall1(quote_literal, |
| 130 | PG_GETARG_DATUM(0))); |
| 131 | } |
| 132 | |