Skip to content

Commit 3d4ec19

Browse files
author
ppom
committed
Documentation: add "Extensions to SQL" page
Fix sqlpage#877
1 parent fbe897a commit 3d4ec19

File tree

3 files changed

+219
-0
lines changed

3 files changed

+219
-0
lines changed

examples/official-site/sqlpage/migrations/01_documentation.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,7 @@ You see the [page layouts demo](./examples/layouts.sql) for a live example of th
12311231
{"link": "/your-first-sql-website", "title": "Getting started", "icon": "book"},
12321232
{"link": "/components.sql", "title": "All Components", "icon": "list-details"},
12331233
{"link": "/functions.sql", "title": "SQLPage Functions", "icon": "math-function"},
1234+
{"link": "your-first-sql-website/extensions-to-sql.sql", "title": "Extensions to SQL", "icon": "cube-plus"},
12341235
{"link": "/custom_components.sql", "title": "Custom Components", "icon": "puzzle"},
12351236
{"link": "//github.com/sqlpage/SQLPage/blob/main/configuration.md#configuring-sqlpage", "title": "Configuration", "icon": "settings"}
12361237
]}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# Extensions to SQL
2+
3+
SQLPage makes some special treatment before executing your SQL queries.
4+
5+
When executing your SQL file, SQLPage executes each query one at a time.
6+
It doesn't send the whole file as-is to the database engine.
7+
8+
## Performance
9+
10+
See the [performance page](/performance.sql) for details on the optimizations
11+
made to run your queries as fast as possible.
12+
13+
## Variables
14+
15+
SQL doesn't have its own mechanism for variables.
16+
SQLPage implements variables in the following way:
17+
18+
### POST parameters
19+
20+
When sending a POST request, most often by sending a form with the
21+
[form component](/component.sql?component=form), the form data is made
22+
available as variables prefixed by a semi-colon.
23+
24+
So when this form is sent:
25+
26+
`form.sql`
27+
```sql
28+
SELECT
29+
'form' AS component,
30+
'POST' AS method, -- form defaults to using the HTTP POST method
31+
'result.sql' AS action;
32+
33+
SELECT
34+
'age' AS name,
35+
'How old are you?' AS label,
36+
'number' AS type;
37+
```
38+
39+
It will make a request to this page:
40+
41+
`result.sql`
42+
```sql
43+
SELECT
44+
'text' AS component,
45+
'You are ' || :age || ' years old!' AS contents;
46+
```
47+
48+
`:age` will be substituted by the actual value of the POST parameter.
49+
50+
### URL parameters
51+
52+
Likewise, URL parameters are available as variables prefixed by a dollar sign.
53+
54+
> URL parameters are often called GET parameters because they can originate
55+
> from a form with 'GET' as the method.
56+
57+
So the previous example can be reworked to handle URL parameters:
58+
59+
`result.sql`
60+
```sql
61+
SELECT
62+
'text' AS component,
63+
'You are ' || $age || ' years old!' AS contents;
64+
```
65+
66+
By querying this page with this URL: `/request.sql?age=42`
67+
we would get `You are 42 years old!` as a response.
68+
69+
### The `SET` command
70+
71+
SQLPage adds a non-standard SQL keyword: `SET`.
72+
73+
```sql
74+
SET coalesced_post_id = COALESCE($post_id, 0);
75+
```
76+
77+
`SET` statements are transformed into `SELECT` queries, and their result is stored in a `$`-variable:
78+
79+
```sql
80+
SELECT COALESCE($post_id, 0);
81+
```
82+
83+
We can override a previous `$`-variable:
84+
85+
```sql
86+
SET post_id = COALESCE($post_id, 0);
87+
```
88+
89+
### Limitations
90+
91+
`$`-variables and `:`-variables are stored by SQLPage, not in the database.
92+
93+
They can only store a string, or null.
94+
95+
As such, they're not designed to store table-valued results.
96+
They will only store the first value of the first column:
97+
98+
```sql
99+
CREATE TABLE t(a, b);
100+
INSERT INTO t(a, b) VALUES (1, 2), (3, 4);
101+
102+
SET var = (SELECT * FROM t);
103+
104+
-- now $var contains '1'
105+
```
106+
107+
Temporary table-valued results can be stored in two ways:
108+
109+
1. Using temporary tables
110+
111+
This is the most efficient method to store large values.
112+
```sql
113+
-- Database connections are reused and temporary tables are stored at the
114+
-- connection level, so we make sure the table doesn't exist already
115+
DROP TABLE IF EXISTS my_temp_table;
116+
CREATE TEMPORARY TABLE my_temp_table(a, b);
117+
118+
-- Insert data from a SELECT query
119+
INSERT INTO my_temp_table(a, b)
120+
SELECT a, b
121+
FROM my_stored_table ...
122+
123+
-- Insert data from direct values
124+
INSERT INTO my_temp_table(a, b)
125+
VALUES (1, 2), (3, 4);
126+
```
127+
128+
2. Using JSON
129+
130+
This can be more convenient, but should only be used for small values, because data
131+
is copied from the database into SQLPage memory, and to the database again at each use.
132+
133+
You can use the JSON functions from your database.
134+
Here are some examples with SQLite:
135+
```sql
136+
-- CREATE TABLE my_table(a, b);
137+
-- INSERT INTO my_table(a, b)
138+
-- VALUES (1, 2), (3, 4);
139+
140+
SET my_json = (
141+
SELECT json_group_array(a)
142+
FROM my_table
143+
);
144+
-- [1, 3]
145+
146+
SET my_json = json_array(1, 2, 3);
147+
-- [1, 2, 3]
148+
```
149+
150+
## Functions
151+
152+
Functions starting with `sqlpage.` are executed by SQLPage, not by your database engine.
153+
See the [functions page](/functions.sql) for more details.
154+
155+
They're either executed before or after the query is run in the database.
156+
157+
1. **Execution before the query**
158+
159+
When they don't process results coming from the database:
160+
161+
```sql
162+
SELECT * FROM blog WHERE slug = sqlpage.path()
163+
```
164+
165+
`sqlpage.path()` will get replaced by the result of the function.
166+
167+
2. **Execution after the query**
168+
169+
When they process results coming from the database:
170+
171+
```sql
172+
SELECT sqlpage.read_file_as_text(blog_post_file) AS title FROM blog;
173+
```
174+
175+
The query executed will be:
176+
177+
```sql
178+
SELECT blog_post_file AS title FROM blog;
179+
```
180+
181+
Then `sqlpage.read_file_as_text()` will be called on each row.
182+
183+
## Implementation details of variables and functions
184+
185+
All queries run by SQLPage in the database are first prepared, then executed.
186+
187+
Statements are prepared and cached the first time they're encountered by SQLPage.
188+
Then those cached prepared statements are executed at each run, with parameter substitution.
189+
190+
All variables and function results are cast as text, to let the
191+
database query optimizer know only strings (or nulls) will be passed.
192+
193+
Examples:
194+
195+
```sql
196+
-- Source query
197+
SELECT * FROM blog WHERE slug = sqlpage.path();
198+
199+
-- Prepared statement (SQLite syntax)
200+
SELECT * FROM blog WHERE slug = CAST(?1 AS TEXT)
201+
```
202+
203+
```sql
204+
-- Source query
205+
SET post_id = COALESCE($post_id, 0);
206+
207+
-- Prepared statement (SQLite syntax)
208+
SELECT COALESCE(CAST(?1 AS TEXT), 0)
209+
```
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
select 'http_header' as component,
2+
'public, max-age=300, stale-while-revalidate=3600, stale-if-error=86400' as "Cache-Control";
3+
4+
select 'dynamic' as component, properties FROM example WHERE component = 'shell' LIMIT 1;
5+
6+
-- Article by Matthew Larkin
7+
select 'text' as component,
8+
sqlpage.read_file_as_text('your-first-sql-website/extensions-to-sql.md') as contents_md,
9+
false as article;

0 commit comments

Comments
 (0)