diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index eadf41f..cf65b5e 100644 *** a/src/backend/catalog/pg_aggregate.c --- b/src/backend/catalog/pg_aggregate.c *************** *** 34,40 **** #include "utils/syscache.h" ! static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid *rettype); --- 34,40 ---- #include "utils/syscache.h" ! extern Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, Oid *rettype); *************** AggregateCreate(const char *aggName, *** 298,304 **** /* * lookup_agg_function -- common code for finding both transfn and finalfn */ ! static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, --- 298,304 ---- /* * lookup_agg_function -- common code for finding both transfn and finalfn */ ! Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index ee83e2f..b324b48 100644 *** a/src/backend/utils/adt/varlena.c --- b/src/backend/utils/adt/varlena.c *************** *** 22,27 **** --- 22,28 ---- #include "libpq/md5.h" #include "libpq/pqformat.h" #include "miscadmin.h" + #include "parser/parser.h" #include "parser/scansup.h" #include "regex/regex.h" #include "utils/builtins.h" *************** text_format(PG_FUNCTION_ARGS) *** 3820,3825 **** --- 3821,3915 ---- isNull = PG_ARGISNULL(arg); typid = get_fn_expr_argtype(fcinfo->flinfo, arg); + if (*cp == '{') + { + const char *format = cp + 1; + + /* search right parensis */ + for (; cp < end_ptr && *cp != '}'; cp++) + { + /* XXX: Should we supply a method to escape '}' ? */ + } + if (cp >= end_ptr) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("conversion format is incomplete"))); + + /* format the value with to_char function */ + if (!isNull) + { + Oid fnOid; + Oid rettype; + Datum formatDatum; + + #define enable_dynamic_to_char_lookup 0 + + if (enable_dynamic_to_char_lookup) + { + Oid input_types[2]; + + extern Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, + Oid *rettype); + + /* + * Only lookup pg_catalog.to_char() and avoid searching + * functions in search_path so that it should not be a + * security hole. + */ + input_types[0] = typid; + input_types[1] = TEXTOID; + fnOid = lookup_agg_function(SystemFuncName("to_char"), + 2, input_types, &rettype); + } + else + { + rettype = TEXTOID; + + switch (typid) + { + case INT4OID: + fnOid = 1773; + break; + case INT8OID: + fnOid = 1774; + break; + case FLOAT4OID: + fnOid = 1775; + break; + case FLOAT8OID: + fnOid = 1776; + break; + case NUMERICOID: + fnOid = 1772; + break; + case TIMESTAMPTZOID: + fnOid = 1770; + break; + case TIMESTAMPOID: + fnOid = 2049; + break; + case INTERVALOID: + fnOid = 1768; + break; + default: + elog(ERROR, "unsupported type oid: %u", typid); + fnOid = rettype = InvalidOid; /* keep compiler quiet */ + } + } + + formatDatum = PointerGetDatum( + cstring_to_text_with_len(format, cp - format)); + value = OidFunctionCall2(fnOid, value, formatDatum); + typid = rettype; + } + + /* Did we run off the end of the string? */ + if (++cp >= end_ptr) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unterminated conversion specifier"))); + } + switch (*cp) { case 's':