Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL function returning an arbitrary type

Is there any way to have a function in PostgreSQL return an arbitrary type?

I am trying to use PLV8 to grab and compare fields from a JSON type in PostgreSQL 9.2.

The following works:

CREATE or replace FUNCTION jn (j json, key any ) RETURNS numeric 
LANGUAGE plv8   
IMMUTABLE 
AS $function$  
  var ej = JSON.parse(j);   
  if (typeof ej != 'object') return NULL;   
  return JSON.stringify(ej[key]);  
$function$;

SELECT * FROM things WHERE jn(data,'count') <= '10';

Returning the where the count field is <= 10. BUT, it fails if the field is not numeric. I don't want to create a specific function for every type of data my json might hold, is there a way to have the data type inferred somehow and cast implicitly?

See also How do I query using fields inside the new PostgreSQL JSON datatype?

like image 555
Toby Hede Avatar asked Oct 17 '25 02:10

Toby Hede


1 Answers

You seem to be looking for functions with Polymorphic types.
Read the above section on types and the last 2 examples in this section.

Note, that types of the key parameter and function's output should match. If this is not your case, then you should probably return text and then cast it to the right type outside the function.

I think this will do the job for you:

CREATE or replace FUNCTION jn (j json, key anyelement ) RETURNS anyelement
LANGUAGE plv8   
IMMUTABLE 
AS $function$  
  var ej = JSON.parse(j);   
  if (typeof ej != 'object') return NULL;   
  return JSON.stringify(ej[key]);  
$function$;

Sorry, I don't have 9.2 server around so I cannot test this.


EDIT:

Things is — before you will be able to perform any casts within the function, it must be created first. At creation time function's input parameters' types and return type is fixed. This means you have only 2 possibilities:

  • use anyelement type, which will force you to have key parameter having the same type you want to be returned from the function;
  • use text type and cast results outside the function.

As PLV8 doesn't support anyelement types yet, you can actually create a wrapper function on PL/pgSQL on top of it to do the job for you:

CREATE FUNCTION jn_wrap(jn varchar, key anyelement, OUT ret anyelement)
    AS $js_wrap$
BEGIN
    EXECUTE 'SELECT CAST(jn($1, $2) AS '||pg_typeof(key)||')'
        USING jn, key INTO ret;

    RETURN ;
END;
$js_wrap$ LANGUAGE plpgsql;

Though I think it might be quite typical, that key's type will differ from the desired return type.

like image 86
vyegorov Avatar answered Oct 19 '25 21:10

vyegorov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!