@@ -11,8 +11,8 @@ If an expression evaluates to `true`, `sqlc vet` will report an error using the
1111
1212## Defining lint rules
1313
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 .
1616
1717``` proto
1818message Config
@@ -41,12 +41,17 @@ message Parameter
4141}
4242```
4343
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.
4751
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.
5055
5156``` yaml
5257version : 2
@@ -82,6 +87,82 @@ rules:
8287 query.cmd == "exec"
8388` ` `
8489
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+
85166# # Built-in rules
86167
87168# ## sqlc/db-prepare
0 commit comments