plpgsql
PL/pgSQL procedural language
Overview
| Package | Version | Category | License | Language |
|---|---|---|---|---|
plpgsql | 1.0 | LANG | PostgreSQL | C |
| ID | Extension | Bin | Lib | Load | Create | Trust | Reloc | Schema |
|---|---|---|---|---|---|---|---|---|
| 3280 | plpgsql | No | Yes | No | Yes | Yes | No | pg_catalog |
| Related | plx plisql plpgsql_check pldbgapi plpgsql_wrap orafce plprofiler plsh pljava pglinter |
|---|---|
| Depended By | bedquilt biscuit cat_tools check_orapg currency data_historization db2fce dbpatch dbstat ddl_historization drop_role_helper dsef event_manager explanation firefly geekspeak generic_plan gogudb grants_manager hello-world hybrid_search index_analyzer istoria italian_codes job_queue json_query json_utils jsonb_schema jx_io keyhippo kilobase kissfft lab-orders launchql-base32 launchql-ext-types launchql-extension-utils launchql-extension-verify launchql-inflection launchql-jwt-claims launchql-stamps launchql-totp livewire medications merge_ips meta_triggers migration monitoring_role mv_rewrite mv_stats myhelper mypg_sharding mysqlcompat newsfeeds nfiesta_gisdata nfiesta_sdesign nfiesta_target_data nonoms norm npm ollama omnidb_plpgsql_debugger partman_to_cstore pase pathman_sharding patients pg-audit-json pg2podg pg4ml pgAutomator pg_abris pg_accumulator pg_audit pg_audit_tools pg_biscuit pg_bleve pg_bm25 pg_cache_tree pg_calcpi pg_catalog_get_defs pg_column_tetris pg_credereum pg_datatype_password pg_dbo_timestamp pg_dbwa pg_dms pg_drop_events pg_dropbuffers pg_dropcache pg_eyes pg_fairmlq pg_fsql pg_gen_uid pg_git pg_graphql_server pg_gsl pg_idm pg_idx_advisor pg_lake_iceberg pg_landmetrics pg_ledger pg_linegazer pg_llm_helper pg_lock_pool pg_message_queue pg_monitoring pg_normalize_email pg_once pg_os pg_osgr pg_pageprep pg_part pg_particulous pg_partman pg_pathman pg_paxos pg_popyramids_datamarts pg_profile pg_prometheus pg_prttn_tools pg_reversi pg_sakila_db pg_semantic_cache pg_sendmail pg_sentence_transformer pg_sessions pg_shardman pg_statviz pg_tileless pg_tms pg_turboquant pg_twkb pg_upless pg_zlog pgaut pgcat pgeyes pgfsm pgh_consistency pgh_hgm pgh_output pgh_output_en_au pgh_output_pt_br pgh_raster pghydro pgmemento pgmock pgnats pgparts pgpm-base32 pgpm-defaults pgpm-faker pgpm-inflection pgpm-jwt-claims pgpm-measurements pgpm-types pgpm-verify pgrao pgrollup pgrouting pgsqlmock pgtap pgtap_fixture pgtelemetry pgvroom plparrot plpgsql_check plpgsql_wrap plrust postgres_ci postpic powa prescriptions qgres quria range_partitioning recall recursively_delete rep_fdw rls_helpers roleman rpg rtiles scheduling session_variables short_ids skitch-extension-defaults skitch-extension-jobs skitch-extension-utils skitch-extension-verify sphinxlink sql_saga supa_queue supabase supabase_auth_apikey sys_syn_dblink tab_tier table_log_pl table_version tablelog telephone test_factory time_for_keys timestampandtz town types unit units us-states uuidv7-sql variant vectors vrprouting wasm webauthn xl_global_views zombodb |
Version
| PG18 | PG17 | PG16 | PG15 | PG14 |
|---|---|---|---|---|
| 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
Install
Note: This is a built-in contrib extension of PostgreSQL
CREATE EXTENSION plpgsql;
Usage
PL/pgSQL is PostgreSQL’s default procedural language. It extends SQL with control structures, variables, cursors, and exception handling.
CREATE EXTENSION plpgsql; -- installed by default
-- Basic function with variables and control flow
CREATE FUNCTION calculate_discount(price numeric, quantity integer) RETURNS numeric
LANGUAGE plpgsql AS $$
DECLARE
discount numeric := 0;
BEGIN
IF quantity >= 100 THEN
discount := 0.20;
ELSIF quantity >= 50 THEN
discount := 0.10;
ELSIF quantity >= 10 THEN
discount := 0.05;
END IF;
RETURN price * quantity * (1 - discount);
END;
$$;
-- Loop and set-returning function
CREATE FUNCTION fibonacci(n integer) RETURNS SETOF integer
LANGUAGE plpgsql AS $$
DECLARE
a integer := 0;
b integer := 1;
tmp integer;
BEGIN
FOR i IN 1..n LOOP
RETURN NEXT a;
tmp := a + b;
a := b;
b := tmp;
END LOOP;
END;
$$;
SELECT * FROM fibonacci(10);
-- Exception handling
CREATE FUNCTION safe_divide(a numeric, b numeric) RETURNS numeric
LANGUAGE plpgsql AS $$
BEGIN
RETURN a / b;
EXCEPTION
WHEN division_by_zero THEN
RAISE NOTICE 'Division by zero, returning NULL';
RETURN NULL;
END;
$$;
-- Trigger function
CREATE FUNCTION update_modified_column() RETURNS trigger
LANGUAGE plpgsql AS $$
BEGIN
NEW.modified_at = now();
RETURN NEW;
END;
$$;
CREATE TRIGGER set_modified
BEFORE UPDATE ON my_table
FOR EACH ROW EXECUTE FUNCTION update_modified_column();
-- Procedure with transaction control (PG 11+)
CREATE PROCEDURE batch_archive(batch_size integer)
LANGUAGE plpgsql AS $$
DECLARE
rows_moved integer;
BEGIN
LOOP
WITH moved AS (
DELETE FROM orders WHERE status = 'completed'
RETURNING *
)
INSERT INTO orders_archive SELECT * FROM moved;
GET DIAGNOSTICS rows_moved = ROW_COUNT;
COMMIT;
EXIT WHEN rows_moved < batch_size;
END LOOP;
END;
$$;
Feedback
Was this page helpful?
Thanks for the feedback! Please let us know how we can improve.
Sorry to hear that. Please let us know how we can improve.