@neralabs/rerail-pack-sql 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Rerail rule pack: SQL
2
2
 
3
- 22 code rules for SQL, ported from SQLFluff 4.4.0. Every one is a candidate: it lives in `candidates/rules/` and moves
4
- to `rules/` and `pack.json` once it passes the V1 rule validation gates
5
- ([nera-rule-validation](https://github.com/neralabs/nera-rule-validation)). While `pack.json` lists no rules, the pack
6
- ships none and is never recommended. Each port is scored against SQLFluff's own findings on SQLFluff's tests and on
7
- pinned public corpora (postgres, mattermost, anki, application-services), with every disagreement declared in
8
- `divergences.json`. The conformance check (`--check`, run in CI) reports the candidates without gating them.
3
+ 22 code rules for SQL, ported from SQLFluff 4.4.0. 19 pass every blocking [port readiness](../../docs/port-readiness.md)
4
+ gate and ship: they live in `rules/` and `pack.json` lists them, 17 on and PG01 and PG02 off. The other 3 (AL05, AM02
5
+ and RF01) are candidates: they live in `candidates/rules/` and move to `rules/` and `pack.json` once they pass every
6
+ blocking gate (see "Port readiness" below). Each port is scored against SQLFluff's own findings on SQLFluff's tests and
7
+ on pinned public corpora (postgres, mattermost, anki, application-services), with every disagreement declared in
8
+ `divergences.json`. The conformance check (`--check`, run in CI) gates the shipped rules and reports the candidates.
9
9
 
10
10
  It follows the [pack structure and validation contract](../../docs/pack-format.md): it is checked by
11
11
  `npx vitest run test/engine/catalog/packs.test.ts -t "pack sql"` and by
@@ -14,20 +14,22 @@ It follows the [pack structure and validation contract](../../docs/pack-format.m
14
14
 
15
15
  | Path | What |
16
16
  |---|---|
17
- | `pack.json` | The pack (`rerail.rule-pack/v1`); it lists no rules while every port is a candidate |
18
- | `candidates/rules/` | The 22 candidate code-rule documents (`rerail.policy/v1`), one per port, named for its id |
19
- | `conformance.json` | Every port (all candidates): its upstream tool and rule, how findings compare, and the capabilities it exercises; the pinned tool and the pinned corpora |
17
+ | `pack.json` | The pack (`rerail.rule-pack/v1`): the 19 shipped rules, with PG01 and PG02 `"on": false` |
18
+ | `rules/` | The 19 shipped code-rule documents (`rerail.policy/v1`), one per port, named for its id |
19
+ | `candidates/rules/` | The 3 candidate code-rule documents: AL05, AM02 and RF01 |
20
+ | `conformance.json` | Every port (shipped and candidate): its upstream tool and rule, how findings compare, and the capabilities it exercises; the pinned tool and the pinned corpora |
20
21
  | `divergences.json` | Declared disagreements with SQLFluff |
21
- | `upstream/sqlfluff/` | SQLFluff's copied tests (`fixtures/`, and Rerail's own PostgreSQL cases beside them in `fixtures/rerail/`, listed as `RERAIL_CASES` in `generate.py`), its recordings (`fixtures.expected.json`, `fixtures.cases.json`, `corpus-<name>.expected.json`) and the recorder (`generate.py`, sharing `fixtures/sql/common.py`) |
22
+ | `upstream/sqlfluff/` | SQLFluff's copied tests (`fixtures/`, and Rerail's own PostgreSQL cases beside them in `fixtures/rerail/`, listed as `RERAIL_CASES` in `generate.py`), its recordings (`fixtures.expected.json`, `fixtures.cases.json`, `corpus-<name>.expected.json`) and the recorder (`generate.py`, sharing `fixtures/sql/common.py`); the port readiness gates' `gates.yaml`, `recording.lock` and `goldens.tsv`. The tests, Rerail's cases and the recordings are pack test data, not in git: one archive in S3, which `test-data.lock` names and `npm run fixtures:pull` fetches |
22
23
  | `licenses/sqlfluff/` | SQLFluff's licence and `UPSTREAM.md`, listing every copied file |
23
24
 
24
- ## Rules that would start off
25
+ ## Rules that start off
25
26
 
26
- PG01, PG02 and AM02 depend on SQLFluff's dialect, and Rerail reads every `.sql` file in one dialect, so each should
27
- start off (`"on": false` in `pack.json`) if it ever ships, to be turned on per repository or checkout. PG01 and PG02
28
- are PostgreSQL-only: on a MySQL or SQLite file they would advise `CONCURRENTLY` or `NOT VALID`, which those databases
29
- lack. AM02 is the reverse: SQLFluff skips it for PostgreSQL, so on a PostgreSQL file a bare `UNION` would be a false
30
- positive; it would be turned on for MySQL or ANSI SQL. The other 19 would start on. The scores below cover all 22.
27
+ PG01 and PG02 ship off (`"on": false` in `pack.json`), to be turned on per repository or checkout: SQLFluff's default
28
+ configuration leaves them off (`force_enable = False`, the port readiness `upstream-status`), and they are
29
+ PostgreSQL-only, while Rerail reads every `.sql` file in one dialect: on a MySQL or SQLite file they would advise
30
+ `CONCURRENTLY` or `NOT VALID`, which those databases lack. AM02, a candidate, is the reverse: SQLFluff skips it for
31
+ PostgreSQL, so on a PostgreSQL file a bare `UNION` would be a false positive; it should start off if it ever ships, to
32
+ be turned on for MySQL or ANSI SQL. The other 17 shipped rules start on. The scores below cover all 22.
31
33
 
32
34
  ## How the rules read SQL
33
35
 
@@ -36,42 +38,42 @@ to lower case, a quoted one is exact, and a whole-row reference (`to_json(t)`) u
36
38
  are written for ANSI, PostgreSQL, MySQL and SQLite (the four dialects copied). The recorder lints each fixture with its
37
39
  own dialect and each ANSI one again with `--dialect postgres` (`fixtures.cases.json`, `postgresDialect.sameFindings`):
38
40
  167 ANSI cases find the same either way and 26 do not. Where a port follows PostgreSQL and the fixture's dialect reads
39
- otherwise, the case is a `not-comparable` divergence, its evidence the PostgreSQL reading. Of the 59 divergences, 57
41
+ otherwise, the case is a `not-comparable` divergence, its evidence the PostgreSQL reading. Of the 59 divergences, 58
40
42
  are `not-comparable` (dialect readings, MySQL-only and SQLite-only syntax, files PostgreSQL rejects, and SQLFluff's
41
- dialect gates for PG01 and AM02) and 2 are `rerail-unknown` (grammar gaps in RF01: a redundantly bracketed join and
42
- `CREATE POLICY`).
43
+ dialect gates for PG01 and AM02) and 1 is `rerail-unknown` (a grammar gap in RF01: a redundantly bracketed join).
43
44
 
