/* * 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. */ static size_t quote_literal_internal(char *dst, const char *src, size_t len) { const char *s; char *savedst = dst; for (s = src; s < src + len; s++) { if (*s == '\\') { *dst++ = ESCAPE_STRING_SYNTAX; break; } } *dst++ = '\''; while (len-- > 0) { if (SQL_STR_DOUBLE(*src, true)) *dst++ = *src; *dst++ = *src++; } *dst++ = '\''; return dst - savedst; }
/* * Print literal `outputstr' already represented as string of type `typid' * into stringbuf `s'. * * Some builtin types aren't quoted, the rest is quoted. Escaping is done as * if standard_conforming_strings were enabled. */ static void print_literal(StringInfo s, Oid typid, char *outputstr) { const char *valptr; switch (typid) { case BOOLOID: if (outputstr[0] == 't') appendStringInfoString(s, "true"); else appendStringInfoString(s, "false"); break; case INT2OID: case INT4OID: case INT8OID: case OIDOID: case FLOAT4OID: case FLOAT8OID: case NUMERICOID: /* NB: We don't care about Inf, NaN et al. */ appendStringInfoString(s, outputstr); break; case BITOID: case VARBITOID: appendStringInfo(s, "B'%s'", outputstr); break; default: appendStringInfoChar(s, '\''); for (valptr = outputstr; *valptr; valptr++) { char ch = *valptr; if (SQL_STR_DOUBLE(ch, false)) appendStringInfoChar(s, ch); appendStringInfoChar(s, ch); } appendStringInfoChar(s, '\''); break; } }
/* * Escape (by doubling) any single quotes or backslashes in given string * * Note: this is used to process postgresql.conf entries and to quote * string literals in pg_basebackup for creating recovery.conf. * Since postgresql.conf strings are defined to treat backslashes as escapes, * we have to double backslashes here. * * Since this function is only used for parsing or creating configuration * files, we do not care about encoding considerations. * * Returns a malloced() string that it's the responsibility of the caller * to free. */ char * escape_single_quotes_ascii(const char *src) { int len = strlen(src), i, j; char *result = static_cast<char *>(malloc(len * 2 + 1)); if (!result) return NULL; for (i = 0, j = 0; i < len; i++) { if (SQL_STR_DOUBLE(src[i], true)) result[j++] = src[i]; result[j++] = src[i]; } result[j] = '\0'; return result; }
/* * quote_literal - * returns a properly quoted literal * * 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. */ Datum quote_literal(PG_FUNCTION_ARGS) { text *t = PG_GETARG_TEXT_P(0); text *result; char *cp1; char *cp2; int len; len = VARSIZE(t) - VARHDRSZ; /* We make a worst-case result area; wasting a little space is OK */ result = (text *) palloc(len * 2 + 3 + VARHDRSZ); cp1 = VARDATA(t); cp2 = VARDATA(result); for (; len-- > 0; cp1++) { if (*cp1 == '\\') { *cp2++ = ESCAPE_STRING_SYNTAX; break; } } len = VARSIZE(t) - VARHDRSZ; cp1 = VARDATA(t); *cp2++ = '\''; while (len-- > 0) { if (SQL_STR_DOUBLE(*cp1, true)) *cp2++ = *cp1; *cp2++ = *cp1++; } *cp2++ = '\''; SET_VARSIZE(result, cp2 - ((char *) result)); PG_RETURN_TEXT_P(result); }
/* * appendLiteral - Format a string as a SQL literal, append to buf * * This function was copied from simple_quote_literal() in * src/backend/utils/adt/ruleutils.c */ static void appendLiteral(StringInfo buf, const char *val) { const char *valptr; /* * We form the string literal according to the prevailing setting of * standard_conforming_strings; we never use E''. User is responsible for * making sure result is used correctly. */ appendStringInfoChar(buf, '\''); for (valptr = val; *valptr; valptr++) { char ch = *valptr; if (SQL_STR_DOUBLE(ch, !standard_conforming_strings)) appendStringInfoChar(buf, ch); appendStringInfoChar(buf, ch); } appendStringInfoChar(buf, '\''); }
/* * Convert a string value to an SQL string literal and append it to * the given buffer. We assume the specified client_encoding and * standard_conforming_strings settings. * * This is essentially equivalent to libpq's PQescapeStringInternal, * except for the output buffer structure. We need it in situations * where we do not have a PGconn available. Where we do, * appendStringLiteralConn is a better choice. */ void appendStringLiteral(PQExpBuffer buf, const char *str, int encoding, bool std_strings) { size_t length = strlen(str); const char *source = str; char *target; if (!enlargePQExpBuffer(buf, 2 * length + 2)) return; target = buf->data + buf->len; *target++ = '\''; while (*source != '\0') { char c = *source; int len; int i; /* Fast path for plain ASCII */ if (!IS_HIGHBIT_SET(c)) { /* Apply quoting if needed */ if (SQL_STR_DOUBLE(c, !std_strings)) *target++ = c; /* Copy the character */ *target++ = c; source++; continue; } /* Slow path for possible multibyte characters */ len = PQmblen(source, encoding); /* Copy the character */ for (i = 0; i < len; i++) { if (*source == '\0') break; *target++ = *source++; } /* * If we hit premature end of string (ie, incomplete multibyte * character), try to pad out to the correct length with spaces. We * may not be able to pad completely, but we will always be able to * insert at least one pad space (since we'd not have quoted a * multibyte character). This should be enough to make a string that * the server will error out on. */ if (i < len) { char *stop = buf->data + buf->maxlen - 2; for (; i < len; i++) { if (target >= stop) break; *target++ = ' '; } break; } } /* Write the terminating quote and NUL character. */ *target++ = '\''; *target = '\0'; buf->len = target - buf->data; }