Procedural Language (PL)
HeliosDB Nano includes a multi-dialect procedural language engine supporting PL/pgSQL, T-SQL, PL/SQL, and DB2 SQL PL syntax.
Overview
The procedural language module enables:
- Stored Procedures: Encapsulate complex business logic
- User-Defined Functions: Create reusable computations
- Control Flow: IF/ELSE, LOOP, WHILE, FOR statements
- Variables: Declare, assign, and manipulate local variables
- Exception Handling: EXCEPTION blocks for error handling
- Cursors: Iterate over query results
Supported Dialects
| Dialect | Description | Primary Use |
|---|
| PL/pgSQL | PostgreSQL procedural language | Default, PostgreSQL compatibility |
| T-SQL | Microsoft SQL Server | SQL Server migrations |
| PL/SQL | Oracle Database | Oracle migrations |
| DB2 SQL PL | IBM DB2 | DB2 migrations |
| Auto | Auto-detect dialect | Mixed environments |
Basic Syntax
Anonymous Blocks
SELECT COUNT(*) INTO v_count FROM users;
RAISE NOTICE 'Total users: %', v_count;
CREATE FUNCTION
CREATE OR REPLACE FUNCTION get_user_count()
SELECT COUNT(*) INTO v_count FROM users;
CREATE PROCEDURE
CREATE OR REPLACE PROCEDURE update_user_status(
UPDATE users SET status = p_status WHERE id = p_user_id;
Variables
Declaration
v_name VARCHAR(100); -- Simple variable
v_count INTEGER := 0; -- With default value
v_active CONSTANT BOOLEAN := TRUE; -- Constant
v_user users%ROWTYPE; -- Row type
v_id users.id%TYPE; -- Column type
Assignment
SELECT name INTO v_name FROM users WHERE id = 1;
SELECT name, email INTO v_name, v_email FROM users WHERE id = 1;
Control Flow
IF Statement
RAISE NOTICE 'High count';
RAISE NOTICE 'Medium count';
RAISE NOTICE 'Low count';
CASE Statement
LOOP
-- FOR loop (numeric range)
RAISE NOTICE 'Iteration: %', i;
-- FOR loop (query result)
FOR rec IN SELECT * FROM users LOOP
RAISE NOTICE 'User: %', rec.name;
Exception Handling
INSERT INTO users (id, name) VALUES (1, 'Alice');
WHEN unique_violation THEN
RAISE NOTICE 'User already exists';
RAISE NOTICE 'Unexpected error: %', SQLERRM;
Common Exception Types
| Exception | Description |
|---|
unique_violation | Duplicate key |
foreign_key_violation | FK constraint failed |
null_value_not_allowed | NULL in NOT NULL column |
check_violation | CHECK constraint failed |
division_by_zero | Division by zero |
OTHERS | Catch-all handler |
Cursors
user_cursor CURSOR FOR SELECT * FROM users;
user_record users%ROWTYPE;
FETCH user_cursor INTO user_record;
RAISE NOTICE 'User: %', user_record.name;
Dialect-Specific Examples
T-SQL Style
-- T-SQL uses @ for variables
SET @v_count = @v_count + 1;
PL/SQL Style
-- PL/SQL uses := for assignment
DBMS_OUTPUT.PUT_LINE(v_count);
Integration with Triggers
Procedural language functions are commonly used as trigger handlers:
-- Create trigger function
CREATE OR REPLACE FUNCTION audit_changes()
INSERT INTO audit_log (table_name, action, changed_at)
VALUES (TG_TABLE_NAME, TG_OP, NOW());
CREATE TRIGGER users_audit
AFTER INSERT OR UPDATE OR DELETE ON users
EXECUTE FUNCTION audit_changes();
Built-in Functions
Utility Functions
| Function | Description |
|---|
RAISE NOTICE | Output debug message |
RAISE EXCEPTION | Throw error |
FOUND | Boolean - last query returned rows |
ROW_COUNT | Rows affected by last statement |
NOW() | Current timestamp |
Trigger Context Variables
| Variable | Description |
|---|
TG_OP | Operation (INSERT, UPDATE, DELETE) |
TG_TABLE_NAME | Name of trigger table |
OLD | Row before modification |
NEW | Row after modification |
TG_WHEN | BEFORE or AFTER |
- PL functions are compiled and cached
- Avoid excessive dynamic SQL
- Use bulk operations where possible
- Consider using IMMUTABLE/STABLE/VOLATILE appropriately
See Also