Stored procedures encapsulate SQL logic on the server, enabling reusable, transactional routines.
Stored procedures let you keep complex logic close to your ParadeDB data, run several SQL statements atomically, and reuse the same code from many clients without shipping it in application code.
Create a procedure when you need multi-step business logic, frequent reuse, tight security, or want to reduce network round-trips. Simple read-only analytics usually stay as plain SQL.
Use CREATE PROCEDURE with a name, parameter list, language, and body. Most ParadeDB users write PL/pgSQL because it supports variables and flow control.
This procedure sums paid Orders and returns the value. It demonstrates parameters, variables, and OUT arguments.
CREATE OR REPLACE PROCEDURE calc_lifetime_spend(
IN p_customer_id INT,
OUT p_total NUMERIC
) LANGUAGE plpgsql AS $$
BEGIN
SELECT COALESCE(SUM(total_amount), 0)
INTO p_total
FROM Orders
WHERE customer_id = p_customer_id;
END;
$$;
Run CALL with matching positional parameters. ParadeDB returns OUT values as a result set.
CALL calc_lifetime_spend(42);
Yes. All statements inside the procedure run in the same transaction started by CALL. Errors roll back automatically unless you trap them.
Use CREATE OR REPLACE PROCEDURE to update in place, or DROP PROCEDURE if it is no longer needed. Specify the full parameter signature when dropping.
CREATE OR REPLACE PROCEDURE calc_lifetime_spend(
IN p_customer_id INT,
OUT p_total NUMERIC,
OUT p_last_order DATE
) LANGUAGE plpgsql AS $$
BEGIN
SELECT COALESCE(SUM(total_amount), 0), MAX(order_date)
INTO p_total, p_last_order
FROM Orders
WHERE customer_id = p_customer_id;
END;
$$;
CREATEDB users with the CREATE privilege on the current schema can create procedures. To run them, grant EXECUTE ON PROCEDURE name TO role.
Use schema-qualified names, add comments with COMMENT ON, avoid dynamic SQL when static can work, and write unit tests in pgTAP or similar.
See the mistakes section below for frequent issues and fixes.
Yes, but only when the CALL is not already inside another transaction block. Use COMMIT or ROLLBACK to split large batch work where needed.
Add RAISE NOTICE statements for variable values, or attach pldbgapi-compatible debuggers such as the one in DataGrip. Logging levels can be increased for procedure sessions.
Performance gains come from reduced latency and pre-parsed plans rather than raw execution speed. For chatty workloads the savings are significant.