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 ProcedureAllowed In Function
COMMIT, ROLLBACKNo (read-only TX context)

4. Using Parameters

ModeNotes
INInput (default)
OUTReturn values via CALL
INOUTBoth
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

AspectFunctionProcedure
InvocationSELECT / inlineCALL
ReturnsValue / set / voidOUT params
TX ControlNoYes
Can be in SELECTYesNo