Search code examples
postgresqlpostgraphile

PostgreSQL: How to Pass a Rowset to a Function


I'm using Postgraphile, which has you create functions that take row sets as arguments. For instance, I have a function that takes a system_versions row set as a parameter:

CREATE OR REPLACE FUNCTION public.system_versions_edition_versions(
    system_version system_versions,
    system_title character varying DEFAULT NULL::character varying
 )
 RETURNS SETOF edition_versions
 LANGUAGE sql
 STABLE STRICT SECURITY DEFINER
 AS $function$

        SELECT ev.*
        FROM public.edition_versions ev
        INNER JOIN public.editions e ON ev.edition_id  = e.id
        INNER JOIN public.systems s ON e.system_id  = s.id
        INNER JOIN public.system_versions sv ON s.id  = sv.system_id
        WHERE sv.id = system_version.id
        AND (
          system_title IS NULL
          OR
          sv.title = system_title
        )
  ;
  $function$
;

Normally these functions are called by Postgraphile, but I need to call this one manually for testing ... and I can't figure out how to provide the parameter.

When I try:

SELECT public.system_versions_edition_versions(public.system_versions);

I get:

ERROR:  missing FROM-clause entry for table "public"
LINE 1: select public.system_versions_edition_versions(public.system...

But when I try to SELECT the table ...

SELECT public.system_versions_edition_versions(SELECT * FROM public.
system_versions);

I get:

ERROR:  syntax error at or near "select"
LINE 1: select public.system_versions_edition_versions(select * from...

When I have a function with a "row set" parameter, can anyone explain how I provide that parameter?


Solution

  • It looks like system_version argument type is row rather than rowset. Otherwise sv.id = system_version.id would cause an error. Since public.system_versions is a table then system_versions is its row type, like system_versions%rowtype in PL/pgSQL.
    You can call it using a scalar subquery like this:

    SELECT public.system_versions_edition_versions(
     (
      SELECT t
      FROM public.system_versions t
      -- WHERE <your logic here>
      LIMIT 1 -- a scalar subquery must return a single row
     )
    );
    

    or

    select public.system_versions_edition_versions(t)
    from public.system_versions t
    -- where <your logic here>;
    

    You may also consider using a lateral join.