Writing hypothetical aggregates

Writing aggregates is not hard and can be highly beneficial for performing more complex operations. In this section, the plan is to write a hypothetical aggregate, which has already been discussed in this chapter.

Implementing hypothetical aggregates is not too different from writing normal aggregates. The really hard part is figuring out when to actually use one. To make this section as easy to understand as possible, I have decided to include a trivial example: given a specific order, what would the result be if we added abc to the end of the string?

Here is how it works:

CREATE AGGREGATE name  ( [ [ argmode ] [ argname ] arg_data_type [ , ... ] ]  
   ORDER  BY [ argmode ] [ argname ] arg_data_type  
   [ , ...])  
( 
   SFUNC  = sfunc, 
   STYPE  = state_data_type 
   [ , SSPACE = state_data_size ] [ , FINALFUNC = ffunc  ] 
   [ , FINALFUNC_EXTRA ] 
   [ , INITCOND = initial_condition ] 
   [ , PARALLEL = { SAFE  | RESTRICTED | UNSAFE } ] [ , HYPOTHETICAL ] 
) 

Two functions will be needed. The sfunc function will be called for every line:

CREATE FUNCTION hypo_sfunc(text, text)  
   RETURNS text  AS 
$$  
   BEGIN 
         RAISE  NOTICE 'hypo_sfunc called with  % and %', $1, $2;  
         RETURN $1 || $2; 
   END; 
$$ LANGUAGE 'plpgsql'; 

Two parameters will be passed to the procedure. The logic is the same as it was previously. Just like we did earlier, a final function call can be defined:

CREATE FUNCTION hypo_final(text, text,  text)  
   RETURNS text  AS 
$$  
   BEGIN 
         RAISE  NOTICE 'hypo_final called with  %, %, and %', 
               $1, $2, $3;  
         RETURN $1 || $2; 
   END; 
$$ LANGUAGE 'plpgsql'; 

Once these functions are in place, the hypothetical aggregate can be created:

CREATE AGGREGATE whatif(text ORDER  BY text)   
(   
   INITCOND = 'START', 
   STYPE  = text, 
   SFUNC  = hypo_sfunc,  
   FINALFUNC = hypo_final,  
   FINALFUNC_EXTRA = true,  
   HYPOTHETICAL 
); 

Note that the aggregate has been marked as hypothetical so that PostgreSQL will know what kind of aggregate it actually is.

Now that the aggregate has been created, it is possible to run it:

test=# SELECT whatif('abc'::text) WITHIN GROUP (ORDER BY id::text)  
       FROM     generate_series(1, 3) AS id; 
psql: NOTICE: hypo_sfunc called with START and 1 psql: NOTICE: hypo_sfunc called with START1 and 2 psql: NOTICE: hypo_sfunc called with START12 and 3 psql: NOTICE: hypo_final called with START123, abc, and <NULL> whatif ------------- START123abc (1 row)

The key to understanding all of these aggregates is really to fully see when each kind of function is called and how the overall machinery works.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset