3

I have a function that accepts as parameter an array like:

CREATE OR REPLACE FUNCTION my_func(some_data custom_datum[]) RETURNS VOID AS $$
 BEGIN
 create table foo_table as (
 select
 coalesce(foo_ind, bar_ind, ter_ind) as foobarter,
 import_date,
 -- do some stuff here
 from unnest (some_data) as T
 group by grouping sets ((foo_ind, import_date), (bar_ind, import_date), (ter_ind, import_date))
 );
 END
$$ LANGUAGE plpgsql;

The input array is generated by another function foo. So I call everything in this way:

select my_func(array(select foo()));

where the function foo is:

CREATE OR REPLACE FUNCTION foo() RETURNS SETOF custom_datum

The problem is that for a big amount of data array(select foo()) returns:

ERROR: array size exceeds the maximum allowed (1073741823)

What I am trying to workaround is the lack of possibility to pass different functions, as at the moment, the input array gets generated by different functions:

select my_func(array(select foo()));
select my_func(array(select bar()));
select my_func(array(select ter()));
.... etc

How can I workaround this problem?

asked Sep 1, 2017 at 15:36
4
  • 1
    Passing in an array like that is usually a horrible idea, paste the definition of my_func Commented Sep 1, 2017 at 15:41
  • the definition of my_func is there Commented Sep 1, 2017 at 15:42
  • 2
    @Randomize I see the signature only. Commented Sep 1, 2017 at 15:43
  • I put the function. Yes actually I create and unnest an array which is quite useless but the problem is, how can I pass a set? Commented Sep 1, 2017 at 15:50

2 Answers 2

3

What your my_func is essentially doing is creating a MATERIALIZED VIEW -- a materialized view is a cached copy of a result set stored as a table. Drop the function and use the normal MATERIALIZED VIEW.

Skip generating an array -- waste of a time and space and may even be serializing the result set to disk twice. And, instead, just use something like this:

CREATE MATERIALIZED VIEW foo_view
AS
 SELECT whatever
 FROM wherever
 GROUP BY GROUPING SETS (
 (foo_ind, import_date),
 (bar_ind, import_date),
 (ter_ind, import_date)
 );

Now you can "refresh" this by doing REFRESH foo_view;

answered Sep 1, 2017 at 15:59
9
  • The problem is that I am workaround different kind of inputs. Please read my updated question. Commented Sep 1, 2017 at 16:06
  • @Randomize how did your function my_func return the table name of the table it generated? Commented Sep 1, 2017 at 16:09
  • it is not doing it at the moment Commented Sep 1, 2017 at 16:14
  • 1
    Just FYI @Randomize, A SQL array is a container type. It's not meant to hold a result set. And doing that is going to sting no way around it -- it's going to be worse in every way (slower, memory intensive, less terse, etc) Commented Sep 1, 2017 at 16:22
  • 1
    SQL is a declarative language that has a declarative method that takes a query and generates an on disk cache of that query. You don't need to write a function that accepts an array, or accepts a text query, you just need CREATE MATERIALIZED VIEW that's sql-esque. That's the SQL way to do it. Commented Sep 1, 2017 at 17:24
1

You can possibly limit the output of foo():

SELECT foo() LIMIT 10000;

Or, most probably better, avoid using arrays altogether (pass the set, not an array made of it). For this, you will, of course, have to rewrite my_func(). Thinking about it, I can imagine that this will be beneficial from a performance point of view, too.

answered Sep 1, 2017 at 15:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.