mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
docs(database): style pass on the database functions guide (#50820)
Inline rewording only. Nothing moves and no claim changes. Addresses reader-facing "we", UI labels in quotes rather than bold, "allows you to", "e.g.", future tense, and title-case common nouns in body prose.
This commit is contained in:
1 parent
19188ece58
commit
e29f4e0736
1 file changed
+39
-41
@@ -6,7 +6,7 @@ video: 'https://www.youtube.com/v/MJZCCpCYEqk'
|
||||
---
|
||||
|
||||
Postgres has built-in support for [SQL functions](https://www.postgresql.org/docs/current/sql-createfunction.html).
|
||||
These functions live inside your database, and they can be [used with the API](../../reference/javascript/rpc).
|
||||
These functions live inside your database, and you can call them from your app with [`rpc()`](../../reference/javascript/rpc).
|
||||
|
||||
## Quick demo
|
||||
|
||||
@@ -14,14 +14,15 @@ These functions live inside your database, and they can be [used with the API](.
|
||||
|
||||
## Getting started
|
||||
|
||||
Supabase provides several options for creating database functions. You can use the Dashboard or create them directly using SQL.
|
||||
We provide a SQL editor within the Dashboard, or you can [connect](../../guides/database/connecting-to-postgres) to your database
|
||||
and run the SQL queries yourself.
|
||||
Create a database function from the Dashboard, or write the SQL yourself against a
|
||||
[direct connection](../../guides/database/connecting-to-postgres).
|
||||
|
||||
1. Go to the "SQL editor" section.
|
||||
2. Click "New Query".
|
||||
3. Enter the SQL to create or replace your Database function.
|
||||
4. Click "Run" or cmd+enter (ctrl+enter).
|
||||
To use the Dashboard:
|
||||
|
||||
1. Go to the **SQL Editor** section.
|
||||
2. Click **New Query**.
|
||||
3. Enter the SQL that creates or replaces your database function.
|
||||
4. Click **Run**. You can also press `cmd+enter` or `ctrl+enter`.
|
||||
|
||||
## Basic functions [#simple-functions]
|
||||
|
||||
@@ -40,26 +41,24 @@ $$; --6
|
||||
<details>
|
||||
<summary>Show/Hide Details</summary>
|
||||
|
||||
At it's most basic a function has the following parts:
|
||||
At its most basic, a function has the following parts:
|
||||
|
||||
1. `create or replace function hello_world()`: The function declaration, where `hello_world` is the name of the function. You can use either `create` when creating a new function or `replace` when replacing an existing function. Or you can use `create or replace` together to handle either.
|
||||
2. `returns text`: The type of data that the function returns. If it returns nothing, you can `returns void`.
|
||||
1. `create or replace function hello_world()`: The function declaration, where `hello_world` is the name of the function. Use `create` for a new function, `replace` for one that exists, or `create or replace` when the function might not exist yet.
|
||||
2. `returns text`: The type of data the function returns. For a function that returns nothing, write `returns void`.
|
||||
3. `language sql`: The language used inside the function body. This can also be a procedural language: `plpgsql`, `plpython`, etc.
|
||||
4. `as $$`: The function wrapper. Anything enclosed inside the `$$` symbols will be part of the function body.
|
||||
5. `select 'hello world';`: A basic function body. The final `select` statement inside a function body will be returned if there are no statements following it.
|
||||
4. `as $$`: The function wrapper. Anything inside the `$$` symbols is part of the function body.
|
||||
5. `select 'hello world';`: A basic function body. The function returns the result of the last `select` statement in its body.
|
||||
6. `$$;`: The closing symbols of the function wrapper.
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
When naming your functions, make the name of the function unique as overloaded functions are not supported.
|
||||
Overloaded functions aren't supported. Give every function a unique name.
|
||||
|
||||
</Admonition>
|
||||
|
||||
After the Function is created, we have several ways of "executing" the function - either directly inside the database using SQL, or with one of the client libraries.
|
||||
After you create the function, you can run it inside the database with SQL, or with one of the client libraries.
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
@@ -144,9 +143,9 @@ Reference: [`Rpc()`](../../reference/csharp/rpc)
|
||||
|
||||
## Returning data sets
|
||||
|
||||
Database Functions can also return data sets from [Tables](../../guides/database/tables) or Views.
|
||||
A database function can also return a data set from a [table](../../guides/database/tables) or a view.
|
||||
|
||||
For example, if we had a database with some Star Wars data inside:
|
||||
For example, take a database holding some Star Wars data:
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
@@ -212,7 +211,7 @@ values
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
We could create a function which returns all the planets:
|
||||
The following function returns all the planets:
|
||||
|
||||
```sql
|
||||
create or replace function get_planets()
|
||||
@@ -223,7 +222,7 @@ as $$
|
||||
$$;
|
||||
```
|
||||
|
||||
Because this function returns a table set, we can also apply filters and selectors. For example, if we only wanted the first planet:
|
||||
Because this function returns a table set, you can apply filters and selectors to it. To get the first planet only:
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
@@ -294,7 +293,7 @@ data = supabase.rpc('get_planets').eq('id', 1).execute()
|
||||
|
||||
## Passing parameters
|
||||
|
||||
Create a function to insert a new planet into the `planets` table and return the new ID. Note that this time we're using the `plpgsql` language.
|
||||
Create a function that inserts a new planet into the `planets` table and returns the new ID. This function uses the `plpgsql` language.
|
||||
|
||||
```sql
|
||||
create or replace function add_planet(name text)
|
||||
@@ -313,7 +312,7 @@ end;
|
||||
$$;
|
||||
```
|
||||
|
||||
Once again, you can execute this function either inside your database using a `select` query, or with the client libraries:
|
||||
You can run this function inside your database with a `select` query, or with the client libraries:
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
@@ -413,14 +412,13 @@ await supabase.Rpc("add_planet", new Dictionary<string, object> { { "name", "Jak
|
||||
|
||||
### Database Functions vs Edge Functions
|
||||
|
||||
For data-intensive operations, use Database Functions, which are executed within your database
|
||||
and can be called remotely using the [REST and GraphQL API](../api).
|
||||
For data-intensive operations, use database functions. They run inside your database, and you can call them remotely with the [REST and GraphQL API](../api).
|
||||
|
||||
For use-cases which require low-latency, use [Edge Functions](../../guides/functions), which are globally-distributed and can be written in Typescript.
|
||||
For use cases that need low latency, use [Edge Functions](../../guides/functions). They're globally distributed and you write them in TypeScript.
|
||||
|
||||
### Security `definer` vs `invoker`
|
||||
|
||||
Postgres allows you to specify whether you want the function to be executed as the user _calling_ the function (`invoker`), or as the _creator_ of the function (`definer`). For example:
|
||||
Postgres runs a function either as the user _calling_ it (`invoker`) or as its _creator_ (`definer`). For example:
|
||||
|
||||
```sql
|
||||
create function hello_world()
|
||||
@@ -434,31 +432,31 @@ end;
|
||||
$$;
|
||||
```
|
||||
|
||||
It is best practice to use `security invoker` (which is also the default). If you ever use `security definer`, you _must_ set the `search_path`.
|
||||
If you use an empty search path (`search_path = ''`), you must explicitly state the schema for every relation in the function body (e.g. `from public.table`).
|
||||
This limits the potential damage if you allow access to schemas which the user executing the function should not have.
|
||||
Prefer `security invoker`, which is also the default. When you use `security definer`, you must set the `search_path`.
|
||||
|
||||
With an empty search path, `search_path = ''`, name the schema for every relation in the function body, such as `from public.table`. An empty search path limits the damage when the function can reach a schema you don't want the calling user to reach.
|
||||
|
||||
### Function privileges
|
||||
|
||||
By default, database functions can be executed by any role. There are two main ways to restrict this:
|
||||
By default, any role can run a database function. You can restrict execution in two ways:
|
||||
|
||||
1. On a case-by-case basis. Specifically revoke permissions for functions you want to protect. Execution needs to be revoked for both `public` and the role you're restricting:
|
||||
1. Revoke on a case-by-case basis. Revoke execute for the functions you want to protect, from both `public` and the role you're restricting:
|
||||
|
||||
```sql
|
||||
revoke execute on function public.hello_world from public;
|
||||
revoke execute on function public.hello_world from anon;
|
||||
```
|
||||
|
||||
1. Restrict function execution by default. Specifically _grant_ access when you want a function to be executable by a specific role.
|
||||
1. Restrict execution by default, then grant access to the roles that need each function.
|
||||
|
||||
To restrict all existing functions, revoke execution permissions from both `public` _and_ the role you want to restrict:
|
||||
To restrict every function that exists, revoke execute from both `public` and the role you want to restrict:
|
||||
|
||||
```sql
|
||||
revoke execute on all functions in schema public from public;
|
||||
revoke execute on all functions in schema public from anon, authenticated;
|
||||
```
|
||||
|
||||
To restrict all new functions, change the default privileges for both `public` _and_ the role you want to restrict:
|
||||
To restrict every function created later, change the default privileges for both `public` and the role you want to restrict:
|
||||
|
||||
```sql
|
||||
alter default privileges in schema public revoke execute on functions from public;
|
||||
@@ -473,7 +471,7 @@ By default, database functions can be executed by any role. There are two main w
|
||||
|
||||
### Debugging functions
|
||||
|
||||
You can add logs to help you debug functions. This is especially recommended for complex functions.
|
||||
Add logs to help you debug a function. Logs matter most in a complex function.
|
||||
|
||||
Good targets to log include:
|
||||
|
||||
@@ -482,7 +480,7 @@ Good targets to log include:
|
||||
|
||||
#### General logging
|
||||
|
||||
To create custom logs in the [Dashboard's Postgres Logs](/dashboard/project/_/logs/postgres-logs), you can use the `raise` keyword. By default, there are 3 observed severity levels:
|
||||
Use the `raise` keyword to write custom logs to the [Postgres logs](/dashboard/project/_/logs/postgres-logs) in the Dashboard. Three severity levels appear by default:
|
||||
|
||||
- `log`
|
||||
- `warning`
|
||||
@@ -533,14 +531,14 @@ $$;
|
||||
select error_if_null(null);
|
||||
```
|
||||
|
||||
Value checking is common, so Postgres provides a shorthand: the `assert` keyword. It uses the following format:
|
||||
Value checking is common, so Postgres provides the `assert` keyword as a shorthand. It takes the following format:
|
||||
|
||||
```sql
|
||||
-- throw error when condition is false
|
||||
assert <some condition>, 'message';
|
||||
```
|
||||
|
||||
Below is an example
|
||||
For example:
|
||||
|
||||
```sql
|
||||
create function assert_example(name text)
|
||||
@@ -567,7 +565,7 @@ $$;
|
||||
select assert_example('Harry Potter');
|
||||
```
|
||||
|
||||
Error messages can also be captured and modified with the `exception` keyword:
|
||||
You can also capture and modify an error message with the `exception` keyword:
|
||||
|
||||
```sql
|
||||
create function error_example()
|
||||
@@ -587,7 +585,7 @@ $$;
|
||||
|
||||
#### Advanced logging
|
||||
|
||||
For more complex functions or complicated debugging, try logging:
|
||||
For a more complex function, or for harder debugging, log the following:
|
||||
|
||||
- Formatted variables
|
||||
- Individual rows
|
||||
|
||||
Reference in new issue
Block a user