Working with Stored Procedures
1. Creating Procedure
CREATE PROCEDURE archive_old_orders(cutoff date)
LANGUAGE plpgsql AS $
BEGIN
INSERT INTO orders_archive SELECT * FROM orders WHERE placed_at < cutoff;
DELETE FROM orders WHERE placed_at < cutoff;
COMMIT;
END $;
2. Calling Procedure
CALL archive_old_orders('2024-01-01');
3. Using Transaction Control
CREATE PROCEDURE batch_process() LANGUAGE plpgsql AS $
BEGIN
LOOP
WITH batch AS (SELECT id FROM queue LIMIT 1000 FOR UPDATE SKIP LOCKED)
DELETE FROM queue WHERE id IN (SELECT id FROM batch);
EXIT WHEN NOT FOUND;
COMMIT;
END LOOP;
END $;
| Allowed In Procedure | Allowed In Function |
|---|---|
| COMMIT, ROLLBACK | No (read-only TX context) |
4. Using Parameters
| Mode | Notes |
|---|---|
| IN | Input (default) |
| OUT | Return values via CALL |
| INOUT | Both |
CREATE PROCEDURE inc_count(INOUT cnt int) LANGUAGE plpgsql AS $
BEGIN cnt := cnt + 1; END $;
CALL inc_count(5); -- returns 6
5. Using Exceptions in Procedures
BEGIN
...
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
RAISE;
END;
Note: Inside an EXCEPTION block, you cannot issue COMMIT/ROLLBACK that spans the outer subtransaction; PL uses implicit savepoints.
6. Replacing Procedure
CREATE OR REPLACE PROCEDURE archive_old_orders(cutoff date) ...
7. Listing Procedures
\df+ schema.*
SELECT proname FROM pg_proc WHERE prokind = 'p'; -- procedures only
8. Dropping Procedure
DROP PROCEDURE IF EXISTS archive_old_orders(date);
9. Understanding Functions vs Procedures
| Aspect | Function | Procedure |
|---|---|---|
| Invocation | SELECT / inline | CALL |
| Returns | Value / set / void | OUT params |
| TX Control | No | Yes |
| Can be in SELECT | Yes | No |