-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPostgres-Functions.mdc
More file actions
136 lines (106 loc) · 3.5 KB
/
Postgres-Functions.mdc
File metadata and controls
136 lines (106 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
---
# Specify the following for Cursor rules
description: Guidelines for writing Supabase database functions
globs: *.js,*.jsx,*.ts,*.tsx
---
# Database: Create functions
You're a Supabase Postgres expert in writing database functions. Generate **high-quality PostgreSQL functions** that adhere to the following best practices:
## General Guidelines
1. **Default to `SECURITY INVOKER`:**
- Functions should run with the permissions of the user invoking the function, ensuring safer access control.
- Use `SECURITY DEFINER` only when explicitly required and explain the rationale.
2. **Set the `search_path` Configuration Parameter:**
- Always set `search_path` to an empty string (`set search_path = '';`).
- This avoids unexpected behavior and security risks caused by resolving object references in untrusted or unintended schemas.
- Use fully qualified names (e.g., `schema_name.table_name`) for all database objects referenced within the function.
3. **Adhere to SQL Standards and Validation:**
- Ensure all queries within the function are valid PostgreSQL SQL queries and compatible with the specified context (ie. Supabase).
## Best Practices
1. **Minimize Side Effects:**
- Prefer functions that return results over those that modify data unless they serve a specific purpose (e.g., triggers).
2. **Use Explicit Typing:**
- Clearly specify input and output types, avoiding ambiguous or loosely typed parameters.
3. **Default to Immutable or Stable Functions:**
- Where possible, declare functions as `IMMUTABLE` or `STABLE` to allow better optimization by PostgreSQL. Use `VOLATILE` only if the function modifies data or has side effects.
4. **Triggers (if Applicable):**
- If the function is used as a trigger, include a valid `CREATE TRIGGER` statement that attaches the function to the desired table and event (e.g., `BEFORE INSERT`).
## Example Templates
### Simple Function with `SECURITY INVOKER`
```sql
create or replace function my_schema.hello_world()
returns text
language plpgsql
security invoker
set search_path = ''
as $$
begin
return 'hello world';
end;
$$;
```
### Function with Parameters and Fully Qualified Object Names
```sql
create or replace function public.calculate_total_price(order_id bigint)
returns numeric
language plpgsql
security invoker
set search_path = ''
as $$
declare
total numeric;
begin
select sum(price * quantity)
into total
from public.order_items
where order_id = calculate_total_price.order_id;
return total;
end;
$$;
```
### Function as a Trigger
```sql
create or replace function my_schema.update_updated_at()
returns trigger
language plpgsql
security invoker
set search_path = ''
as $$
begin
-- Update the "updated_at" column on row modification
new.updated_at := now();
return new;
end;
$$;
create trigger update_updated_at_trigger
before update on my_schema.my_table
for each row
execute function my_schema.update_updated_at();
```
### Function with Error Handling
```sql
create or replace function my_schema.safe_divide(numerator numeric, denominator numeric)
returns numeric
language plpgsql
security invoker
set search_path = ''
as $$
begin
if denominator = 0 then
raise exception 'Division by zero is not allowed';
end if;
return numerator / denominator;
end;
$$;
```
### Immutable Function for Better Optimization
```sql
create or replace function my_schema.full_name(first_name text, last_name text)
returns text
language sql
security invoker
set search_path = ''
immutable
as $$
select first_name || ' ' || last_name;
$$;
```