format.diff
text/x-patch
Filename: format.diff
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| doc/src/sgml/func.sgml | 20 | 0 |
| src/backend/utils/adt/varlena.c | 156 | 0 |
| src/include/catalog/pg_proc.h | 4 | 0 |
| src/include/utils/builtins.h | 2 | 0 |
| src/test/regress/expected/text.out | 19 | 0 |
| src/test/regress/sql/text.sql | 6 | 0 |
*** ./doc/src/sgml/func.sgml.orig 2010-08-24 08:30:43.000000000 +0200
--- ./doc/src/sgml/func.sgml 2010-09-09 08:58:12.515512369 +0200
***************
*** 1272,1277 ****
--- 1272,1280 ----
<primary>encode</primary>
</indexterm>
<indexterm>
+ <primary>format</primary>
+ </indexterm>
+ <indexterm>
<primary>initcap</primary>
</indexterm>
<indexterm>
***************
*** 1482,1487 ****
--- 1485,1507 ----
<row>
<entry>
+ <literal><function>format</function>(<parameter>formatstr</parameter> <type>text</type>
+ [, <parameter>str</parameter> <type>"any"</type> [, ...] ])</literal>
+ </entry>
+ <entry><type>text</type></entry>
+ <entry>
+ This functions can be used to create a formated string or message. There are allowed
+ three types of tags: %s as string, %i as SQL identifiers and %l as SQL literals. Attention:
+ result for %i and %l must not be same as result of <function>quote_ident</function> and
+ <function>quote_literal</function> functions, because this function doesn't try to coerce
+ parameters to <type>text</type> type and directly use a type's output functions.
+ </entry>
+ <entry><literal>format('Hello %s', 'World')</literal></entry>
+ <entry><literal>Hello World</literal></entry>
+ </row>
+
+ <row>
+ <entry>
<literal><function>encode</function>(<parameter>data</parameter> <type>bytea</type>,
<parameter>type</parameter> <type>text</type>)</literal>
</entry>
*** ./src/backend/utils/adt/varlena.c.orig 2010-08-24 08:30:43.000000000 +0200
--- ./src/backend/utils/adt/varlena.c 2010-09-09 08:44:40.450637505 +0200
***************
*** 21,28 ****
--- 21,30 ----
#include "libpq/md5.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
+ #include "parser/parse_coerce.h"
#include "parser/scansup.h"
#include "regex/regex.h"
+ #include "utils/array.h"
#include "utils/builtins.h"
#include "utils/bytea.h"
#include "utils/lsyscache.h"
***************
*** 3702,3704 ****
--- 3704,3860 ----
PG_RETURN_TEXT_P(result);
}
+
+ /*
+ * Text format - a variadic function replaces %c symbols with entered text.
+ */
+ Datum
+ text_format(PG_FUNCTION_ARGS)
+ {
+ text *fmt;
+ StringInfoData str;
+ char *cp;
+ int i = 1;
+ size_t len;
+ char *start_ptr;
+ char *end_ptr;
+ text *result;
+
+ /* When format string is null, returns null */
+ if (PG_ARGISNULL(0))
+ PG_RETURN_NULL();
+
+ fmt = PG_GETARG_TEXT_PP(0);
+ len = VARSIZE_ANY_EXHDR(fmt);
+ start_ptr = VARDATA_ANY(fmt);
+ end_ptr = start_ptr + len - 1;
+
+ initStringInfo(&str);
+ for (cp = start_ptr; cp <= end_ptr; cp++)
+ {
+ /*
+ * there are allowed escape char - '\'
+ */
+ if (cp[0] == '\\')
+ {
+ /* check next char */
+ if (cp < end_ptr)
+ {
+ switch (cp[1])
+ {
+ case '\\':
+ case '%':
+ appendStringInfoChar(&str, cp[1]);
+ break;
+
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unsupported escape sequence \\%c", cp[1])));
+ }
+ cp++;
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("broken escape sequence")));
+ }
+ else if (cp[0] == '%')
+ {
+ char tag;
+
+ /* initial check */
+ if (cp == end_ptr)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("missing formating tag")));
+
+ if (i >= PG_NARGS())
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("too few parameters for format function")));
+
+ tag = cp[1];
+ cp++;
+
+ if (!PG_ARGISNULL(i))
+ {
+ Oid valtype;
+ Datum value;
+ Oid typoutput;
+ bool typIsVarlena;
+
+ /* append n-th value */
+ value = PG_GETARG_DATUM(i);
+ valtype = get_fn_expr_argtype(fcinfo->flinfo, i);
+ getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
+
+ if (tag == 's')
+ {
+ /* show it as unspecified string */
+ appendStringInfoString(&str, OidOutputFunctionCall(typoutput, value));
+ }
+ else if (tag == 'i')
+ {
+ char *target_value;
+
+ /* show it as sql identifier */
+ target_value = OidOutputFunctionCall(typoutput, value);
+ appendStringInfoString(&str, quote_identifier(target_value));
+ }
+ else if (tag == 'l')
+ {
+ text *txt;
+ text *quoted_txt;
+
+ /* get text value and quotize */
+ txt = cstring_to_text(OidOutputFunctionCall(typoutput, value));
+ quoted_txt = DatumGetTextP(DirectFunctionCall1(quote_literal,
+ PointerGetDatum(txt)));
+ appendStringInfoString(&str, text_to_cstring(quoted_txt));
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unsupported tag \"%%%c\"", tag)));
+ }
+ else
+ {
+ if (tag == 'i')
+ ereport(ERROR,
+ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+ errmsg("NULL is used as SQL identifier")));
+ else if (tag == 'l')
+ appendStringInfoString(&str, "NULL");
+ else if (tag != 's')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unsupported tag \"%%%c\"", tag)));
+ }
+ i++;
+ }
+ else
+ appendStringInfoChar(&str, cp[0]);
+ }
+
+ /* check if all arguments are used */
+ if (i != PG_NARGS())
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("too many parameters for format function")));
+
+ result = cstring_to_text_with_len(str.data, str.len);
+ pfree(str.data);
+
+ PG_RETURN_TEXT_P(result);
+ }
+
+ /*
+ * Non variadic text_format function - only wrapper
+ * Print and check format string
+ */
+ Datum
+ text_format_nv(PG_FUNCTION_ARGS)
+ {
+ return text_format(fcinfo);
+ }
*** ./src/include/catalog/pg_proc.h.orig 2010-08-24 08:30:43.000000000 +0200
--- ./src/include/catalog/pg_proc.h 2010-09-09 08:37:11.321512358 +0200
***************
*** 2732,2737 ****
--- 2732,2741 ----
DESCR("return the last n characters");
DATA(insert OID = 3062 ( reverse PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ text_reverse _null_ _null_ _null_ ));
DESCR("reverse text");
+ DATA(insert OID = 3063 ( format PGNSP PGUID 12 1 0 2276 f f f f f s 2 0 25 "25 2276" "{25,2276}" "{i,v}" _null_ _null_ text_format _null_ _null_ _null_ ));
+ DESCR("format text message");
+ DATA(insert OID = 3064 ( format PGNSP PGUID 12 1 0 0 f f f f f s 1 0 25 "25" _null_ _null_ _null_ _null_ text_format_nv _null_ _null_ _null_ ));
+ DESCR("format text message");
DATA(insert OID = 1810 ( bit_length PGNSP PGUID 14 1 0 0 f f f t f i 1 0 23 "17" _null_ _null_ _null_ _null_ "select pg_catalog.octet_length($1) * 8" _null_ _null_ _null_ ));
DESCR("length in bits");
*** ./src/include/utils/builtins.h.orig 2010-08-24 08:30:44.000000000 +0200
--- ./src/include/utils/builtins.h 2010-09-09 08:38:33.001512464 +0200
***************
*** 738,743 ****
--- 738,745 ----
extern Datum text_left(PG_FUNCTION_ARGS);
extern Datum text_right(PG_FUNCTION_ARGS);
extern Datum text_reverse(PG_FUNCTION_ARGS);
+ extern Datum text_format(PG_FUNCTION_ARGS);
+ extern Datum text_format_nv(PG_FUNCTION_ARGS);
/* version.c */
extern Datum pgsql_version(PG_FUNCTION_ARGS);
*** ./src/test/regress/expected/text.out.orig 2010-08-24 08:30:44.000000000 +0200
--- ./src/test/regress/expected/text.out 2010-09-09 09:09:59.000000000 +0200
***************
*** 118,120 ****
--- 118,139 ----
5 | ahoj | ahoj
(11 rows)
+ select format('some text');
+ format
+ -----------
+ some text
+ (1 row)
+
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', 'My tab', 'Hello', NULL, 10);
+ format
+ -----------------------------------------------------------
+ -- insert into "My tab" (a,b,c) values('Hello',NULL,'10')
+ (1 row)
+
+ -- should fail
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', NULL, 'Hello', NULL, 10);
+ ERROR: NULL is used as SQL identifier
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', 'My tab', NULL, 'Hello');
+ ERROR: too few parameters for format function
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', 'My tab', 'Hello', NULL, 10, 10);
+ ERROR: too many parameters for format function
*** ./src/test/regress/sql/text.sql.orig 2010-08-24 08:30:44.000000000 +0200
--- ./src/test/regress/sql/text.sql 2010-09-09 09:17:50.920668808 +0200
***************
*** 41,43 ****
--- 41,49 ----
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 format('some text');
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', 'My tab', 'Hello', NULL, 10);
+ -- should fail
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', NULL, 'Hello', NULL, 10);
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', 'My tab', NULL, 'Hello');
+ select format('-- insert into %i (a,b,c) values(%l,%l,%l)', 'My tab', 'Hello', NULL, 10, 10);