Use this file to discover all available pages before exploring further.
PostgreSQL database functions allow you to encapsulate business logic directly in your database. Functions can be written in SQL, PL/pgSQL, or other procedural languages, and can be called from your application code via the Supabase client libraries.
create or replace function get_shipping_cost( total_amount numeric, country_code text)returns numericlanguage plpgsqlas $$declare shipping_cost numeric;begin -- Free shipping for orders over $100 if total_amount >= 100 then return 0; end if; -- Different rates by country case country_code when 'US' then shipping_cost := 9.99; when 'CA' then shipping_cost := 12.99; when 'GB' then shipping_cost := 14.99; else shipping_cost := 19.99; end case; return shipping_cost;end;$$;
create or replace function get_product_by_id(product_id bigint)returns table ( id bigint, name text, price numeric, in_stock boolean)language sqlas $$ select id, name, price, (quantity > 0) as in_stock from products where id = product_id;$$;
create or replace function get_top_rated_movies(min_rating numeric)returns table ( id bigint, name text, rating numeric, release_year integer)language sqlas $$ select id, name, rating, release_year from movies where rating >= min_rating order by rating desc limit 10;$$;
create or replace function get_active_users()returns setof users -- Returns rows matching the users table structurelanguage sqlas $$ select * from users where deleted_at is null and last_login > now() - interval '30 days';$$;
create or replace function update_inventory( product_id bigint, quantity_change integer)returns booleanlanguage plpgsqlas $$declare current_qty integer;begin -- Get current quantity select quantity into current_qty from products where id = product_id; -- Check if we have enough stock if current_qty + quantity_change < 0 then raise exception 'Insufficient inventory'; end if; -- Update quantity update products set quantity = quantity + quantity_change, updated_at = now() where id = product_id; return true;end;$$;
-- Runs with creator's permissions (security definer)create function admin_function()returns voidlanguage plpgsqlsecurity definerset search_path = publicas $$begin -- Can access tables the creator has access to delete from sensitive_table where expired = true;end;$$;-- Runs with caller's permissions (security invoker - default)create function user_function()returns voidlanguage plpgsqlsecurity invokeras $$begin -- Can only access what the caller has access to select * from public.products;end;$$;
When using security definer, always set search_path to prevent security vulnerabilities.
-- Revoke public executionrevoke execute on function sensitive_function() from public;revoke execute on function sensitive_function() from anon;-- Grant to specific rolegrant execute on function sensitive_function() to authenticated;
Restrict all new functions by default:
alter default privileges in schema public revoke execute on functions from public;alter default privileges in schema public revoke execute on functions from anon, authenticated;
create or replace function withdraw_funds( account_id bigint, amount numeric)returns voidlanguage plpgsqlas $$declare current_balance numeric;begin -- Get current balance select balance into current_balance from accounts where id = account_id; -- Validate amount if amount <= 0 then raise exception 'Amount must be positive'; end if; -- Check sufficient funds if current_balance < amount then raise exception 'Insufficient funds. Balance: %, Requested: %', current_balance, amount; end if; -- Perform withdrawal update accounts set balance = balance - amount where id = account_id;end;$$;
create or replace function process_order(order_id bigint)returns voidlanguage plpgsqlas $$declare order_total numeric;begin select total into order_total from orders where id = order_id; -- Throw error if order not found assert order_total is not null, 'Order not found'; -- Throw error if invalid total assert order_total > 0, 'Invalid order total'; -- Process the order...end;$$;
create or replace function safe_insert_product(product_name text)returns textlanguage plpgsqlas $$begin insert into products (name) values (product_name); return 'Success';exception when unique_violation then return 'Product already exists'; when others then return 'Error: ' || sqlerrm;end;$$;
create or replace function debug_function(input_val text)returns textlanguage plpgsqlas $$declare result text;begin raise log 'Function started with input: %', input_val; -- Do some work result := upper(input_val); raise log 'Result calculated: %', result; return result;end;$$;
-- IMMUTABLE: always returns same result for same inputscreate function add_numbers(a int, b int)returns intlanguage sqlimmutableas $$ select a + b;$$;-- STABLE: same result within a single querycreate function get_current_date()returns datelanguage sqlstableas $$ select current_date;$$;-- VOLATILE: result may change (default)create function generate_id()returns uuidlanguage sqlvolatileas $$ select gen_random_uuid();$$;