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 | 162 | 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-09-09 02:48:22.000000000 +0200
--- ./doc/src/sgml/func.sgml 2010-09-29 07:18:59.845395002 +0200
***************
*** 1272,1277 ****
--- 1272,1280 ----
<primary>encode</primary>
</indexterm>
<indexterm>
+ <primary>format</primary>
+ </indexterm>
+ <indexterm>
<primary>initcap</primary>
</indexterm>
<indexterm>
***************
*** 1495,1500 ****
--- 1498,1520 ----
<entry><literal>encode(E'123\\000\\001', 'base64')</literal></entry>
<entry><literal>MTIzAAE=</literal></entry>
</row>
+
+ </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>initcap(<parameter>string</parameter>)</function></literal></entry>
*** ./src/backend/utils/adt/varlena.c.orig 2010-09-29 07:16:25.744395786 +0200
--- ./src/backend/utils/adt/varlena.c 2010-09-29 09:51:39.340270718 +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"
***************
*** 48,53 ****
--- 50,61 ----
int skiptable[256]; /* skip distance for given mismatched char */
} TextPositionState;
+ typedef struct
+ {
+ int n_valid_oids;
+ Oid typoutput[FUNC_MAX_ARGS];
+ } format_fn_extra_cache;
+
#define DatumGetUnknownP(X) ((unknown *) PG_DETOAST_DATUM(X))
#define DatumGetUnknownPCopy(X) ((unknown *) PG_DETOAST_DATUM_COPY(X))
#define PG_GETARG_UNKNOWN_P(n) DatumGetUnknownP(PG_GETARG_DATUM(n))
***************
*** 3702,3704 ****
--- 3710,3866 ----
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 \\%.*s", pg_mblen(&cp[1]), &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 \"%%%.*s\"", pg_mblen(cp), cp)));
+ }
+ 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 \"%%%.*s\"", pg_mblen(cp), cp)));
+ }
+ 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-09-03 03:34:55.000000000 +0200
--- ./src/include/catalog/pg_proc.h 2010-09-29 07:16:42.658395449 +0200
***************
*** 2741,2746 ****
--- 2741,2750 ----
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-09-03 03:34:55.000000000 +0200
--- ./src/include/utils/builtins.h 2010-09-29 07:16:42.661395833 +0200
***************
*** 742,747 ****
--- 742,749 ----
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-09-29 07:16:25.749395800 +0200
--- ./src/test/regress/expected/text.out 2010-09-29 07:16:42.662395333 +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-09-29 07:16:25.751395218 +0200
--- ./src/test/regress/sql/text.sql 2010-09-29 07:16:42.662395333 +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);