From 4343c0e546b216ab38a3397a4f0f7476d557b352 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Sat, 20 Nov 2010 10:04:48 -0500 Subject: [PATCH] Expose quote_literal_cstr() from core. This eliminates the need for inefficient implementions of this functionality in both contrib/dblink and contrib/tablefunc, so remove them. The upcoming patch implementing an in-core format() function will also require this functionality. In passing, add some regression tests. --- contrib/dblink/dblink.c | 20 -------- contrib/tablefunc/tablefunc.c | 20 -------- src/backend/utils/adt/quote.c | 79 +++++++++++++++++++++--------- src/include/utils/builtins.h | 1 + src/test/regress/expected/text.out | 18 +++++++ src/test/regress/sql/text.sql | 3 ++ 6 files changed, 77 insertions(+), 64 deletions(-) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index ce86829210..30f1b0eab0 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -91,7 +91,6 @@ static char **get_text_array_contents(ArrayType *array, int *numitems); static char *get_sql_insert(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals); static char *get_sql_delete(Relation rel, int *pkattnums, int pknumatts, char **tgt_pkattvals); static char *get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals, char **tgt_pkattvals); -static char *quote_literal_cstr(char *rawstr); static char *quote_ident_cstr(char *rawstr); static int get_attnum_pk_pos(int *pkattnums, int pknumatts, int key); static HeapTuple get_tuple_of_interest(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals); @@ -1893,25 +1892,6 @@ get_sql_update(Relation rel, int *pkattnums, int pknumatts, char **src_pkattvals return (buf.data); } -/* - * Return a properly quoted literal value. - * Uses quote_literal in quote.c - */ -static char * -quote_literal_cstr(char *rawstr) -{ - text *rawstr_text; - text *result_text; - char *result; - - rawstr_text = cstring_to_text(rawstr); - result_text = DatumGetTextP(DirectFunctionCall1(quote_literal, - PointerGetDatum(rawstr_text))); - result = text_to_cstring(result_text); - - return result; -} - /* * Return a properly quoted identifier. * Uses quote_ident in quote.c diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index ea2f2e15b0..2e9ea1a626 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -85,7 +85,6 @@ static Tuplestorestate *build_tuplestore_recursively(char *key_fld, MemoryContext per_query_ctx, AttInMetadata *attinmeta, Tuplestorestate *tupstore); -static char *quote_literal_cstr(char *rawstr); typedef struct { @@ -1564,22 +1563,3 @@ compatCrosstabTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc) /* OK, the two tupdescs are compatible for our purposes */ return true; } - -/* - * Return a properly quoted literal value. - * Uses quote_literal in quote.c - */ -static char * -quote_literal_cstr(char *rawstr) -{ - text *rawstr_text; - text *result_text; - char *result; - - rawstr_text = cstring_to_text(rawstr); - result_text = DatumGetTextP(DirectFunctionCall1(quote_literal, - PointerGetDatum(rawstr_text))); - result = text_to_cstring(result_text); - - return result; -} diff --git a/src/backend/utils/adt/quote.c b/src/backend/utils/adt/quote.c index 70e98cad84..af07443f7d 100644 --- a/src/backend/utils/adt/quote.c +++ b/src/backend/utils/adt/quote.c @@ -33,8 +33,8 @@ quote_ident(PG_FUNCTION_ARGS) } /* - * quote_literal - - * returns a properly quoted literal + * 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 @@ -42,6 +42,37 @@ quote_ident(PG_FUNCTION_ARGS) * 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, char *src, size_t len) +{ + 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; +} + +/* + * quote_literal - + * returns a properly quoted literal + */ Datum quote_literal(PG_FUNCTION_ARGS) { @@ -58,32 +89,32 @@ quote_literal(PG_FUNCTION_ARGS) 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)); + SET_VARSIZE(result, VARHDRSZ + quote_literal_internal(cp2, cp1, len)); PG_RETURN_TEXT_P(result); } +/* + * quote_literal_cstr - + * returns a properly quoted literal + */ +char * +quote_literal_cstr(char *rawstr) +{ + char *result; + int len; + int newlen; + + len = strlen(rawstr); + /* We make a worst-case result area; wasting a little space is OK */ + result = palloc(len * 2 + 3); + + newlen = quote_literal_internal(result, rawstr, len); + result[newlen] = '\0'; + + return result; +} + /* * quote_nullable - * Returns a properly quoted literal, with null values returned diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 7b1bb23538..ae267ab17a 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -977,6 +977,7 @@ extern int32 type_maximum_size(Oid type_oid, int32 typemod); /* quote.c */ extern Datum quote_ident(PG_FUNCTION_ARGS); extern Datum quote_literal(PG_FUNCTION_ARGS); +extern char *quote_literal_cstr(char *rawstr); extern Datum quote_nullable(PG_FUNCTION_ARGS); /* guc.c */ diff --git a/src/test/regress/expected/text.out b/src/test/regress/expected/text.out index 84f4a5cda8..0b0014a6e2 100644 --- a/src/test/regress/expected/text.out +++ b/src/test/regress/expected/text.out @@ -118,3 +118,21 @@ select i, left('ahoj', i), right('ahoj', i) from generate_series(-5, 5) t(i) ord 5 | ahoj | ahoj (11 rows) +select quote_literal(''); + quote_literal +--------------- + '' +(1 row) + +select quote_literal('abc'''); + quote_literal +--------------- + 'abc''' +(1 row) + +select quote_literal(e'\\'); + quote_literal +--------------- + E'\\' +(1 row) + diff --git a/src/test/regress/sql/text.sql b/src/test/regress/sql/text.sql index a8768ee81a..50c3033d9e 100644 --- a/src/test/regress/sql/text.sql +++ b/src/test/regress/sql/text.sql @@ -41,3 +41,6 @@ select concat_ws('',10,20,null,30); select concat_ws(NULL,10,20,null,30) is null; select reverse('abcde'); select i, left('ahoj', i), right('ahoj', i) from generate_series(-5, 5) t(i) order by i; +select quote_literal(''); +select quote_literal('abc'''); +select quote_literal(e'\\');