Re: postgres array quoting - Mailing list pgsql-general

From Marc Evans
Subject Re: postgres array quoting
Date
Msg-id 20060901080954.J22986@me.softwarehackery.com
Whole thread Raw
In response to postgres array quoting  (marc@softwarehackery.com)
List pgsql-general
On Thu, 31 Aug 2006, marc@softwarehackery.com wrote:

> Hello -
>
> I am attempting to find a way to make use of arrays of text, as demonstraited
> by the following:
>
> CREATE TABLE messages (
>  id SERIAL,
>  format TEXT NOT NULL,
>  arguments TEXT[]
> );
>
> Into that table will be values that you would associate with some form of
> printf. For example:
>
> INSERT INTO messages (format,arguments)
>  VALUES ('hello %s','{"world"}');
> INSERT INTO messages (format,arguments)
>  VALUES ('test 2 %s %s','{"one","two"}');
> INSERT INTO messages (format,arguments)
>  VALUES ('test 3 %s','{"abc","d,e,f","g,\\"h,i\'"}');
>
> A select shows the following:
>
> id |    format    |        arguments
> ----+--------------+--------------------------
>  1 | hello %s     | {world}
>  2 | test 2 %s %s | {one,two}
>  3 | test 3 %s    | {abc,"d,e,f","g,\"h,i'"}
>
> The goal of this table is to extract each row and pass it to some variation
> of printf. My problem is that I can't figure out a good way to do this, and
> am hoping that someone has already found a way.
>
> * If I could figure a way to pass a variable number of arguments to a
>   plperl function, or an array reference, I could use something like this
>   function:
>
> CREATE OR REPLACE FUNCTION audit_log_format(TEXT,...) RETURNS TEXT AS $$
>  return sprintf shift,@_;
> $$ LANGUAGE plperl;
>
> * If I could figure out a way to force select to always apply
>   escaping/quoting logic to each of the elements in the arguments array,
>   then I could probably find a way to do this. This split is non-trivial,
>   but doable.
>
> * If I could perform a select within a plperl function and receive back
>   a perl array for the arguments column, I could use a plperl function
>   kinda like the one above, except taking an ID value as the argument.
>
> Given the number of ways that things could be escaped in text stored in the
> arguments array, such as embedded quotes, commas, back slashes, etc,
> compounded by the lack of quotes in same cases but not others, parsing the
> output of a select is difficult at best. I suspect that it is sadly my only
> option.
>
> Suggestions?

Thanks to all that had feedback. So that the archives contain a functional
(though very ugly) solution, here is what I have found can be made to
work. The key to it is that it retrieves each element of the array one at
a time, building a perl array which it then hands to the sprintf function.

-- The first argument is the format string to hand sprintf. This is
-- seperate to allow easier I18N, e.g. the caller hands this function a
-- localized string.
-- The second argument is the ID of the record to be formatted.
CREATE OR REPLACE FUNCTION log_sprintf(text,integer) RETURNS TEXT as $$
   my $fmt = shift;
   my $id = shift;
   my $msg = spi_exec_query("SELECT array_upper(msg_args,1) FROM logs WHERE id = $id",1);
   my $nArgs = $msg->{rows}[0]->{array_upper};
   my $i = 1;
   my @args;
   while ($i <= $nArgs) {
     $msg = spi_exec_query("SELECT msg_args[$i] FROM logs WHERE id = $id",1);
     push(@args,$msg->{rows}[0]->{msg_args});
     $i++;
   }
   return sprintf $fmt,@args;
$$ LANGUAGE plperl;

- Marc

pgsql-general by date:

Previous
From: "Dan"
Date:
Subject: Re: Create user or role from inside a function?
Next
From: "Boguk Maxim"
Date:
Subject: Some strange plans choosed by postgres for one query: