Examples

October 7, 2025 ยท View on GitHub

Hello, world

DO LANGUAGE plhaskell $$
  import PGutils
    ( PGm,
      notice,
      report,
    )

  _' :: PGm ()
  _' = report notice "Hello, world!"
$$;
DO LANGUAGE plhaskellu $$
  import PGutils
    ( notice,
      report,
      unPGm,
    )

  _' :: IO ()
  _' = unPGm $ report notice "Hello, world!"
$$;

Addition

CREATE FUNCTION add(int, int) RETURNS int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( PGm,
    )

  add :: Maybe Int32 -> Maybe Int32 -> PGm (Maybe Int32)
  add Nothing Nothing = return Nothing
  add (Just a) (Just b) = return $ Just $ a + b
  add a Nothing = return a
  add Nothing b = return b
$$
LANGUAGE plhaskell;
CREATE FUNCTION add(int, int) RETURNS int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )

  add :: Maybe Int32 -> Maybe Int32 -> IO (Maybe Int32)
  add Nothing Nothing = return Nothing
  add (Just a) (Just b) = return $ Just $ a + b
  add a Nothing = return a
  add Nothing b = return b
$$
LANGUAGE plhaskellu;

Fibonacci Sequence

CREATE FUNCTION fibonacci(int) RETURNS int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( PGm,
    )

  fibonacci' :: Int32 -> Int32
  fibonacci' 0 = 0
  fibonacci' 1 = 1
  fibonacci' n = fibonacci' (n - 2) + fibonacci' (n - 1)

  fibonacci :: Maybe Int32 -> PGm (Maybe Int32)
  fibonacci = return . fmap fibonacci'
$$
LANGUAGE plhaskell;
CREATE FUNCTION fibonacci(int) RETURNS int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )

  fibonacci' :: Int32 -> Int32
  fibonacci' 0 = 0
  fibonacci' 1 = 1
  fibonacci' n = fibonacci' (n - 2) + fibonacci' (n - 1)

  fibonacci :: Maybe Int32 -> IO (Maybe Int32)
  fibonacci = return . fmap fibonacci'
$$
LANGUAGE plhaskellu;

Primes

This section shows how to return a set of results. The functions listed produce lists of prime numbers using the Sieve of Eratosthenes.

Composite Type

The functions in this section return a set of composite results.

CREATE TYPE n_p AS (n int, p int);
CREATE FUNCTION primes(int) RETURNS SETOF n_p IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( PGm,
      raiseError,
    )

  sieve :: [Int32] -> [Int32]
  sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
  sieve [] = []

  primes :: Maybe Int32 -> PGm [Maybe (Maybe Int32, Maybe Int32)]
  primes Nothing = raiseError "Invalid Null"
  primes (Just n) = return $ zipWith (curry Just) ([Just i | i <- [1 .. n]]) (map Just $ sieve [2 .. ])
$$
LANGUAGE plhaskell;
CREATE FUNCTION primes(int) RETURNS SETOF n_p IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( raiseError,
    )

  sieve :: [Int32] -> [Int32]
  sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
  sieve [] = []

  primes :: Maybe Int32 -> IO [Maybe (Maybe Int32, Maybe Int32)]
  primes Nothing = raiseError "Invalid Null"
  primes (Just n) = return $ zipWith (curry Just) ([Just i | i <- [1 .. n]]) (map Just $ sieve [2 .. ])
$$
LANGUAGE plhaskellu;

By running the query

SELECT *
FROM primes(10)

The following is produced

np
12
23
35
47
511
613
717
819
923
1029

Infinite List

The following functions return a infinite list of prime numbers

CREATE FUNCTION primes() RETURNS SETOF int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( PGm,
    )

  sieve :: [Int32] -> [Int32]
  sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p /= 0]

  primes :: PGm [Maybe Int32]
  primes = return $ map Just $ sieve [2 ..]
$$
LANGUAGE plhaskell;
CREATE FUNCTION primes() RETURNS SETOF int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )

  sieve :: [Int32] -> [Int32]
  sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p /= 0]

  primes :: IO [Maybe Int32]
  primes = return $ map Just $ sieve [2 ..]
$$
LANGUAGE plhaskellu;

To generate the first twenty-five prime numbers, run:

SELECT primes()
LIMIT 25
primes
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97

Array

The following add one to all non-null elements of an array.

CREATE FUNCTION increment_array(int[]) RETURNS int[] IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( Array,
      PGm,
      arrayMap,
    )

  increment_array :: Maybe (Array (Maybe Int32)) -> PGm (Maybe (Array (Maybe Int32)))
  increment_array  = return . (fmap $ arrayMap $ fmap succ)
$$
LANGUAGE plhaskell;
CREATE FUNCTION increment_array(int[]) RETURNS int[] IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( Array,
      arrayMap,
    )

  increment_array :: Maybe (Array (Maybe Int32)) -> IO (Maybe (Array (Maybe Int32)))
  increment_array  = return . (fmap $ arrayMap $ fmap succ)
$$
LANGUAGE plhaskellu;

Message

The following demonstrate how to show a notice from within a function.

CREATE FUNCTION forty_two() RETURNS int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( PGm,
      notice,
      report,
    )

  forty_two :: PGm (Maybe Int32)
  forty_two = do
    report notice "Don't Panic"
    return $ Just 42
$$
LANGUAGE plhaskell;
CREATE FUNCTION forty_two() RETURNS int IMMUTABLE AS
$$
  import Data.Int
    ( Int32,
    )
  import PGutils
    ( notice,
      report,
      unPGm,
    )

  forty_two :: IO (Maybe Int32)
  forty_two = do
    unPGm $ report notice "Don't Panic"
    return $ Just 42
$$
LANGUAGE plhaskellu;

Query

The following delete all elements of table t and return the number of rows removed.

CREATE FUNCTION remove_all() RETURNS bigint VOLATILE AS
$$
  import Data.Int
    ( Int64,
    )
  import PGutils
    ( PGm,
      QueryResults (DeleteResults),
      query,
    )

  remove_all :: PGm (Maybe Int64)
  remove_all = do
    DeleteResults processed <- query "DELETE FROM t" []
    return $ Just $ fromIntegral processed
$$
LANGUAGE plhaskell;
CREATE FUNCTION remove_all() RETURNS bigint VOLATILE AS
$$
  import Data.Int
    ( Int64,
    )
  import PGutils
    ( QueryResults (DeleteResults),
      query,
      unPGm,
    )

  remove_all :: IO (Maybe Int64)
  remove_all = do
    DeleteResults processed <- unPGm $ query "DELETE FROM t" []
    return $ Just $ fromIntegral processed
$$
LANGUAGE plhaskellu;

The following return the last names of students with the passed first name.

CREATE FUNCTION last_names(text) RETURNS SETOF text IMMUTABLE AS
$$
  import Data.Text
    ( Text,
    )
  import PGutils
    ( PGm,
      QueryParam (QueryParamText),
      QueryResultValue (QueryResultValueText),
      QueryResults (SelectResults),
      query,
    )

  extract_text :: [QueryResultValue] -> Maybe Text
  extract_text [QueryResultValueText name] = name

  last_names :: Maybe Text -> PGm [Maybe Text]
  last_names first_name = do
    SelectResults _processed _header results <- query "SELECT last_name FROM students WHERE first_name = \$1" [QueryParamText first_name]
    return $ map extract_text results
$$
LANGUAGE plhaskell;
CREATE FUNCTION last_names(text) RETURNS SETOF text IMMUTABLE AS
$$
  import Data.Text
    ( Text,
    )
  import PGutils
    ( QueryParam (QueryParamText),
      QueryResultValue (QueryResultValueText),
      QueryResults (SelectResults),
      query,
      unPGm,
    )

  extract_text :: [QueryResultValue] -> Maybe Text
  extract_text [QueryResultValueText name] = name

  last_names :: Maybe Text -> IO [Maybe Text]
  last_names first_name = do
    SelectResults _processed _header results <- unPGm $ query "SELECT last_name FROM students WHERE first_name = \$1" [QueryParamText first_name]
    return $ map extract_text results
$$
LANGUAGE plhaskellu;