@@ -11,8 +11,8 @@ If an expression evaluates to `true`, `sqlc vet` will report an error using the
11
11
12
12
## Defining lint rules
13
13
14
- Each lint rule's CEL expression has access to variables from your sqlc configuration and queries,
15
- defined in the following struct .
14
+ Each lint rule's CEL expression has access to information from your sqlc configuration and queries
15
+ via variables defined in the following proto messages .
16
16
17
17
``` proto
18
18
message Config
@@ -41,12 +41,17 @@ message Parameter
41
41
}
42
42
```
43
43
44
- This struct will likely expand in the future to include more query information.
45
- We may also add information returned from a running database, such as the result from
46
- ` EXPLAIN ... ` .
44
+ In addition to this basic information, when you have a PostgreSQL or MySQL
45
+ [ database connection configured] ( ../reference/config.html#database )
46
+ each CEL expression has access to the output from running ` EXPLAIN ... ` on your query
47
+ via the ` postgresql.explain ` and ` mysql.explain ` variables.
48
+ This output is quite complex and depends on the structure of your query but sqlc attempts
49
+ to parse and provide as much information as it can. See
50
+ [ Rules using ` EXPLAIN ... ` output] ( #rules-using-explain-output ) for more information.
47
51
48
- While these examples are simplistic, they give you a flavor of the types of
49
- rules you can write.
52
+ Here are a few example rules just using the basic configuration and query information available
53
+ to the CEL expression environment. While these examples are simplistic, they give you a flavor
54
+ of the types of rules you can write.
50
55
51
56
``` yaml
52
57
version : 2
@@ -82,6 +87,82 @@ rules:
82
87
query.cmd == "exec"
83
88
` ` `
84
89
90
+ ### Rules using ` EXPLAIN ...` output
91
+
92
+ The CEL expression environment has two variables containing `EXPLAIN ...` output,
93
+ ` postgresql.explain` and `mysql.explain`. `sqlc` only populates the variable associated with
94
+ your configured database engine, and only when you have a
95
+ [database connection configured](../reference/config.html#database).
96
+
97
+ For the `postgresql` engine, `sqlc` runs
98
+
99
+ ` ` ` sql
100
+ EXPLAIN (ANALYZE false, VERBOSE, COSTS, SETTINGS, BUFFERS, FORMAT JSON) ...
101
+ ` ` `
102
+
103
+ where `"..."` is your query string, and parses the output into a `PostgreSQLExplain` proto message.
104
+
105
+ For the `mysql` engine, `sqlc` runs
106
+
107
+ ` ` ` sql
108
+ EXPLAIN FORMAT=JSON ...
109
+ ` ` `
110
+
111
+ where `"..."` is your query string, and parses the output into a `MySQLExplain` proto message.
112
+
113
+ These proto message definitions are too long to include here, but you can find them in the `protos`
114
+ directory within the `sqlc` source tree.
115
+
116
+ The output from `EXPLAIN ...` depends on the structure of your query so it's a bit difficult
117
+ to offer generic examples. Refer to the
118
+ [PostgreSQL documentation](https://www.postgresql.org/docs/current/using-explain.html) and
119
+ [MySQL documentation](https://dev.mysql.com/doc/refman/en/explain-output.html) for more
120
+ information.
121
+
122
+ ` ` ` yaml
123
+ ...
124
+ rules:
125
+ - name: postgresql-query-too-costly
126
+ message: "Query cost estimate is too high"
127
+ rule: "postgresql.explain.plan.total_cost > 1.0"
128
+ - name: postgresql-no-seq-scan
129
+ message: "Query plan results in a sequential scan"
130
+ rule: "postgresql.explain.plan.node_type == 'Seq Scan'"
131
+ - name: mysql-query-too-costly
132
+ message: "Query cost estimate is too high"
133
+ rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0"
134
+ - name: mysql-must-use-primary-key
135
+ message: "Query plan doesn't use primary key"
136
+ rule: "has(mysql.explain.query_block.table.key) && mysql.explain.query_block.table.key != 'PRIMARY'"
137
+ ` ` `
138
+
139
+ When building rules that depend on `EXPLAIN ...` output, it may be helpful to see the actual JSON
140
+ returned from the database. `sqlc` will print it When you set the environment variable
141
+ ` SQLCDEBUG=dumpexplain=1` . Use this environment variable together with a dummy rule to see
142
+ ` EXPLAIN ...` output for all of your queries.
143
+
144
+ ` ` ` yaml
145
+ version: 2
146
+ sql:
147
+ - schema: "query.sql"
148
+ queries: "query.sql"
149
+ engine: "postgresql"
150
+ gen:
151
+ go:
152
+ package: "db"
153
+ out: "db"
154
+ rules:
155
+ - debug
156
+ rules:
157
+ - name: debug
158
+ message: "Debug"
159
+ rule: has(postgresql.explain)
160
+ ` ` `
161
+
162
+ Please note that `sqlc` does not manage or migrate your database. Use your
163
+ migration tool of choice to create the necessary database tables and objects
164
+ before running `sqlc vet` with rules that depend on `EXPLAIN ...` output.
165
+
85
166
# # Built-in rules
86
167
87
168
# ## sqlc/db-prepare
0 commit comments