44
45
  ## Scores
45
46
 
46
- TP/FP/FN of each candidate against SQLFluff 4.4.0, from `node --import tsx conformance/languages/cli.ts --pack sql`; `div.` counts the
47
- findings a declared divergence explains. On the recorded fixtures and the four pinned corpora, every candidate has no
48
- false positive and no false negative on the fixtures outside its declared divergences; that says nothing about other
49
- SQL, and a port's reading is PostgreSQL's wherever the dialects differ. Corpus false negatives do not fail the gate.
50
-
51
- | Port | SQLFluff rule | Fixtures | postgres | mattermost | anki | application-services | Skips files with syntax errors |
52
- |---|---|---|---|---|---|---|---|
53
- | `sqlfluff-al04-aliasing-unique-table` | AL04 | 9/0/0 | 0/0/3 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
54
- | `sqlfluff-al05-aliasing-unused` | AL05 | 10/0/0 (6 div.) | 4/0/57 | 0/0/0 | 1/0/0 | 0/0/0 | yes |
55
- | `sqlfluff-al08-aliasing-unique-column` | AL08 | 14/0/0 (1 div.) | 1/0/52 | 0/0/0 | 0/0/0 | 0/0/1 | yes |
56
- | `sqlfluff-al09-aliasing-self-alias-column` | AL09 | 18/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
57
- | `sqlfluff-am01-ambiguous-distinct` | AM01 | 1/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
58
- | `sqlfluff-am02-ambiguous-union` | AM02 | 5/0/0 (1 div.) | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
59
- | `sqlfluff-am05-ambiguous-join` | AM05 | 14/0/0 | 26/0/8 | 4/0/1 | 2/0/0 | 0/0/2 | no |
60
- | `sqlfluff-am09-ambiguous-order-by-limit` | AM09 | 3/0/0 | 1/0/2 | 0/0/0 | 2/0/0 | 0/0/0 | yes |
61
- | `sqlfluff-cv02-convention-coalesce` | CV02 | 2/0/0 | 0/0/0 | 3/0/0 | 0/0/0 | 0/0/1 | no |
62
- | `sqlfluff-cv04-convention-count-rows` | CV04 | 3/0/0 | 0/0/0 | 0/0/0 | 1/0/0 | 0/0/0 | no |
63
- | `sqlfluff-cv05-convention-is-null` | CV05 | 7/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
64
- | `sqlfluff-cv08-convention-left-join` | CV08 | 9/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
65
- | `sqlfluff-pg01-postgres-excessive-locks` | PG01 | 10/0/0 (1 div.) | 55/0/56 | 148/0/118 | 0/0/0 (3 div.) | 0/0/0 | yes |
66
- | `sqlfluff-pg02-postgres-not-valid-foreign-key` | PG02 | 1/0/0 | 0/0/1 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
67
- | `sqlfluff-rf01-references-from` | RF01 | 26/0/0 (6 div.) | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/7 | yes |
68
- | `sqlfluff-rf04-references-keywords` | RF04 | 4/0/0 (3 div.) | 28/0/78 | 55/0/87 | 0/0/1 (1 div.) | 0/0/0 | yes |
69
- | `sqlfluff-rf05-references-special-chars` | RF05 | 10/0/0 (4 div.) | 0/0/9 | 0/0/0 | 10/0/0 | 0/0/0 | yes |
70
- | `sqlfluff-rf06-references-quoting` | RF06 | 19/0/0 (47 div.) | 23/0/13 | 4/0/1 | 0/0/0 | 0/0/0 | yes |
71
- | `sqlfluff-st01-structure-else-null` | ST01 | 4/0/0 | 0/0/0 | 0/0/0 | 1/0/1 | 0/0/0 | no |
72
- | `sqlfluff-st02-structure-simple-case` | ST02 | 15/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
73
- | `sqlfluff-st08-structure-distinct` | ST08 | 7/0/0 | 0/0/1 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
74
- | `sqlfluff-st10-structure-constant-expression` | ST10 | 10/0/0 | 4/0/1 | 0/0/0 | 0/0/0 | 0/0/0 | no |
47
+ TP/FP/FN of each port against SQLFluff 4.4.0, from `node --import tsx conformance/languages/cli.ts --pack sql`; `div.` counts the
48
+ findings a declared divergence explains. Every port has no false positive and no false negative on the fixtures outside
49
+ its declared divergences, and no shipped rule has a false positive on the four pinned corpora (AM02, a candidate, has
50
+ one on postgres); that says nothing about other SQL, and a port's reading is PostgreSQL's wherever the dialects differ.
51
+ Corpus false negatives do not fail the gate.
52
+
53
+ | Port | SQLFluff rule | Status | Fixtures | postgres | mattermost | anki | application-services | Skips files with syntax errors |
54
+ |---|---|---|---|---|---|---|---|---|
55
+ | `sqlfluff-al04-aliasing-unique-table` | AL04 | shipped | 9/0/0 | 3/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
56
+ | `sqlfluff-al05-aliasing-unused` | AL05 | candidate | 9/0/0 (7 div.) | 61/0/0 | 0/0/0 | 1/0/0 | 0/0/0 | yes |
57
+ | `sqlfluff-al08-aliasing-unique-column` | AL08 | shipped | 14/0/0 (1 div.) | 53/0/0 | 0/0/0 | 0/0/0 | 0/0/1 | yes |
58
+ | `sqlfluff-al09-aliasing-self-alias-column` | AL09 | shipped | 18/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
59
+ | `sqlfluff-am01-ambiguous-distinct` | AM01 | shipped | 1/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
60
+ | `sqlfluff-am02-ambiguous-union` | AM02 | candidate | 5/0/0 (1 div.) | 0/1/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
61
+ | `sqlfluff-am05-ambiguous-join` | AM05 | shipped | 14/0/0 | 34/0/0 | 5/0/0 | 2/0/0 | 0/0/2 | no |
62
+ | `sqlfluff-am09-ambiguous-order-by-limit` | AM09 | shipped | 3/0/0 | 3/0/0 | 0/0/0 | 2/0/0 | 0/0/0 | yes |
63
+ | `sqlfluff-cv02-convention-coalesce` | CV02 | shipped | 2/0/0 | 0/0/0 | 3/0/0 | 0/0/0 | 0/0/1 | no |
64
+ | `sqlfluff-cv04-convention-count-rows` | CV04 | shipped | 3/0/0 | 0/0/0 | 0/0/0 | 1/0/0 | 0/0/0 | no |
65
+ | `sqlfluff-cv05-convention-is-null` | CV05 | shipped | 7/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
66
+ | `sqlfluff-cv08-convention-left-join` | CV08 | shipped | 9/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
67
+ | `sqlfluff-pg01-postgres-excessive-locks` | PG01 | shipped, off | 10/0/0 (1 div.) | 111/0/0 | 266/0/0 | 0/0/0 (3 div.) | 0/0/0 | yes |
68
+ | `sqlfluff-pg02-postgres-not-valid-foreign-key` | PG02 | shipped, off | 1/0/0 | 1/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
69
+ | `sqlfluff-rf01-references-from` | RF01 | candidate | 27/0/0 (5 div.) | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/7 | yes |
70
+ | `sqlfluff-rf04-references-keywords` | RF04 | shipped | 4/0/0 (3 div.) | 106/0/0 | 79/0/63 | 0/0/1 (1 div.) | 0/0/0 | yes |
71
+ | `sqlfluff-rf05-references-special-chars` | RF05 | shipped | 10/0/0 (4 div.) | 9/0/0 | 0/0/0 | 10/0/0 | 0/0/0 | yes |
72
+ | `sqlfluff-rf06-references-quoting` | RF06 | shipped | 19/0/0 (47 div.) | 36/0/0 | 4/0/1 | 0/0/0 | 0/0/0 | yes |
73
+ | `sqlfluff-st01-structure-else-null` | ST01 | shipped | 4/0/0 | 0/0/0 | 0/0/0 | 2/0/0 | 0/0/0 | no |
74
+ | `sqlfluff-st02-structure-simple-case` | ST02 | shipped | 15/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
75
+ | `sqlfluff-st08-structure-distinct` | ST08 | shipped | 7/0/0 | 1/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | yes |
76
+ | `sqlfluff-st10-structure-constant-expression` | ST10 | shipped | 10/0/0 | 5/0/0 | 0/0/0 | 0/0/0 | 0/0/0 | no |
75
77
 
