>
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
index 08cea106b45..7385afd2d3d 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
@@ -399,16 +399,41 @@ export const database = {
items: [],
},
{ name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] },
+ {
+ name: 'PGAudit: Postgres Auditing',
+ url: '/guides/database/extensions/pgaudit',
+ items: [],
+ },
+ {
+ name: 'pgjwt: JSON Web Tokens',
+ url: '/guides/database/extensions/pgjwt',
+ items: [],
+ },
{
name: 'PGroonga: Multilingual Full Text Search',
url: '/guides/database/extensions/pgroonga',
items: [],
},
+ {
+ name: 'pgRouting: Geospatial Routing',
+ url: '/guides/database/extensions/pgrouting',
+ items: [],
+ },
{
name: 'pg_cron: Job Scheduling',
url: '/guides/database/extensions/pgcron',
items: [],
},
+ {
+ name: 'pg_graphql: GraphQL Support',
+ url: '/guides/database/extensions/pg_graphql',
+ items: [],
+ },
+ {
+ name: 'pg_hashids: Short UIDs',
+ url: '/guides/database/extensions/pg_hashids',
+ items: [],
+ },
{
name: 'pg_jsonschema: JSON Schema Validation',
url: '/guides/database/extensions/pg_jsonschema',
@@ -419,6 +444,16 @@ export const database = {
url: '/guides/database/extensions/pgnet',
items: [],
},
+ {
+ name: 'pg_plan_filter: Restrict Total Cost',
+ url: '/guides/database/extensions/pg_plan_filter',
+ items: [],
+ },
+ {
+ name: 'pg_stat_monitor: Extended Query Performance Monitoring',
+ url: '/guides/database/extensions/pg_stat_monitor',
+ items: [],
+ },
{
name: 'pgvector: Embeddings and vector similarity',
url: '/guides/database/extensions/pgvector',
@@ -439,7 +474,27 @@ export const database = {
url: '/guides/database/extensions/postgis',
items: [],
},
+ {
+ name: 'pg-safeupdate: Required Where Clauses',
+ url: '/guides/database/extensions/pg-safeupdate',
+ items: [],
+ },
+ {
+ name: 'pgsodium: Encryption Features',
+ url: '/guides/database/extensions/pgsodium',
+ items: [],
+ },
{ name: 'pgTAP: Unit Testing', url: '/guides/database/extensions/pgtap', items: [] },
+ {
+ name: 'plpgsql_check: PL/pgSQL Linter',
+ url: '/guides/database/extensions/plpgsql_check',
+ items: [],
+ },
+ {
+ name: 'timescaledb: Time-series data',
+ url: '/guides/database/extensions/timescaledb',
+ items: [],
+ },
{
name: 'uuid-ossp: Unique Identifiers',
url: '/guides/database/extensions/uuid-ossp',
@@ -450,6 +505,11 @@ export const database = {
url: '/guides/database/extensions/rum',
items: [],
},
+ {
+ name: 'wrappers: 3rd Party Integrations',
+ url: '/guides/database/extensions/wrappers',
+ items: [],
+ },
],
},
{
diff --git a/apps/docs/data/authProviders.ts b/apps/docs/data/authProviders.ts
index 44958476ba6..ea5855061bd 100644
--- a/apps/docs/data/authProviders.ts
+++ b/apps/docs/data/authProviders.ts
@@ -107,7 +107,7 @@ const authProviders = [
supporter: 'MessageBird',
platform: true,
selfHosted: true,
- authType: 'phone'
+ authType: 'phone',
},
{
name: 'Notion',
diff --git a/apps/docs/pages/guides/database/extensions/http.mdx b/apps/docs/pages/guides/database/extensions/http.mdx
index 11ac8e55d41..7f686ed8e7b 100644
--- a/apps/docs/pages/guides/database/extensions/http.mdx
+++ b/apps/docs/pages/guides/database/extensions/http.mdx
@@ -63,7 +63,7 @@ drop extension if exists http;
Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
To disable an extension, call `drop extension`.
-It's good practice to create the extension within a separate schema (like `extensions`) to keep your database clean.
+It's good practice to create the extension within a separate schema (like `extensions`) to keep the `public` schema clean.
diff --git a/apps/docs/pages/guides/database/extensions/hypopg.mdx b/apps/docs/pages/guides/database/extensions/hypopg.mdx
index c493f9f89cd..18688e276e4 100644
--- a/apps/docs/pages/guides/database/extensions/hypopg.mdx
+++ b/apps/docs/pages/guides/database/extensions/hypopg.mdx
@@ -7,11 +7,10 @@ export const meta = {
}
`HypoPG` is PostgreSQL extension for creating hypothetical/virtual indexes. HypoPG allows users to rapidly create hypothetical/virtual indexes that have no resource cost (CPU, disk, memory) that are visible to the PostgreSQL query planner.
-That allows users to quickly search for an index to improve a slow query without waiting for them to build.
-## Usage
+The motivation for HypoPG is to allow users to quickly search for an index to improve a slow query without consuming server resources or waiting for them to build.
-### Enable the extension
+## Enable the extension
### Speeding up a query
-Given the following table and a simple query to select from the table by id:
+Given the following table and a simple query to select from the table by `id`:
{/* prettier-ignore */}
```sql
diff --git a/apps/docs/pages/guides/database/extensions/pg-safeupdate.mdx b/apps/docs/pages/guides/database/extensions/pg-safeupdate.mdx
new file mode 100644
index 00000000000..33773977b55
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pg-safeupdate.mdx
@@ -0,0 +1,60 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pg-safeupdate',
+ title: 'pg-safeupdate: Required Where Clauses',
+ description: 'Requires a where clause for update and delete',
+}
+
+[pg-safeupdate](https://github.com/eradman/pg-safeupdate) is a PostgreSQL extension designed to prevent users from accidentally updating or deleting too many records in a single statement by requiring a "where" clause in all update and delete statements.
+
+The `pg-safeupdate` extension is a useful tool for protecting data integrity and preventing accidental data loss. Without it, a user could accidentally execute an update or delete statement that affects all records in a table. With `pg-safeupdate`, users are required to be more deliberate in their update and delete statements, which reduces the risk of significant error.
+
+## Enable the extension
+
+`pg-safeupdate` can be enabled on a per connection basis:
+
+{/* prettier-ignore */}
+```sql
+load 'safeupdate';
+```
+
+or for all connections:
+
+{/* prettier-ignore */}
+```sql
+alter database some_db set session_preload_libraries = 'safeupdate';
+```
+
+## Usage
+
+Let's take a look at an example to see how pg-safeupdate works. Suppose we have a table called `employees` with the following columns: `id`, `name`, `department`, and `date_of_birth`. We want to update the `date_of_birth` for a specific employee with the `id` of 12345. Here is what the query would look like if we forgot to add a "where" clause:
+
+{/* prettier-ignore */}
+```sql
+load 'safeupdate';
+
+update employees set date_of_birth = '1987-01-28';
+```
+
+This query updates the `date_of_birth` for all employees to 1987-01-28, which is not what we intended. With `pg-safeupdate` enabled, we receive an error message prompting us to add a "where" clause to the query:
+
+{/* prettier-ignore */}
+```sql
+ERROR: UPDATE requires a WHERE clause
+```
+
+We would then update our query to include a "where" clause specifying the employee with the `id` of 12345:
+
+{/* prettier-ignore */}
+```sql
+update employees set date_of_birth = '1987-01-28' where id = 12345;
+```
+
+## Resources
+
+- Official [pg-safeupdate documentation](https://github.com/eradman/pg-safeupdate)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pg_graphql.mdx b/apps/docs/pages/guides/database/extensions/pg_graphql.mdx
new file mode 100644
index 00000000000..a63be68c164
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pg_graphql.mdx
@@ -0,0 +1,116 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pg_graphql',
+ title: 'pg_graphql: GraphQL for PostgreSQL',
+ description: 'A GraphQL Interface for PostgreSQL',
+}
+
+[pg_graphql](https://supabase.github.io/pg_graphql/) is PostgreSQL extension for interacting with the database using [GraphQL](https://graphql.org) instead of SQL.
+
+The extension reflects a GraphQL schema from the existing SQL schema and exposes it through a SQL function, `graphql.resolve(...)`. This enables any programming language that can connect to PostgreSQL to query the database via GraphQL with no additional servers, processes, or libraries.
+
+The `pg_graphql` resolve method is designed to interop with [PostgREST](https://postgrest.org/en/stable/index.html), the tool that underpins the Supabase API, such that the `graphql.resolve` function can be called via RPC to safely and performantly expose the GraphQL API over HTTP/S.
+
+For more information about how the SQL schema is reflected into a GraphQL schema, see the [pg_graphql API docs](https://supabase.github.io/pg_graphql/api/).
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pg_graphql" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pg_graphql" extension
+create extension pg_graphql;
+
+-- Disable the "pg_graphql" extension
+drop extension if exists pg_graphql;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+
+
+
+## Usage
+
+Given a table
+
+{/* prettier-ignore */}
+```sql
+create table "Blog"(
+ id serial primary key,
+ name varchar(255) not null,
+ description varchar(255),
+);
+
+insert into "Blog"(name)
+values ('My Blog');
+```
+
+The reflected GraphQL schema can be queries immediately as
+
+{/* prettier-ignore */}
+```sql
+select
+ graphql.resolve($$
+ {
+ blogCollection(first: 1) {
+ edges {
+ node {
+ id,
+ name
+ }
+ }
+ }
+ }
+ $$);
+```
+
+returning the JSON
+
+{/* prettier-ignore */}
+```json
+{
+ "data": {
+ "blogCollection": {
+ "edges": [
+ {
+ "node": {
+ "id": 1
+ "name": "My Blog"
+ }
+ }
+ ]
+ }
+ }
+}
+```
+
+Note that `pg_graphql` fully supports schema introspection so you can connect any GraphQL IDE or schema inspection tool to see the full set of fields and arguments available in the API.
+
+## API
+
+- [`graphql.resolve`](https://supabase.github.io/pg_graphql/sql_interface/): A SQL function for executing GraphQL queries.
+
+## Resources
+
+- Official [`pg_graphql` documentation](https://github.com/supabase/pg_graphql)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pg_hashids.mdx b/apps/docs/pages/guides/database/extensions/pg_hashids.mdx
new file mode 100644
index 00000000000..ad02c19b1ff
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pg_hashids.mdx
@@ -0,0 +1,81 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pg_hashids',
+ title: 'pg_hashids: Short UIDs',
+ description: 'Generate Short UIDs from Numbers',
+}
+
+[pg_hashids](https://github.com/iCyberon/pg_hashids) provides a secure way to generate short, unique, non-sequential ids from numbers. The hashes are intended to be small, easy-to-remember identifiers that can be used to obfuscate data (optionally) with a password, alphabet, and salt. For example, you may wish to hide data like user IDs, order numbers, or tracking codes in favor of `pg_hashid`'s unique identifers.
+
+## Enable the Extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pg_hashids" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pg_hashids" extension
+create extension pg_hashids with schema extensions;
+
+-- Disable the "pg_hashids" extension
+drop extension if exists pg_hashids;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+It's good practice to create the extension within a separate schema (like `extensions`) to keep your `public` schema clean.
+
+
+
+
+## Usage
+
+Suppose we have a table that stores order information, and we want to give customers a unique identifer without exposing the sequential `id` column. To do this, we can use `pg_hashid`'s `id_encode` function.
+
+```sql
+create table orders (
+ id serial primary key,
+ description text,
+ price_cents bigint
+);
+
+insert into orders (description, price_cents)
+values ('a book', 9095);
+
+select
+ id,
+ id_encode(id) as short_id,
+ description,
+ price_cents
+from
+ orders;
+
+ id | short_id | description | price_cents
+----+----------+-------------+-------------
+ 1 | jR | a book | 9095
+(1 row)
+```
+
+To reverse the `short_id` back into an `id`, there is an equivalent function named `id_decode`.
+
+## Resources
+
+- Official [pg_hashids documention](https://github.com/iCyberon/pg_hashids)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pg_jsonschema.mdx b/apps/docs/pages/guides/database/extensions/pg_jsonschema.mdx
index c51a4c3783e..4cf54f21a19 100644
--- a/apps/docs/pages/guides/database/extensions/pg_jsonschema.mdx
+++ b/apps/docs/pages/guides/database/extensions/pg_jsonschema.mdx
@@ -6,11 +6,9 @@ export const meta = {
description: 'Validate json/jsonb with JSON Schema in PostgreSQL.',
}
-[JSON Schema](https://json-schema.org) is a language for annotating and validating JSON documents. [`pg_jsonschema`](https://json-schema.org) is a PostgreSQL extension that adds the ability to validate PostgreSQL's built-in `json` and `jsonb` data types against a JSON Schema document.
+[JSON Schema](https://json-schema.org) is a language for annotating and validating JSON documents. [`pg_jsonschema`](https://github.com/supabase/pg_jsonschema) is a PostgreSQL extension that adds the ability to validate PostgreSQL's built-in `json` and `jsonb` data types against JSON Schema documents.
-## Usage
-
-### Enable the extension
+## Enable the extension
@@ -49,9 +47,9 @@ It's good practice to create the extension within a separate schema (like `exten
- [`json_matches_schema(schema json, instance json)`](https://github.com/supabase/pg_jsonschema#api): Checks if a `json` _instance_ conforms to a JSON Schema _schema_.
- [`jsonb_matches_schema(schema json, instance jsonb)`](https://github.com/supabase/pg_jsonschema#api): Checks if a `jsonb` _instance_ conforms to a JSON Schema _schema_.
-### Validating a document
+## Usage
-Since `pg_jsonschema` exposes its utilities as functions, we can test it with a simple select statement:
+Since `pg_jsonschema` exposes its utilities as functions, we can execute them with a select statement:
{/* prettier-ignore */}
```sql
@@ -62,7 +60,7 @@ select
);
```
-`pg_jsonschema` is generally used in tandem with a [check constraint](https://www.postgresql.org/docs/current/ddl-constraints.html) as a way to constrain the contents of a json/b field to match a JSON Schema.
+`pg_jsonschema` is generally used in tandem with a [check constraint](https://www.postgresql.org/docs/current/ddl-constraints.html) as a way to constrain the contents of a json/b column to match a JSON Schema.
{/* prettier-ignore */}
```sql
diff --git a/apps/docs/pages/guides/database/extensions/pg_plan_filter.mdx b/apps/docs/pages/guides/database/extensions/pg_plan_filter.mdx
new file mode 100644
index 00000000000..ab46d931ffe
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pg_plan_filter.mdx
@@ -0,0 +1,97 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pg_plan_filter',
+ title: 'pg_plan_filter: Restrict Total Cost',
+ description: 'Block queries over a total cost limit',
+}
+
+[pg_plan_filter](https://github.com/pgexperts/pg_plan_filter) is PostgreSQL extension to block execution of statements where query planner's estimate of the total cost exceeds a threshold. This is intended to give database administrators a way to restrict the contribution an individual query has on database load.
+
+## Enable the extension
+
+`pg_plan_filter` can be enabled on a per connection basis:
+
+{/* prettier-ignore */}
+```sql
+load 'plan_filter';
+```
+
+or for all connections:
+
+{/* prettier-ignore */}
+```sql
+alter database some_db set session_preload_libraries = 'plan_filter';
+```
+
+## API
+
+`plan_filter.statement_cost_limit`: restricts the maximum total cost for executed statements
+`plan_filter.limit_select_only`: restricts to `select` statements
+
+Note that `limit_select_only = true` is not the same as read-only because `select` statements may modfiy data e.g. through a function call.
+
+## Example
+
+To demonstrate total cost filtering, we'll compare how `plan_filter.statement_cost_limit` treats queries that are under and over its cost limit. First, we set up a table with some data:
+
+{/* prettier-ignore */}
+```sql
+create table book(
+ id int primary key
+);
+-- CREATE TABLE
+
+insert into book(id) select * from generate_series(1, 10000);
+-- INSERT 0 10000
+```
+
+Next, we can review the explain plans for a single record select, and a whole table select.
+
+{/* prettier-ignore */}
+```sql
+explain select * from book where id =1;
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Index Only Scan using book_pkey on book (cost=0.28..2.49 rows=1 width=4)
+ Index Cond: (id = 1)
+(2 rows)
+
+explain select * from book;
+ QUERY PLAN
+---------------------------------------------------------
+ Seq Scan on book (cost=0.00..135.00 rows=10000 width=4)
+(1 row)
+```
+
+Now we can choose a `statement_cost_filter` value between the total cost for the single select (2.49) and the whole table select (135.0) so one statement will succeed and one will fail.
+
+{/* prettier-ignore */}
+```sql
+load 'plan_filter';
+set plan_filter.statement_cost_limit = 50; -- between 2.49 and 135.0
+
+select * from book where id = 1;
+ id
+----
+ 1
+(1 row)
+-- SUCCESS
+```
+
+{/* prettier-ignore */}
+```sql
+select * from book;
+
+ERROR: plan cost limit exceeded
+HINT: The plan for your query shows that it would probably have an excessive run time. This may be due to a logic error in the SQL, or it maybe just a very costly query. Rewrite your query or increase the configuration parameter "plan_filter.statement_cost_limit".
+-- FAILURE
+```
+
+## Resources
+
+- Official [pg_plan_filter documentation](https://github.com/pgexperts/pg_plan_filter)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pg_stat_monitor.mdx b/apps/docs/pages/guides/database/extensions/pg_stat_monitor.mdx
new file mode 100644
index 00000000000..4c1363b83b9
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pg_stat_monitor.mdx
@@ -0,0 +1,88 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pg_stat_monitor',
+ title: 'pg_stat_monitor: Query Performance Monitoring',
+ description: 'Query performance monitoring for PostgreSQL',
+}
+
+[pg_stat_monitor](https://github.com/percona/pg_stat_monitor) is query performance monitoring tool that provides query execution statistics in a SQL view named `pg_stat_monitor`. It tracks a superset of statistics available in [`pg_stat_statements`](https://www.postgresql.org/docs/current/pgstatstatements.html). Some of the most useful features are:
+
+- **Time Interval Grouping**: configurable time buckets to track query usage over time
+- **Capture Parameters**: optionally track parameters passed into queries instead of generic placeholders e.g. `$1`
+- **Query Plan**: store query plans used for execution
+
+For more information on query optimization, check out the [query performance guide](/docs/guides/platform/performance#examining-query-performance).
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pg_stat_monitor" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pg_stat_monitor" extension
+create extension pg_stat_monitor with schema extensions;
+
+-- Disable the "pg_stat_monitor" extension
+drop extension if exists pg_stat_monitor;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+It's good practice to create the extension within a separate schema (like `extensions`) to keep the `public` schema clean.
+
+
+
+
+## Views
+
+{/* prettier-ignore */}
+```sql
+select * from extensions.pg_stat_monitor;
+```
+
+The following table shows a subset of available columns:
+
+| Column Type | Description |
+| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
+| bucket bigint | Data collection unit. The number shows what bucket in a chain a record belongs to |
+| bucket_start_time timestampz | The start time of the bucket |
+| userid oid (references pg_authid.oid) | OID of user who executed the statement |
+| dbid oid (references pg_database.oid) | OID of database in which the statement was executed |
+| toplevel bool | True if the query was executed as a top-level statement (always true if pg_stat_statements.track is set to top) |
+| client_ip inet | The IP address of a client that ran the query |
+| queryid bigint | Hash code to identify identical normalized queries. |
+| planid text | An internally generated ID of a query plan |
+| query_plan text | The sequence of steps used to execute a query. This parameter is only available when pgsm_enable_query_plan is enabled |
+| query text | Text of a representative statement |
+| plans bigint | Number of times the statement was planned (if pg_stat_statements.track_planning is enabled, otherwise zero) |
+| total_plan_time double precision | Total time spent planning the statement, in milliseconds (if pg_stat_statements.track_planning is enabled, otherwise zero) |
+| min_plan_time double precision | Minimum time spent planning the statement, in milliseconds (if pg_stat_statements.track_planning is enabled, otherwise zero) |
+
+A full list of statistics is available in the [pg_stat_monitor docs](https://docs.percona.com/pg-stat-monitor/reference.html#postgresql-15).
+
+## Functions
+- [`pg_stat_monitor_reset()`](https://docs.percona.com/pg-stat-monitor/functions.html): Resets the statistics tracked by the `pg_stat_monitor` view and deletes all previous data.
+- [`pg_stat_monitor_version()`](https://docs.percona.com/pg-stat-monitor/functions.html): Displays the version of the `pg_stat_monitor` extension.
+
+## Resources
+
+- Official [`pg_stat_monitor` documentation](https://github.com/percona/pg_stat_monitor)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pg_stat_statements.mdx b/apps/docs/pages/guides/database/extensions/pg_stat_statements.mdx
index 711878d78c0..cb64a901b0c 100644
--- a/apps/docs/pages/guides/database/extensions/pg_stat_statements.mdx
+++ b/apps/docs/pages/guides/database/extensions/pg_stat_statements.mdx
@@ -2,7 +2,7 @@ import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'pg_stat_statements',
- title: 'pg_stat_statements: SQL Planning and Execution Statistics',
+ title: 'pg_stat_statements: Query Performance Monitoring',
description:
'Track planning and execution statistics of all SQL statements executed on the database.',
}
@@ -22,9 +22,9 @@ export const meta = {
A full list of statistics is available in the [pg_stat_statements docs](https://www.postgresql.org/docs/current/pgstatstatements.html).
-## Usage
+For more information on query optimization, check out the [query performance guide](/docs/guides/platform/performance#examining-query-performance).
-### Enable the extension
+## Enable the extension
-### Inspecting activity
+## Inspecting activity
A common use for `pg_stat_statements` is to track down expensive or slow queries. The `pg_stat_statements` view contains a row for each executed query with statistics inlined. For example, you can leverage the statistics to identify frequently executed and slow queries against a given table.
@@ -74,15 +74,15 @@ select
from
pg_stat_statements
where
- calls > 1000 -- at least 50 calls
- and mean_exec_time > 2.0 -- averaging at least 2ms/call
- and total_exec_time > 60000 -- at least one minute total server time spent
- and query ilike '%user_in_organization%' -- filter to queries that touch the user_in_organization table
+ calls > 50 -- at least 50 calls
+ and mean_exec_time > 2.0 -- averaging at least 2ms/call
+ and total_exec_time > 60000 -- at least one minute total server time spent
+ and query ilike '%user_in_organization%' -- filter to queries that touch the user_in_organization table
order by
calls desc
```
-From the results, an informed decision about which queries to optimize, index, or adjust can be made.
+From the results, we can make an informed decision about which queries to optimize or index.
## Resources
diff --git a/apps/docs/pages/guides/database/extensions/pgaudit.mdx b/apps/docs/pages/guides/database/extensions/pgaudit.mdx
new file mode 100644
index 00000000000..0352fb6d131
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pgaudit.mdx
@@ -0,0 +1,105 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pgaudit',
+ title: 'PGAudit: Postgres Auditing',
+ description: 'Session and object auditing via PostgreSQL standard logging',
+}
+
+[PGAudit](https://www.pgaudit.org) is a PostgreSQL extension for logging session and object auditing over the standard PostgreSQL logging utility.
+
+PGAudit grants fine grain control over which statements and objects are emitted to logs.
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pgaudit" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pgaudit" extension
+create extension pgaudit;
+
+-- Disable the "pgaudit" extension
+drop extension if exists pgaudit;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+
+
+
+## Settings
+
+The `pgaudit.log` setting controls which statements to log. Available values include:
+
+- **read**: `SELECT` and `COPY` when the source is a relation or a query.
+- **write**: `INSERT`, `UPDATE`, `DELETE`, `TRUNCATE`, and `COPY` when the destination is a relation.
+- **function**: Function calls and `DO` blocks.
+- **role**: Statements related to roles and privileges: `GRANT`, `REVOKE`, `CREATE/ALTER/DROP ROLE`.
+- **ddl**: All `DDL` that is not included in the `ROLE` class.
+- **misc**: Miscellaneous commands, e.g. `DISCARD`, `FETCH`, `CHECKPOINT`, `VACUUM`, `SET`.
+- **misc_set**: Miscellaneous `SET` commands, e.g. `SET ROLE`.
+
+- **all**: Include all of the above.
+
+For a full list of available settings see [settings docs](https://github.com/pgaudit/pgaudit/blob/master/README.md#settings). Be aware that the `all` setting will generate a very large volume of logs.
+
+## Example
+
+Given a pgaudit setting
+
+{/* prettier-ignore */}
+```sql
+set pgaudit.log = 'read, ddl';
+```
+
+The following create table, insert and select statements
+
+{/* prettier-ignore */}
+```sql
+create table account (
+ id int primary key,
+ name text,
+ description text
+);
+
+insert into account (id, name, description)
+values (1, 'Foo Barsworth', 'Customer account');
+
+select * from account;
+```
+
+Results in the log output
+
+```text
+AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.account,create table account(
+ id int,
+ name text,
+ description text
+);,
+AUDIT: SESSION,2,1,READ,SELECT,,,select * from account,,
+```
+
+Note that the insert statement is not logged because we did not include the `write` option for `pgaudit.log`.
+
+## Resources
+
+- Official [`PGAudit` documentation](https://www.pgaudit.org)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pgjwt.mdx b/apps/docs/pages/guides/database/extensions/pgjwt.mdx
new file mode 100644
index 00000000000..77c8bcc8dea
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pgjwt.mdx
@@ -0,0 +1,113 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pgjwt',
+ title: 'pgjwt: JSON Web Tokens',
+ description: 'Encode and decode JWTs in PostgreSQL',
+}
+
+The [pgjwt](https://github.com/michelp/pgjwt) (PostgreSQL JSON Web Token) extension allows you to create and parse [JSON Web Tokens (JWTs)](https://en.wikipedia.org/wiki/JSON_Web_Token) within a PostgreSQL database. JWTs are commonly used for authentication and authorization in web applications and services.
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pgjwt" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pgjwt" extension
+create extension pgjwt schema extensions;
+
+-- Disable the "pgjwt" extension
+drop extension if exists pgjwt;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+It's good practice to create the extension within a separate schema (like `extensions`) to keep the `public` schema clean.
+
+
+
+
+## API
+
+- [`sign(payload json, secret text, algorithm text default 'HSA256')`](https://github.com/michelp/pgjwt#usage): Signs a JWT containng _payload_ with _secret_ using _algorithm_.
+- [`verify(token text, secret text, algorithm text default 'HSA256')`](https://github.com/michelp/pgjwt#usage): Decodes a JWT _token_ that was signed with _secret_ using _algorithm_.
+
+Where:
+
+- `payload` is an encrypted JWT represented as a string.
+- `secret` is the private/secret passcode which is used to sign the JWT and verify its integrity.
+- `algorithm` is the method used to sign the JWT using the secret.
+- `token` is an encrypted JWT represented as a string.
+
+## Usage
+
+Once the extension is installed, you can use its functions to create and parse JWTs. Here's an example of how you can use the `sign` function to create a JWT:
+
+{/* prettier-ignore */}
+```sql
+select
+ extensions.sign(
+ payload := '{"sub":"1234567890","name":"John Doe","iat":1516239022}',
+ secret := 'secret',
+ algorithm := 'HS256'
+ );
+```
+
+The pgjwt_encode function returns a string that represents the JWT, which can then be safely transmitted between parties.
+
+{/* prettier-ignore */}
+```
+ sign
+---------------------------------
+ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX
+ VCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiw
+ ibmFtZSI6IkpvaG4gRG9lIiwiaWF0Ijo
+ xNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y9
+ 22BhjWgQzWXcXNrz0ogtVhfEd2o
+(1 row)
+```
+
+To parse a JWT and extract its claims, you can use the `verify` function. Here's an example:
+
+{/* prettier-ignore */}
+```sql
+select
+ extensions.verify(
+ token := 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiRm9vIn0.Q8hKjuadCEhnCPuqIj9bfLhTh_9QSxshTRsA5Aq4IuM',
+ secret := 'secret',
+ algorithm := 'HS256'
+ );
+```
+
+Which returns the decoded contents and some associated metadata.
+
+{/* prettier-ignore */}
+```sql
+ header | payload | valid
+-----------------------------+----------------+-------
+ {"alg":"HS256","typ":"JWT"} | {"name":"Foo"} | t
+(1 row)
+```
+
+## Resources
+
+- Official [`pgjwt` documentation](https://github.com/michelp/pgjwt)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pgnet.mdx b/apps/docs/pages/guides/database/extensions/pgnet.mdx
index 18c51a8dd2a..3246fb4f5df 100644
--- a/apps/docs/pages/guides/database/extensions/pgnet.mdx
+++ b/apps/docs/pages/guides/database/extensions/pgnet.mdx
@@ -16,9 +16,8 @@ The pg_net API is in alpha. Functions signatures may change.
It differs from the `http` extension in that it is asynchronous by default. This makes it useful in blocking functions (like triggers).
-## Usage
-### Enable the extension
+## Enable the extension
-### Creating a full text search index
+## Creating a full text search index
Given a table with a `text` column:
diff --git a/apps/docs/pages/guides/database/extensions/pgrouting.mdx b/apps/docs/pages/guides/database/extensions/pgrouting.mdx
new file mode 100644
index 00000000000..73a047fb362
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pgrouting.mdx
@@ -0,0 +1,159 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pgrouting',
+ title: 'pgrouting: Geospatial Routing',
+ description: 'Extends PostGIS with Geospatial Routing',
+}
+
+[pgRouting](http://pgrouting.org) is PostgreSQL and [PostGIS](http://postgis.net) extension adding geospatial routing functionality.
+
+The core functionality of `pgRouting` is a set of path finding algorithms including:
+
+- All Pairs Shortest Path, Johnson’s Algorithm
+- All Pairs Shortest Path, Floyd-Warshall Algorithm
+- Shortest Path A\*
+- Bi-directional Dijkstra Shortest Path
+- Bi-directional A\* Shortest Path
+- Shortest Path Dijkstra
+- Driving Distance
+- K-Shortest Path, Multiple Alternative Paths
+- K-Dijkstra, One to Many Shortest Path
+- Traveling Sales Person
+- Turn Restriction Shortest Path (TRSP)
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pgrouting" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pgRouting" extension
+create extension pgrouting cascade;
+
+-- Disable the "pgRouting" extension
+drop extension if exists pgRouting;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+
+
+
+## Example
+
+As an example, we'll solve the [traveling salesman probelem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using the pgRouting's `pgr_TSPeuclidean` function from some PostGIS coodinates.
+
+A summary of the traveling salesman problem is, given a set of city coordinates, solve for a path that goes through each city and minimizes the total distance traveled.
+
+First we populate a table with some X, Y coordinates
+
+{/* prettier-ignore */}
+```sql
+create table wi29 (
+ id bigint,
+ x float,
+ y float,
+ geom geometry
+);
+
+insert into wi29 (id, x, y)
+values
+ (1,20833.3333,17100.0000),
+ (2,20900.0000,17066.6667),
+ (3,21300.0000,13016.6667),
+ (4,21600.0000,14150.0000),
+ (5,21600.0000,14966.6667),
+ (6,21600.0000,16500.0000),
+ (7,22183.3333,13133.3333),
+ (8,22583.3333,14300.0000),
+ (9,22683.3333,12716.6667),
+ (10,23616.6667,15866.6667),
+ (11,23700.0000,15933.3333),
+ (12,23883.3333,14533.3333),
+ (13,24166.6667,13250.0000),
+ (14,25149.1667,12365.8333),
+ (15,26133.3333,14500.0000),
+ (16,26150.0000,10550.0000),
+ (17,26283.3333,12766.6667),
+ (18,26433.3333,13433.3333),
+ (19,26550.0000,13850.0000),
+ (20,26733.3333,11683.3333),
+ (21,27026.1111,13051.9444),
+ (22,27096.1111,13415.8333),
+ (23,27153.6111,13203.3333),
+ (24,27166.6667,9833.3333),
+ (25,27233.3333,10450.0000),
+ (26,27233.3333,11783.3333),
+ (27,27266.6667,10383.3333),
+ (28,27433.3333,12400.0000),
+ (29,27462.5000,12992.2222);
+```
+
+Next we use the `pgr_TSPeuclidean` function to find the best path.
+
+{/* prettier-ignore */}
+```sql
+select
+ *
+from
+ pgr_TSPeuclidean($$select * from wi29$$)
+```
+
+{/* prettier-ignore */}
+```sql
+ seq | node | cost | agg_cost
+-----+------+------------------+------------------
+ 1 | 1 | 0 | 0
+ 2 | 2 | 74.535614157127 | 74.535614157127
+ 3 | 6 | 900.617093380362 | 975.152707537489
+ 4 | 10 | 2113.77757765045 | 3088.93028518793
+ 5 | 11 | 106.718669615254 | 3195.64895480319
+ 6 | 12 | 1411.95293791574 | 4607.60189271893
+ 7 | 13 | 1314.23824873744 | 5921.84014145637
+ 8 | 14 | 1321.76283931305 | 7243.60298076942
+ 9 | 17 | 1202.91366735569 | 8446.5166481251
+ 10 | 18 | 683.333268292684 | 9129.84991641779
+ 11 | 15 | 1108.05137466134 | 10237.9012910791
+ 12 | 19 | 772.082339448903 | 11009.983630528
+ 13 | 22 | 697.666150054665 | 11707.6497805827
+ 14 | 23 | 220.141999627513 | 11927.7917802102
+ 15 | 21 | 197.926372783442 | 12125.7181529937
+ 16 | 29 | 440.456596290771 | 12566.1747492844
+ 17 | 28 | 592.939989005405 | 13159.1147382898
+ 18 | 26 | 648.288376333318 | 13807.4031146231
+ 19 | 20 | 509.901951359278 | 14317.3050659824
+ 20 | 25 | 1330.83095428717 | 15648.1360202696
+ 21 | 27 | 74.535658878487 | 15722.6716791481
+ 22 | 24 | 559.016994374947 | 16281.688673523
+ 23 | 16 | 1243.87392358622 | 17525.5625971092
+ 24 | 9 | 4088.0585364911 | 21613.6211336004
+ 25 | 7 | 650.85409697993 | 22264.4752305803
+ 26 | 3 | 891.004385199336 | 23155.4796157796
+ 27 | 4 | 1172.36699411442 | 24327.846609894
+ 28 | 8 | 994.708187806297 | 25322.5547977003
+ 29 | 5 | 1188.01888359478 | 26510.5736812951
+ 30 | 1 | 2266.91173136004 | 28777.4854126552
+```
+
+## Resources
+
+- Official [`pgRouting` documentation](https://docs.pgrouting.org/latest/en/index.html)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pgsodium.mdx b/apps/docs/pages/guides/database/extensions/pgsodium.mdx
new file mode 100644
index 00000000000..f11c5fc3ec8
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/pgsodium.mdx
@@ -0,0 +1,49 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'pgsodium',
+ title: 'pgsodium: Encryption Features',
+ description: 'Encryption library for PostgreSQL',
+}
+
+[pgsodium](https://github.com/michelp/pgsodium) is a PostgreSQL extension which provides SQL access to libsodium's high-level cryptographic algorithms. It also enables some Postgres specific features including:
+
+- [Server Key Management](https://github.com/michelp/pgsodium#server-key-management)
+- [Transparent Column Encryption](https://github.com/michelp/pgsodium#transparent-column-encryption)
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "pgsodium" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "pgsodium" extension
+create extension pgsodium;
+
+-- Disable the "pgsodium" extension
+drop extension if exists pgsodium;
+```
+
+
+
+
+## Resources
+
+- Official [`pgsodium` documentation](https://github.com/michelp/pgsodium)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/pgtap.mdx b/apps/docs/pages/guides/database/extensions/pgtap.mdx
index fc642b522ab..219eedd11ee 100644
--- a/apps/docs/pages/guides/database/extensions/pgtap.mdx
+++ b/apps/docs/pages/guides/database/extensions/pgtap.mdx
@@ -15,9 +15,7 @@ Let's cover some basic concepts:
- Unit tests: allow you to test small parts of a system (like a database table!).
- TAP: stands for [Test Anything Protocol](http://testanything.org/). It is an framework which aims to simplify the error reporting during testing.
-## Usage
-
-### Enable the extension
+## Enable the extension
-### Testing tables
+## Testing tables
```sql
begin;
@@ -68,7 +66,7 @@ API:
- [`has_index()`](https://pgtap.org/documentation.html#has_index): Checks for the existence of a named index associated with the named table.
- [`has_relation()`](https://pgtap.org/documentation.html#has_relation): Tests whether or not a relation exists in the database.
-### Testing columns
+## Testing columns
```sql
begin;
@@ -86,7 +84,7 @@ API:
- [`has_column()`](https://pgtap.org/documentation.html#has_column): Tests whether or not a column exists in a given table, view, materialized view or composite type.
- [`col_is_pk()`](https://pgtap.org/documentation.html#col_is_pk): Tests whether the specified column or columns in a table is/are the primary key for that table.
-### Testing RLS Policies
+## Testing RLS Policies
```sql
begin;
@@ -133,7 +131,7 @@ API:
- [`results_eq()`](https://pgtap.org/documentation.html#results_eq)
- [`results_ne()`](https://pgtap.org/documentation.html#results_ne)
-### Testing Functions
+## Testing Functions
```sql
begin;
diff --git a/apps/docs/pages/guides/database/extensions/plpgsql_check.mdx b/apps/docs/pages/guides/database/extensions/plpgsql_check.mdx
new file mode 100644
index 00000000000..a064f463df6
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/plpgsql_check.mdx
@@ -0,0 +1,105 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'plpgsql_check',
+ title: 'plpgsql_check: PL/pgSQL Linter',
+ description: 'Lint PL/pgSQL code',
+}
+
+[plpgsql_check](https://github.com/okbob/plpgsql_check) is a PostgreSQL extension that lints plpgsql for syntax, semantic and other related issues. The tool helps developers to identify and correct errors before executing the code. plpgsql_check is most useful for developers who are working with large or complex SQL codebases, as it can help identify and resolve issues early in the development cycle.
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "plpgsql_check" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "plpgsql_check" extension
+create extension plpgsql_check;
+
+-- Disable the "plpgsql_check" extension
+drop extension if exists plpgsql_check;
+```
+
+Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
+To disable an extension you can call `drop extension`.
+
+
+
+
+## API
+
+- [`plpgsql_check_function( ... )`](https://github.com/okbob/plpgsql_check#active-mode): Scans a function for errors.
+
+`plpgsql_check_function` is highly customizable. For a complete list of available arguments see [the docs](https://github.com/okbob/plpgsql_check#arguments)
+
+## Usage
+
+To demonstrate `plpgsql_check` we can create a function with a known error. In this case we create a function `some_func`, that references a non-existent column `place.created_at`.
+
+{/* prettier-ignore */}
+```sql
+create table place(
+ x float,
+ y float
+);
+
+create or replace function public.some_func()
+ returns void
+ language plpgsql
+as $$
+declare
+ rec record;
+begin
+ for rec in select * from place
+ loop
+ -- Bug: There is no column `created_at` on table `place`
+ raise notice '%', rec.created_at;
+ end loop;
+end;
+$$;
+```
+
+Note that executing the function would not catch the invalid reference error because the `loop` does not execute if no rows are present in the table.
+
+{/* prettier-ignore */}
+```sql
+select public.some_func();
+ some_func
+ ───────────
+
+ (1 row)
+```
+
+Now we can use plpgsql_check's `plpgsql_check_function` function to identify the known error.
+
+{/* prettier-ignore */}
+```sql
+select plpgsql_check_function('public.some_func()');
+
+ plpgsql_check_function
+------------------------------------------------------------
+ error:42703:8:RAISE:record "rec" has no field "created_at"
+ Context: SQL expression "rec.created_at"
+```
+
+## Resources
+
+- Official [`plpgsql_check` documentation](https://github.com/okbob/plpgsql_check)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/plv8.mdx b/apps/docs/pages/guides/database/extensions/plv8.mdx
index eb408b2c30f..fdb827f85da 100644
--- a/apps/docs/pages/guides/database/extensions/plv8.mdx
+++ b/apps/docs/pages/guides/database/extensions/plv8.mdx
@@ -15,9 +15,8 @@ While Postgres natively runs SQL, it can also run other "procedural languages".
It can be used for database functions, triggers, queries and more.
-## Usage
-### Enable the extension
+## Enable the extension
-### Create `plv8` functions
+## Create `plv8` functions
Functions written in `plv8` are written just like any other PostgreSQL functions, only
with the `language` identifier set to `plv8`.
@@ -135,6 +134,8 @@ returns setof messages as $$
return json_result;
$$ language plv8;
+
+select * from get_messages();
```
## Resources
diff --git a/apps/docs/pages/guides/database/extensions/postgis.mdx b/apps/docs/pages/guides/database/extensions/postgis.mdx
index 6f241b0774e..9e9a65098ad 100644
--- a/apps/docs/pages/guides/database/extensions/postgis.mdx
+++ b/apps/docs/pages/guides/database/extensions/postgis.mdx
@@ -14,9 +14,7 @@ While you may be able to store simple lat/long geographic coordinates as a set o
The additional data types that PostGIS provides include [Point](https://postgis.net/docs/using_postgis_dbmanagement.html#Point), [Polygon](https://postgis.net/docs/using_postgis_dbmanagement.html#Polygon), [Linestring](https://postgis.net/docs/using_postgis_dbmanagement.html#LineString), and many more to represent different types of geographical data. In this guide, we will mainly focus on how to interact with `Point` type, which represents a single set of latitude and longitude. If you are interested in digging deeper, you can learn more about different data types on the [data management section of PostGIS docs](https://postgis.net/docs/using_postgis_dbmanagement.html).
-## Usage
-
-### Enable the extension
+## Enable the extension
You can get started with PostGIS by enabling the PostGIS extension in your Supabase dashboard.
diff --git a/apps/docs/pages/guides/database/extensions/timescaledb.mdx b/apps/docs/pages/guides/database/extensions/timescaledb.mdx
new file mode 100644
index 00000000000..265e8662ad4
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/timescaledb.mdx
@@ -0,0 +1,99 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'timescaledb',
+ title: 'timescaledb: Time-Series data',
+ description: 'Scalable time-series data storage and analysis',
+}
+
+[timescaledb](https://docs.timescale.com/timescaledb/latest/) is a PostgreSQL extension designed for improved handling of time-series data. It provides a scalable, high-performance solution for storing and querying time-series data on top of a standard PostgreSQL database.
+
+`timescaledb` uses a time-series-aware storage model and indexing techniques to improve performance of PostgreSQL in working with time-series data. The extension divides data into chunks based on time intervals, allowing it to scale efficiently, especially for large data sets. The data is then compressed, optimized for write-heavy workloads, and partitioned for parallel processing. `timescaledb` also includes a set of functions, operators, and indexes that work with time-series data to reduce query times, and make data easier to work with.
+
+## Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "timescaledb" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "timescaledb" extension
+create extension timescaledb;
+
+-- Disable the "timescaledb" extension
+drop extension if exists timescaledb;
+```
+
+
+
+
+## Usage
+
+To demonstrate how `timescaledb` works, let's consider a simple example where we have a table that stores temperature data from different sensors. We will create a table named "temperatures" and store data for two sensors.
+
+First we create a hypertable, which is a virtual table that is partitioned into chunks based on time intervals. The hypertable acts as a proxy for the actual table and makes it easy to query and manage time-series data.
+
+{/* prettier-ignore */}
+```sql
+create table temperatures (
+ time timestamp not null,
+ sensor_id int not null,
+ temperature double precision not null
+);
+
+select create_hypertable('temperatures', 'time');
+```
+
+Next, we can populate some values
+
+{/* prettier-ignore */}
+```sql
+insert into temperatures (time, sensor_id, temperature)
+values
+ ('2023-02-14 09:00:00', 1, 23.5),
+ ('2023-02-14 09:00:00', 2, 21.2),
+ ('2023-02-14 09:05:00', 1, 24.5),
+ ('2023-02-14 09:05:00', 2, 22.3),
+ ('2023-02-14 09:10:00', 1, 25.1),
+ ('2023-02-14 09:10:00', 2, 23.9),
+ ('2023-02-14 09:15:00', 1, 24.9),
+ ('2023-02-14 09:15:00', 2, 22.7),
+ ('2023-02-14 09:20:00', 1, 24.7),
+ ('2023-02-14 09:20:00', 2, 23.5);
+```
+
+And finally we can query the table using `timescaledb`'s `time_bucket` function to divide the time-series into intervals of the specified size (in this case, 1 hour) averaging the `temperature` reading within each group.
+
+{/* prettier-ignore */}
+```sql
+select
+ time_bucket('1 hour', time) AS hour,
+ avg(temperature) AS average_temperature
+from
+ temperatures
+where
+ sensor_id = 1
+ and time > NOW() - interval '1 hour'
+group by
+ hour;
+```
+
+## Resources
+
+- Official [`timescaledb` documentation](https://docs.timescale.com/timescaledb/latest/)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx b/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx
index 167e9b92807..b270fdd581f 100644
--- a/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx
+++ b/apps/docs/pages/guides/database/extensions/uuid-ossp.mdx
@@ -13,9 +13,7 @@ The `uuid-ossp` extension can be used to generate a `UUID`.
A `UUID` is a "Universally Unique Identifier" and it is, for practical purposes, unique.
This makes them particularly well suited as Primary Keys. It is occasionally referred to as a `GUID`, which stands for "Globally Unique Identifier".
-## Usage
-
-### Enable the extension
+## Enable the extension
-### The `uuid` type
+## The `uuid` type
Once the extension is enabled, you now have access to a `uuid` type.
-### `uuid_generate_v1()`
+## `uuid_generate_v1()`
Creates a UUID value based on the combination of computer’s MAC address, current timestamp, and a random value.
@@ -67,7 +65,7 @@ Creates a UUID value based on the combination of computer’s MAC address, curre
applications.
-### `uuid_generate_v4()`
+## `uuid_generate_v4()`
Creates UUID values based solely on random numbers. You can also use Postgres's built-in [`gen_random_uuid()`](https://www.postgresql.org/docs/current/functions-uuid.html) function to generate a UUIDv4.
diff --git a/apps/docs/pages/guides/database/extensions/wrappers.mdx b/apps/docs/pages/guides/database/extensions/wrappers.mdx
new file mode 100644
index 00000000000..943b1dd6391
--- /dev/null
+++ b/apps/docs/pages/guides/database/extensions/wrappers.mdx
@@ -0,0 +1,75 @@
+import Layout from '~/layouts/DefaultGuideLayout'
+
+export const meta = {
+ id: 'wrappers',
+ title: 'wrappers: 3rd Party Integrations',
+ description: '3rd party integrations for PostgreSQL ',
+}
+
+[supabase/wrappers](https://supabase.github.io/wrappers/) is a PostgreSQL extension that provides integrations with external sources so you can interact with third-party data using SQL.
+
+For example, the [Stripe wrapper](https://supabase.github.io/wrappers/stripe/) connects to [Stripe's API](https://stripe.com/docs/api) and exposes each endpoint as a SQL table.
+
+{/* prettier-ignore */}
+```sql
+select
+ customer_id
+ currency
+from
+ stripe.customers;
+
+ customer_id | currency
+--------------------+-----------
+ cus_MJiBtCqOF1Bb3F | usd
+(1 row)
+```
+
+## Usage
+
+### Enable the extension
+
+
+
+
+1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
+2. Click on **Extensions** in the sidebar.
+3. Search for "wrappers" and enable the extension.
+
+
+
+
+{/* prettier-ignore */}
+```sql
+-- Enable the "wrappers" extension
+create extension wrappers;
+
+-- Disable the "wrappers" extension
+drop extension if exists wrappers;
+```
+
+
+
+
+Instructions for setting up connections to each 3rd party service via SQL are available at the links in the integrations section below.
+A web interface for connecting to external data is coming to Supabase Studio in 2023.
+
+## Integrations
+
+- [Firebase](https://supabase.github.io/wrappers/firebase/)
+- [Stripe](https://supabase.github.io/wrappers/stripe/)
+- Airtable - Coming Soon
+- BigQuery - Coming Soon
+- Clickhouse - Coming Soon
+
+## Resources
+
+- Official [`supabase/wrappers` documentation](https://supabase.github.io/wrappers/)
+
+export const Page = ({ children }) =>
+
+export default Page
diff --git a/apps/docs/pages/guides/database/tables.mdx b/apps/docs/pages/guides/database/tables.mdx
index 13fd0bfa2bd..9ed2619b47d 100644
--- a/apps/docs/pages/guides/database/tables.mdx
+++ b/apps/docs/pages/guides/database/tables.mdx
@@ -242,9 +242,18 @@ You would [connect](../../guides/database/connecting-to-postgres#direct-connecti
```bash
psql -h DATABASE_URL -p 5432 -d postgres -U postgres \
- -c "COPY movies FROM './movies.csv';"
+ -c "\COPY movies FROM './movies.csv';"
```
+Additionally use the `DELIMITER`, `HEADER` and `FORMAT` options as defined in the PostgreSQL [COPY](https://www.postgresql.org/docs/current/sql-copy.html) docs.
+
+```bash
+psql -h DATABASE_URL -p 5432 -d postgres -U postgres \
+ -c "\COPY movies FROM './movies.csv' WITH DELIMITER ',' CSV HEADER"
+```
+
+If you receive an error `FATAL: password authentication failed for user "postgres"`, reset your database password in the Database Settings and try again.
+
## Joining tables with Foreign Keys
Tables can be "joined" together using Foreign Keys.
diff --git a/apps/docs/pages/guides/integrations/flutterflow.mdx b/apps/docs/pages/guides/integrations/flutterflow.mdx
index b7a25f8d1a5..ed6ddf1f046 100644
--- a/apps/docs/pages/guides/integrations/flutterflow.mdx
+++ b/apps/docs/pages/guides/integrations/flutterflow.mdx
@@ -8,8 +8,14 @@ export const meta = {
canonical: 'https://docs.flutterflow.io/actions/actions/backend-database/supabase',
}
+
+ FlutterFlow and Supabase integration is currently in alpha, and supported features may be limited.
+
+
[FlutterFlow](https://flutterflow.io/) is a low-code builder for developing native mobile applications using Flutter. You can use the simple drag-and-drop interface to build your app faster than traditional development.
+This guide gives you a quick overview of implementing basic CRUD operations using FlutterFlow and Supabase. You can find the full docs on FlutterFlow and Supabase [here](https://docs.flutterflow.io/actions/actions/backend-database/supabase).
+
-This guide gives you a quick overview of implementing basic CRUD operations using FlutterFlow and Supabase. You can find the full docs on FlutterFlow and Supabase [here](https://docs.flutterflow.io/actions/actions/backend-database/supabase).
## Step 1: Connect FlutterFlow to Supabase
diff --git a/apps/docs/pages/guides/platform/database-usage.mdx b/apps/docs/pages/guides/platform/database-usage.mdx
index c6a734b4fac..6ce6385770d 100644
--- a/apps/docs/pages/guides/platform/database-usage.mdx
+++ b/apps/docs/pages/guides/platform/database-usage.mdx
@@ -24,7 +24,7 @@ This value is also reported in the [database settings page](https://app.supabase
Supabase uses network-attached storage to balance performance with scalability.
For Pro and Enterprise projects, disk size expands ~1.5x automatically (e.g., 8GB -> 12GB) when you reach 90% of the disk size.
-Automatic disk size expansion can only occur once every six hours.
+Disk size expansion can only occur once every six hours.
Pro projects can store up to 1024TB.
All projects enter read-only mode when you reach 95% of the disk size. In read-only mode, clients will encounter errors such as `cannot execute INSERT in a read-only transaction`.
diff --git a/apps/docs/pages/learn/auth-deep-dive/auth-policies.mdx b/apps/docs/pages/learn/auth-deep-dive/auth-policies.mdx
index 636eef09903..00caf731fbc 100644
--- a/apps/docs/pages/learn/auth-deep-dive/auth-policies.mdx
+++ b/apps/docs/pages/learn/auth-deep-dive/auth-policies.mdx
@@ -155,6 +155,17 @@ create policy "Only Blizzard staff can update leaderboard"
Supabase comes with two built-in helper functions: `auth.uid()` and `auth.jwt()`.
+To create your own functions, navigate to the SQL editor and create a a new query.
+
+```sql
+create or replace function user_agent()
+returns text
+language sql
+as $$
+ select nullif(current_setting('request.headers', true)::json->>'user-agent', '')::text;
+$$;
+```
+
See the full PostgreSQL policy docs here: [https://www.postgresql.org/docs/12/sql-createpolicy.html](https://www.postgresql.org/docs/12/sql-createpolicy.html)
You can get as creative as you like with these policies.
diff --git a/apps/docs/public/sitemap.xml b/apps/docs/public/sitemap.xml
index 90cd255fc9c..35bf4d7ff55 100644
--- a/apps/docs/public/sitemap.xml
+++ b/apps/docs/public/sitemap.xml
@@ -3867,4 +3867,4 @@
weekly0.5
-
+
\ No newline at end of file
diff --git a/apps/www/_blog/2022-06-30-flutter-tutorial-building-a-chat-app.mdx b/apps/www/_blog/2022-06-30-flutter-tutorial-building-a-chat-app.mdx
index 8285a717828..cbe86871d1b 100644
--- a/apps/www/_blog/2022-06-30-flutter-tutorial-building-a-chat-app.mdx
+++ b/apps/www/_blog/2022-06-30-flutter-tutorial-building-a-chat-app.mdx
@@ -890,5 +890,6 @@ If you have any questions please reach out via [Twitter](https://twitter.com/dsh
- [Part 2: Flutter Authentication and Authorization with RLS](https://supabase.com/blog/flutter-authentication-and-authorization-with-rls)
- [Flutter Supabase Quick Starter Guide](https://supabase.com/docs/guides/with-flutter)
- [supabase-flutter v1.0 released](https://supabase.com/blog/supabase-flutter-sdk-v1-released)
+- [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-multiplayer-game)
- [Open source map based Flutter app with CI/CD and scalable statemanagement example](https://github.com/dshukertjr/spot)
- [Build a Flutter app with Very Good CLI and Supabase](https://verygood.ventures/blog/flutter-app-very-good-cli-supabase)
diff --git a/apps/www/_blog/2022-08-02-supabase-flutter-sdk-1-developer-preview.mdx b/apps/www/_blog/2022-08-02-supabase-flutter-sdk-1-developer-preview.mdx
index 39f8595377c..cdabad21e70 100644
--- a/apps/www/_blog/2022-08-02-supabase-flutter-sdk-1-developer-preview.mdx
+++ b/apps/www/_blog/2022-08-02-supabase-flutter-sdk-1-developer-preview.mdx
@@ -160,4 +160,5 @@ If you have any feedbacks, please let us know in the issues of the [supabase-flu
- [supabase-flutter 1.0 developer preview](https://pub.dev/packages/supabase_flutter)
- [Flutter Tutorial: building a Flutter chat app](https://supabase.com/blog/flutter-tutorial-building-a-chat-app)
- [Flutter Tutorial - Part 2: Authentication and Authorization with RLS](https://supabase.com/blog/flutter-authentication-and-authorization-with-rls)
+- [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-multiplayer-game)
- [Build a Flutter app with Very Good CLI and Supabase](https://verygood.ventures/blog/flutter-app-very-good-cli-supabase)
diff --git a/apps/www/_blog/2022-10-21-supabase-flutter-sdk-v1-released.mdx b/apps/www/_blog/2022-10-21-supabase-flutter-sdk-v1-released.mdx
index 92aed5cbb3b..8709747976a 100644
--- a/apps/www/_blog/2022-10-21-supabase-flutter-sdk-v1-released.mdx
+++ b/apps/www/_blog/2022-10-21-supabase-flutter-sdk-v1-released.mdx
@@ -100,4 +100,5 @@ It required massive support from the community to bring the supabase-flutter to
- [v0 to v1 migration guide](https://supabase.com/docs/reference/dart/v0/upgrade-guide)
- [Flutter Tutorial: building a Flutter chat app](https://supabase.com/blog/flutter-tutorial-building-a-chat-app)
- [Flutter Tutorial - Part 2: Authentication and Authorization with RLS](https://supabase.com/blog/flutter-authentication-and-authorization-with-rls)
+- [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-multiplayer-game)
- [Build a Flutter app with Very Good CLI and Supabase](https://verygood.ventures/blog/flutter-app-very-good-cli-supabase)
diff --git a/apps/www/_blog/2022-11-22-flutter-authentication-and-authorization-with-rls.mdx b/apps/www/_blog/2022-11-22-flutter-authentication-and-authorization-with-rls.mdx
index e6ecfbe4cd2..fde39a288d0 100644
--- a/apps/www/_blog/2022-11-22-flutter-authentication-and-authorization-with-rls.mdx
+++ b/apps/www/_blog/2022-11-22-flutter-authentication-and-authorization-with-rls.mdx
@@ -1357,6 +1357,7 @@ We can for example update this to a list of users that are online at the same ti
- [Complete set of code of this chat app](https://github.com/supabase-community/flutter-chat/tree/with_auth)
- [supabase-flutter docs](https://supabase.com/docs/reference/dart)
+- [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-multiplayer-game)
- [Flutter Supabase Quick Starter Guide](https://supabase.com/docs/guides/with-flutter)
- [supabase-flutter v1.0 released](https://supabase.com/blog/supabase-flutter-sdk-v1-released)
- [Build a Flutter app with Very Good CLI and Supabase](https://verygood.ventures/blog/flutter-app-very-good-cli-supabase)
diff --git a/apps/www/_blog/2023-02-03-openai-embeddings-postgres-vector.mdx b/apps/www/_blog/2023-02-03-openai-embeddings-postgres-vector.mdx
index c04183c99b0..e6c7aa2fe4f 100644
--- a/apps/www/_blog/2023-02-03-openai-embeddings-postgres-vector.mdx
+++ b/apps/www/_blog/2023-02-03-openai-embeddings-postgres-vector.mdx
@@ -6,7 +6,7 @@ image: embeddings/og_pgvector.png
thumb: embeddings/og_pgvector.png
tags:
- postgres
- - ai
+ - AI
date: '2023-02-06'
toc_depth: 3
---
diff --git a/apps/www/_blog/2023-02-07-chatgpt-supabase-docs.mdx b/apps/www/_blog/2023-02-07-chatgpt-supabase-docs.mdx
index 6c1b29a9e70..bce1784c0f6 100644
--- a/apps/www/_blog/2023-02-07-chatgpt-supabase-docs.mdx
+++ b/apps/www/_blog/2023-02-07-chatgpt-supabase-docs.mdx
@@ -5,7 +5,7 @@ author: paul_copplestone
image: docsgpt/og_supabase_clippy.png
thumb: docsgpt/og_supabase_clippy.png
tags:
- - ai
+ - AI
- docs
date: '2023-02-07'
toc_depth: 3
diff --git a/apps/www/_blog/2023-02-14-flutter-real-time-multiplayer-game.mdx b/apps/www/_blog/2023-02-14-flutter-real-time-multiplayer-game.mdx
index 321263554ba..796f60340f8 100644
--- a/apps/www/_blog/2023-02-14-flutter-real-time-multiplayer-game.mdx
+++ b/apps/www/_blog/2023-02-14-flutter-real-time-multiplayer-game.mdx
@@ -14,7 +14,7 @@ toc_depth: 3
Flutter is a UI library to build apps that run on any platform, but it can also build interactive games thanks to an open-source game engine built on top of Flutter called [Flame](https://flame-engine.org/). Flame takes care of things like collision detection or loading image sprites to bring game development to all the Flutter devs. We can take it a step further to introduce real-time communication features so that players can play against each other in real-time.
-In this article, we will use Flutter, Flame, and Supabase's real-time features to build a real-time multiplayer shooting game. You can find the complete code of this tutorial [here](https://github.com/supabase/supabase/tree/master/examples/realtime/examples/flutter-multiplayer-shooting-game).
+In this article, we will use Flutter, Flame, and Supabase's real-time features to build a real-time multiplayer shooting game. You can find the complete code of this tutorial [here](https://github.com/supabase/supabase/tree/master/examples/realtime/flutter-multiplayer-shooting-game).
## Overview of the final game
@@ -833,7 +833,8 @@ We learned how to create an interactive shooting game. We took advantage of Flut
## More Flutter Resources
-- [Complete code of this article](https://github.com/supabase/supabase/tree/master/examples/realtime/examples/flutter-multiplayer-shooting-game)
-- [Flame Engine website](https://flame-engine.org/)
+- [Complete code of this article](https://github.com/supabase/supabase/tree/master/examples/realtime/flutter-multiplayer-shooting-game)
+- [Flutter Tutorial: building a Flutter chat app](https://supabase.com/blog/flutter-tutorial-building-a-chat-app)
+- [Flutter Authentication and Authorization with RLS](https://supabase.com/blog/flutter-authentication-and-authorization-with-rls)
- [Generate Flame template using Very Good CLI](https://verygood.ventures/blog/generate-a-game-with-our-new-template)
- [Supabase Flutter SDK docs](https://supabase.com/docs/reference/dart/start)
diff --git a/apps/www/components/AuthWidget/AuthWidgetSection.tsx b/apps/www/components/AuthWidget/AuthWidgetSection.tsx
index 047ff5c4ac7..f9ee1bbf25a 100644
--- a/apps/www/components/AuthWidget/AuthWidgetSection.tsx
+++ b/apps/www/components/AuthWidget/AuthWidgetSection.tsx
@@ -3,10 +3,11 @@ import { Button } from 'ui'
import { useState } from 'react'
// Import Swiper React components
import { useRouter } from 'next/router'
+import Image from 'next/image'
import { ColorSwatchIcon, MenuIcon } from '@heroicons/react/outline'
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
-import { useTheme } from '../Providers'
+import { useTheme } from 'common/Providers'
const supabase = createClient(
'https://rsnibhkhsbfnncjmwnkj.supabase.co',
@@ -120,7 +121,14 @@ function AuthWidgetSection() {
match your brand and aesthetic
+ Every project on the Supabase Platform comes with its own dedicated Postgres
+ instance running inside a virtual machine (VM). The following table describes the
+ base instance with additional compute add-ons available if you need extra
+ performance when scaling up Supabase.
+