2

I need a function like

SELECT vformat('Hello %%! Bye %%...', array['John','Maria'], '%%');
-- 'Hello John! Bye Maria...'

Supplying a string with placeholders (a template), and corresponding inputs into a vector, it returns a text. The "placeholder mark" is a free string.

I can't use the pg9.1 format (like sprintf) function, because it does not allow other mark than '%' (see ex. Python formatter) and not allow array parameter (see ex. vsprintf). The SIMPLEST solution with PostgreSQL 9.0 (I think 8.4+) is

CREATE FUNCTION array_zipper_string(anyarray,anyarray) RETURNS text AS $$ 
  -- use with bigger array at left
  SELECT string_agg(t.val||coalesce($2[t.idx],''),'')  
  FROM  (SELECT generate_subscripts($1, 1) AS idx, unnest($1) AS val) AS t;
$$ LANGUAGE SQL IMMUTABLE;

CREATE FUNCTION tpl_positional(text,anyarray,varchar DEFAULT '%%') 
RETURNS text AS $$ 
  SELECT array_zipper_string(string_to_array($1,$3),$2);
$$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION tpl_positional(
   text, text, varchar DEFAULT '%%',varchar DEFAULT '|' 
) RETURNS text AS $$ 
  SELECT tpl_positional($1,string_to_array($2,$4),$3);
$$ LANGUAGE SQL IMMUTABLE;

-- TESTING:
SELECT tpl_positional('Hello %%! Bye %%...', 'John|Maria');
SELECT tpl_positional('Hello %%!',array['John']);

There are well-knowed (open source) function or library for do the same?

PS: that do this and also something more (!) ... My wishes list:

  • open source from a standard library
  • option to indexable placeholders, 'Hello %%{1}! Bye %%{2}...'
  • option to use formatters, 'There are %%2d monkeys.' or 'There are %%{1|2d} monkeys.';
4

3 回答 3

4

PostgreSQL FORMAT() function formats arguments based on a format string.

If you have worked with C programming language, you will find that the FORMAT() function is similar to the sprintf() function.

SELECT FORMAT('Hello, %s','PostgreSQL');

      format
-------------------
 Hello, PostgreSQL
(1 row)

For details, see http://www.postgresqltutorial.com/postgresql-format/

于 2018-04-10T16:32:06.157 回答
2

If Python's formatting function does what you need, wrap it via PL/Python, and use that. You'll need to:

CREATE LANGUAGE plpythonu;

... which may require you to install an additional package containing the python language support or re-compile using --with-python, depending on how you installed Pg or the packages you're using. For me using the Fedora 17 packages it was yum install postgresql-plpython.

You'll need a signature like:

CREATE OR REPLACE FUNCTION my_format(formatstr text, placeholder text, args VARIADIC text) RETURNS text LANGUAGE 'plpythonu' IMMUTABLE AS $$
 .... body here ....
 $$;

Note the usage plpythonu. Here u means "untrusted", ie "has no security model". Code running in untrusted languages can't be restricted, so the server only permits the superuser to create functions in such languages. They must be written so that they can't be tricked into doing things other than the author intended if the database is exposed to less-trusted users.

Unfortunately the procedural languages' handling of arrays was, last I checked, less than wonderful. See the depesz article at the bottom of this post, and its comments. It's workable, just clumsier than would be nice.

If Python's format functionality doesn't do what you want, consider Perl. PL/Perl is very popular, partly because unlike Python it has a security model and there's a "trusted" version of plperl. I'll be very surprised if you can't find a suitable CPAN module to do what you want. The function signature would be much the same, just with plperl.

See this excellent-as-usual depesz article on plperl and sprintf.

于 2012-09-03T22:55:32.523 回答
1

Other possibility is using orafce http://postgres.cz/wiki/Oracle_functionality_%28en%29 - functions from schema ''PLVsubst'' does exactly what you want. Orafce is in redhat, centos repositories, but it is not enabled on any hosting usually.

于 2012-09-04T05:14:33.227 回答