76
78
  RF06's 47 fixture divergences are ANSI and MySQL case folding, each line checked with `sqlfluff lint --dialect
77
79
  postgres`.
@@ -84,23 +86,44 @@ others run around the errors (`source-partial`). Per source:
84
86
 
85
87
  | Source | Files | Left out (SQLFluff could not analyse them) | Scored | With a syntax error, skipped | Parsed cleanly |
86
88
  |---|---|---|---|---|---|
87
- | fixtures | 283 | 0 | 283 | 13 | 270 (95%) |
88
- | postgres | 629 | 342 | 287 | 202 | 85 (30%) |
89
- | mattermost | 560 | 0 | 560 | 262 | 298 (53%) |
90
- | anki | 112 | 15 | 97 | 33 | 64 (66%) |
89
+ | fixtures | 283 | 0 | 283 | 8 | 275 (97%) |
90
+ | postgres | 629 | 342 | 287 | 0 | 287 (100%) |
91
+ | mattermost | 560 | 0 | 560 | 191 | 369 (66%) |
92
+ | anki | 112 | 15 | 97 | 29 | 68 (70%) |
91
93
  | application-services | 21 | 15 | 6 | 4 | 2 (33%) |
92
94
 
93
- The corpus false negatives are mostly these files: of the 356 the report lists (at most 50 per port and corpus), 347
95
+ The corpus false negatives are mostly these files: of the 63 the report lists (at most 50 per port and corpus), 59
94
96
  are in a file with a syntax error. `--rule <id>` prints each syntax-error file at its first error (`SYNTAX
