Pavel Stehule escribió:

> Please, try to compile and run sprintf function from attachment

There's a minor bug in the comparison to PG_NARGS() inside the loop,
fixed in this version.

The one problem I have with this is that if the format string does not
contain any % (and thus there is no extra argument), it errors out:

alvherre=# select text_format('ouch');
ERROR:  function text_format(unknown) does not exist
LÍNEA 1: select text_format('ouch');
                ^
SUGERENCIA:  No function matches the given name and argument types. You might 
need to add explicit type casts.

AFAICS fixing this would require a second pg_proc entry for this
function.


alvherre=# select text_format('% was % at % and said % % times', 'Pavel'::text, 
'here'::unknown, now(), row('a','b','c'), '{42}'::int[]);
                                 text_format                                 
-----------------------------------------------------------------------------
 Pavel was here at 2009-09-10 13:12:09.054653-04 and said (a,b,c) {42} times
(1 fila)

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Index: src/backend/utils/adt/varlena.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/adt/varlena.c,v
retrieving revision 1.172
diff -c -p -r1.172 varlena.c
*** src/backend/utils/adt/varlena.c	4 Aug 2009 16:08:36 -0000	1.172
--- src/backend/utils/adt/varlena.c	10 Sep 2009 17:06:16 -0000
*************** text_position_cleanup(TextPositionState 
*** 1175,1180 ****
--- 1175,1242 ----
  	}
  }
  
+ Datum
+ text_format(PG_FUNCTION_ARGS)
+ {
+ 	char	   *fmt = text_to_cstring(PG_GETARG_TEXT_P(0));
+ 	StringInfo	str;
+ 	char	   *cp;
+ 	int			i = 1;
+ 
+ 	if (PG_ARGISNULL(0))
+ 		PG_RETURN_NULL();
+ 	
+ 	str = makeStringInfo();
+ 	
+ 	for (cp = fmt; *cp; cp++)
+ 	{
+ 		if (cp[0] == '%')
+ 		{
+ 			if (cp[1] == '%')
+ 			{
+ 				appendStringInfoChar(str, cp[1]);
+ 				cp++;
+ 				continue;
+ 			}
+ 			
+ 			if (i >= PG_NARGS())
+ 				ereport(ERROR,
+ 					   (errmsg("too few parameters specified for the format string")));
+ 			
+ 			if (PG_ARGISNULL(i))
+ 			{
+ 				appendStringInfoString(str, "NULL");
+ 			}
+ 			else
+ 			{
+ 				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);
+ 				appendStringInfoString(str, OidOutputFunctionCall(typoutput, value));
+ 			}
+ 			i++;
+ 		}
+ 		else
+ 			appendStringInfoChar(str, cp[0]);
+ 	}
+ 	
+ 	if (i != PG_NARGS())
+ 		ereport(ERROR,
+ 			   (errmsg("too many parameters for the format string")));
+ 	
+ 	pfree(fmt);
+ 
+ 	PG_RETURN_TEXT_P(CStringGetTextDatum(str->data));
+ }
+ 
+ 
  /* varstr_cmp()
   * Comparison function for text strings with given lengths.
   * Includes locale support, but must copy strings to temporary memory
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.550
diff -c -p -r1.550 pg_proc.h
*** src/include/catalog/pg_proc.h	1 Sep 2009 02:54:52 -0000	1.550
--- src/include/catalog/pg_proc.h	10 Sep 2009 16:52:48 -0000
*************** DATA(insert OID = 1257 (  textlen		   PG
*** 214,219 ****
--- 214,221 ----
  DESCR("length");
  DATA(insert OID = 1258 (  textcat		   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 25 "25 25" _null_ _null_ _null_ _null_ textcat _null_ _null_ _null_ ));
  DESCR("concatenate");
+ DATA(insert OID = 1259 (  text_format      PGNSP PGUID 12 1 0 2276 f f f t f i 2 0 25 "25 2276" "{25,2276}" "{i,v}" _null_ _null_ text_format _null_ _null_ _null_ ));
+ DESCR("format arguments, sprintf-style");
  
  DATA(insert OID =  84 (  boolne			   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "16 16" _null_ _null_ _null_ _null_ boolne _null_ _null_ _null_ ));
  DESCR("not equal");
Index: src/include/utils/builtins.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.339
diff -c -p -r1.339 builtins.h
*** src/include/utils/builtins.h	9 Sep 2009 19:00:09 -0000	1.339
--- src/include/utils/builtins.h	10 Sep 2009 16:35:34 -0000
*************** extern Datum text_substr(PG_FUNCTION_ARG
*** 698,703 ****
--- 698,704 ----
  extern Datum text_substr_no_len(PG_FUNCTION_ARGS);
  extern Datum name_text(PG_FUNCTION_ARGS);
  extern Datum text_name(PG_FUNCTION_ARGS);
+ extern Datum text_format(PG_FUNCTION_ARGS);
  extern int	varstr_cmp(char *arg1, int len1, char *arg2, int len2);
  extern List *textToQualifiedNameList(text *textval);
  extern bool SplitIdentifierString(char *rawstring, char separator,
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to