How do I pass a table parameter to this function?

I have a function organized like this:

create function everything(waypoints waypoint)
  returns table(node int, xy text array) as $$
BEGIN
    create view results as ...

    return query (select * from results);
END;
$$ LANGUAGE plpgsql;

      

And I have a table where the arguments are organized the way the data type is structured waypoint

. This table is clearly not of type waypoint

.

The function is created as it should, however I cannot call it by going into my table like this:

select everything(waypoints);

Or select everything(select * from temp);

But he says there is a syntax error at or near select

for the latter and the column waypoints

does not exist for the former.

How can I proceed?

+3


source to share


2 answers


Everything is tested in Postgres 9.4 .

Postgres has several syntax weaknesses for handling ROW types. You cannot dump directly from the table (alias):

SELECT w::waypoint FROM waypoints w;
      

ERROR:  cannot cast type waypoints to waypoint

      

The solution is just one step away: expand the string into a subquery, then the job is done. This way the column values ​​are decomposed and transferred to the new type directly, without pushing on text

and back. You don't need to list all the columns individually, and you don't need to create a custom listing, either:

SELECT (w.*)::waypoint FROM (SELECT * FROM waypoints) w;

      

Or shorter:

SELECT w.*::waypoint FROM (TABLE waypoints) w;

      

Or shorter, but:

SELECT w::waypoint FROM (TABLE waypoints) w;

      

SQL Fiddle

It is shorter and faster, when tested quickly with 30k lines and simple types, it is 10x faster than text

back and forth. If you have (large) columns jsonb

or any complex type (expensive to / from conversion text

) the difference will be much larger.

More importantly, you don't need another custom composite (ROW) type. Each table already has its own row, defined as type automatically. Just use the existing type waypoints

instead waypoint

(if at all possible). Then you only need:



SELECT w FROM waypoints w;

      

Or for your example:

SELECT everything(t) FROM temp t;  -- using type waypoints
SELECT everything(t::waypoint) FROM (TABLE temp) t;  -- using type waypoint

      

Asides:

  • There are no "arguments" in the table, but columns.
  • You are not passing table parameter to this function

    , but rather the string value. The way you pass the table by name:

    You cannot "pass the entire table" as a parameter directly to Postgres, there are no table variables. You would use a cursor or temp table for this.

Function

Your function has an invalid type declaration and is unnecessarily complicated. I seriously doubt you want to create a view:

CREATE FUNCTION everything(_wp waypoint)  -- or use type waypoints
  RETURNS TABLE(node int, xy text[]) AS
$func$
BEGIN
   RETURN QUERY
   SELECT ...
END
$func$ LANGUAGE plpgsql;

      

text array

invalid syntax, using text[]

instead to declare an array text

.

Rather, don't use the table / type waypoints

name as the function parameter name, which would lead to confusing errors.

Or just use a simple SQL function if your case is simple as shown:

CREATE FUNCTION everything(_wp waypoint)  -- or use type waypoints
  RETURNS TABLE(node int, xy text[]) AS
$func$
   SELECT ...
$func$ LANGUAGE sql;

      

Do not include the language name. This is an identifier.

+6


source


If all types are in waypoint

and temp

convertible to text

, you can serialize and deserialize from text

:

SELECT  everything(temp::text::waypoint)
FROM    temp

      

However, an explicit construct would be cleaner:



SELECT  everything((col1, col2, col3, ...)::waypoint)
FROM    temp

      

or create CAST

:

CREATE FUNCTION temp_to_waypoint (temp)
RETURNS waypoint
AS
$$
        SELECT  (col1, col2, col3, ...)::waypoint
$$
LANGUAGE 'sql';

CREATE CAST (temp AS waypoint) WITH FUNCTION temp_to_waypoint (test) AS IMPLICIT;

SELECT  everything(temp)
FROM    temp;

      

+1


source







All Articles