95
97
  path:line:column`).
96
98
 
99
+ ## Port readiness
100
+
101
+ `sql/sqlfluff` is gated (`upstream/sqlfluff/gates.yaml`). Upstream runs as `dialect: postgres`, `templater: raw` with
102
+ the port's rule configuration on every SQLFluff YAML case and corpus file, because the engine reads every `.sql` file
103
+ as PostgreSQL; a case SQLFluff's postgres dialect cannot read whole, a Jinja case and a case configured otherwise are
104
+ skipped. From `npm run port-readiness -- --pack sql --tool sqlfluff`, 19 ports pass every blocking gate and ship, each
105
+ agreeing with SQLFluff on every golden (`goldens.tsv`), and 3 stay candidates:
106
+
107
+ | Port | Stops at | Why |
108
+ |---|---|---|
109
+ | `sqlfluff-al05-aliasing-unused` | matches-upstream-tests | 6 of its cases differ, each a file the engine cannot read whole and libpg_query rejects (BigQuery, Snowflake and T-SQL syntax); its 27 findings on the rest are all reproduced |
110
+ | `sqlfluff-am02-ambiguous-union` | matches-upstream-tests | SQLFluff skips AM02 for PostgreSQL, so it reports nothing on its tests: the port's 7 findings are extra, it reproduces no upstream finding (`fires`), and 1 golden differs (`functional_deps.sql`, 181:1 extra) |
111
+ | `sqlfluff-rf01-references-from` | matches-upstream-tests | 9 of its cases differ (55 of 70 findings reproduced): 8 the engine cannot read whole (DuckDB, BigQuery `UNNEST ... WITH OFFSET`, Snowflake `SEMANTIC_VIEW`, and the redundantly bracketed join `JOIN ((b JOIN c ON ...))`, which PostgreSQL accepts), and a Trino row reference, missed at 5:47 |
112
+
113
+ The `CREATE POLICY` and `ALTER POLICY` known gaps are gone: the grammar reads both statements, and the scope binds the
114
+ policy's table for the queries in its `USING` and `WITH CHECK`, as SQLFluff's RF01 does on PostgreSQL. PG01 and PG02
115
+ are off in SQLFluff's default configuration (`force_enable = False`), so they ship off.
116
+
97
117
  ## Re-recording and scoring
98
118
 
99
- Re-recording runs offline against the pinned SQLFluff 4.4.0, in the venv that `fixtures/sql/common.py` documents:
119
+ Re-recording is a maintainer deriving the pack's test data from its pins and archiving it
120
+ ([CONTRIBUTING.md](../../CONTRIBUTING.md#pack-test-data)); it is never committed. The recipe
121
+ (`scripts/pack-data/recipes/sql.ts`) runs `upstream/sqlfluff/generate.py`, in `fixtures` mode and then `corpus` mode,
122
+ against the pinned SQLFluff 4.4.0, in the venv that `fixtures/sql/common.py` pins:
100
123
 
101
124
  ```sh
102
- .rerail/tools/sql/venv/bin/python packs/sql/upstream/sqlfluff/generate.py fixtures
103
- .rerail/tools/sql/venv/bin/python packs/sql/upstream/sqlfluff/generate.py corpus
125
+ npm run fixtures:derive -- --pack sql
126
+ npm run fixtures:push -- --pack sql # on your own branch: archive it and rewrite its test-data.lock
104
127
  ```
105
128
 
106
129
  Scoring one rule with every false positive and false negative printed:
@@ -108,3 +131,103 @@ Scoring one rule with every false positive and false negative printed:
108
131
  ```sh
109
132
  node --import tsx conformance/languages/cli.ts --pack sql --rule sqlfluff-al04-aliasing-unique-table --fixtures
110
133
  ```
134
+
135
+ The port readiness recording (`upstream/sqlfluff/recording.lock`) comes from the recorder's own runtime
136
+ (`conformance/recorders/port-readiness/runtimes/sqlfluff-4.4.0`):
137
+
138
+ ```sh
139
+ npm run port-readiness:record -- --pack sql --tool sqlfluff
140
+ npm run port-readiness -- --pack sql --tool sqlfluff
141
+ ```
142
+
143
+ ## Rule details
144
+
145
+ What each rule matches beyond its one-line description: exact matching, edge cases, upstream settings and known divergences.
146
+
147
+ ### `sqlfluff-al04-aliasing-unique-table`
148
+
149
+ Port of SQLFluff 4.4.0 AL04, which reads SELECT statements: report a table relation whose alias (its explicit alias, else its table name) repeats the alias of an earlier relation in the same FROM clause, or of a relation in a subquery of the same SELECT, other than the subquery the relation aliases; a relation that calls one of the postgres dialect's value table functions (unnest, generate_series) has no table alias; names compare as SQLFluff's raw_normalized does, with quotes removed and case kept.
150
+
151
+ ### `sqlfluff-al05-aliasing-unused`
152
+
153
+ Port of SQLFluff 4.4.0 AL05 (aliasing.unused) with default settings. Not reported where the alias is required (a derived table or VALUES list) or where the same table is referenced more than once.
154
+
155
+ ### `sqlfluff-al08-aliasing-unique-column`
156
+
157
+ Port of SQLFluff 4.4.0 AL08. In each SELECT list, reports each later reused explicit alias or column-reference name, case-insensitively, with identifier quote delimiters ignored.
158
+
159
+ ### `sqlfluff-al09-aliasing-self-alias-column`
160
+
161
+ Port of SQLFluff 4.4.0 AL09 (aliasing.self_alias.column). Reports a column reference aliased to its own last name part, either written identically (quotes and case included) or, both unquoted, differing in case only (the "ambiguous self alias" message). Anchored at the select element's start.
162
+
163
+ ### `sqlfluff-am01-ambiguous-distinct`
164
+
165
+ Port of SQLFluff 4.4.0 AM01 (ambiguous.distinct). Implementation note: the grammar puts GROUP BY in the FROM node after the SELECT node.
166
+
167
+ ### `sqlfluff-am02-ambiguous-union`
168
+
169
+ Port of SQLFluff 4.4.0 AM02 (ambiguous.union). Flags a UNION not immediately followed by DISTINCT or ALL. SQLFluff skips AM02 in its postgres dialect (it runs in ANSI, MySQL and other dialects with UNION DISTINCT; not SQLite), so the rule would start off and be turned on for MySQL/ANSI repositories (README already covers the start-off part).
170
+
171
+ ### `sqlfluff-am05-ambiguous-join`
172
+
173
+ Port of SQLFluff 4.4.0 AM05 (ambiguous.join) with default fully_qualify_join_types=inner: reports a join whose first join keyword is bare JOIN, anchored at the JOIN clause start.
174
+
175
+ ### `sqlfluff-am09-ambiguous-order-by-limit`
176
+
177
+ Port of SQLFluff 4.4.0 AM09 (ambiguous.order_by_limit). Anchored at LIMIT. A LIMIT that ends a UNION, INTERSECT or EXCEPT belongs to the set expression, which SQLFluff's AM09 does not read. The grammar parses no OFFSET without LIMIT.
178
+
179
+ ### `sqlfluff-cv02-convention-coalesce`
180
+
181
+ Port of SQLFluff 4.4.0 CV02 (convention.coalesce), default settings. Only unqualified IFNULL/NVL are reported; schema-qualified names are user-defined functions and are excluded.
182
+
183
+ ### `sqlfluff-cv04-convention-count-rows`
184
+
185
+ Port of SQLFluff 4.4.0 CV04 (convention.count_rows) with prefer_count_1 and prefer_count_0 false. An unqualified COUNT whose only argument is the literal 0 or 1 is reported at the function's start; COUNT(column), COUNT(DISTINCT ...) and other expressions are not.
186
+
187
+ ### `sqlfluff-cv05-convention-is-null`
188
+
189
+ Port of SQLFluff 4.4.0 CV05 (convention.is_null). Only =, != and <> whose right operand is the bare NULL literal (not parenthesised), anchored at the operator. A SET clause's assignment and an exclusion constraint's operator are not comparisons in the grammar, as SQLFluff skips them.
190
+
191
+ ### `sqlfluff-cv08-convention-left-join`
192
+
193
+ Port of SQLFluff 4.4.0 CV08 (convention.left_join). Reports RIGHT JOIN and RIGHT OUTER JOIN at the start of the join clause.
194
+
195
+ ### `sqlfluff-pg01-postgres-excessive-locks`
196
+
197
+ Port of SQLFluff 4.4.0 PG01 (postgres.excessive_locks), force_enable=true. CREATE INDEX (except UNIQUE), DROP INDEX, REINDEX and REFRESH MATERIALIZED VIEW must use CONCURRENTLY; each anchored at the statement start. Statements inside a dollar-quoted routine or DO body (a string to SQLFluff) or an error region are not read.
198
+
199
+ ### `sqlfluff-pg02-postgres-not-valid-foreign-key`
200
+
201
+ Port of SQLFluff 4.4.0 PG02 (postgres.not_valid_foreign_key), force_enable=true. ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY must include NOT VALID; anchored at the ALTER TABLE start. Statements inside a dollar-quoted routine or DO body or an error region are not read.
202
+
203
+ ### `sqlfluff-rf01-references-from`
204
+
205
+ Port of SQLFluff 4.4.0 RF01 (references.from), default settings. Flags the table qualifier of a column reference that names no table or alias in the FROM clause of its query or of an enclosing query.
206
+
207
+ ### `sqlfluff-rf04-references-keywords`
208
+
209
+ Port of SQLFluff 4.4.0 RF04 (references.keywords) with its defaults (unquoted_identifiers_policy = aliases, quoted_identifiers_policy = none): report a naked identifier of more than one character that names a table or column alias or a CREATE TABLE column definition and is a keyword. SQLFluff reads the naked identifier against its dialect's unreserved keywords; the engine reads every .sql file as PostgreSQL, so the regex holds exactly SQLFluff's postgres unreserved keywords (dialect_selector('postgres').sets('unreserved_keywords'), 836 words). A column definition is one of a CREATE TABLE column list, with its type, as in SQLFluff's postgres dialect: an ALTER TABLE ... ADD COLUMN name, a typed or partition table's `name WITH OPTIONS`, a foreign table's column and a composite type's attribute are column references or plain words there, and a column definition list after a table function's alias is parameters, so they are skipped.
210
+
211
+ ### `sqlfluff-rf05-references-special-chars`
212
+
213
+ Port of SQLFluff 4.4.0's RF05 (references.special_chars) with its defaults (both identifier policies all, no space or additional characters allowed): report a naked or quoted identifier whose name, without its quotes and underscores, holds a character other than a Unicode letter or digit (a doubled quote included). A name in a SELECT element that has an alias is not read (only the alias is), and neither is a PostgreSQL extension name or a routine's parameter name (a parameter to SQLFluff, not an identifier).
214
+
215
+ ### `sqlfluff-rf06-references-quoting`
216
+
217
+ Port of SQLFluff 4.4.0's RF06 (references.quoting) with its defaults (prefer_quoted_identifiers and prefer_quoted_keywords false, case_sensitive true), under SQLFluff's postgres dialect, the reading the engine gives every .sql file: report a double-quoted identifier that would mean the same unquoted, because its name has no upper-case letter (PostgreSQL folds unquoted names to lower case), matches the postgres dialect's naked-identifier template [\p{L}_][\p{L}\p{N}_$]* and is none of the dialect's reserved words (its anti-template, embedded here). PostgreSQL lexes every double-quoted token as a quoted identifier; the engine reads one as an identifier, or as a literal where its grammar takes a name as a string (a column list, an index or extension name). A routine body (dollar-quoted, a string to SQLFluff) is not read.
218
+
219
+ ### `sqlfluff-st01-structure-else-null`
220
+
221
+ Port of SQLFluff 4.4.0 ST01 (structure.else_null). Reports a CASE whose ELSE is the bare NULL literal, at the CASE start.
222
+
223
+ ### `sqlfluff-st02-structure-simple-case`
224
+
225
+ Port of SQLFluff 4.4.0 ST02 (structure.simple_case). Reports a searched CASE with one WHEN that is boolean (THEN TRUE ELSE FALSE, or the reverse), or whose condition is `column IS NULL` with the column as its ELSE, or `column IS NOT NULL` with the column as its THEN; anchored at the WHEN condition. A simple CASE, several WHENs, a compound condition and IS DISTINCT FROM are not reported.
226
+
227
+ ### `sqlfluff-st08-structure-distinct`
228
+
229
+ Port of SQLFluff 4.4.0 ST08 (structure.distinct). Three cases: in a SELECT DISTINCT whose first selected expression is parenthesized alone, reports the parentheses; where the parentheses start an arithmetic expression right after DISTINCT with no space, reports DISTINCT; and reports DISTINCT written as a function, DISTINCT(x), as an aggregate's lone argument (not around a subquery).
230
+
231
+ ### `sqlfluff-st10-structure-constant-expression`
232
+
233
+ Port of SQLFluff 4.4.0's ST10 (structure.constant_expression): report =, != or <> whose operands are the same non-literal written identically, or two literals other than the allowed 1 = 1 and 1 = 0 (compared without a string's quotes, so '1' = 1 is allowed too), anchored at the operator. SQLFluff's operands are the pieces adjacent to the operator, as its postgres dialect reads them: a positional parameter ($1) is a literal; a date, time, timestamp or interval literal is one operand and no literal; any other typed string (name 'x') is a type then a string, so on the left its string is the operand and on the right the type, which matches nothing; a right operand followed by COLLATE is the collated expression, a left one is the collation name, which matches nothing; an operand that is itself an arithmetic, bitwise or other binary expression is not adjacent, so such comparisons are skipped.