Skip to content

Commit 8a4d0ad

Browse files
authored
Use ColumnDef position in lint report (#391)
## Summary Fixed the display of lint errors for large DDL statements. Previously, when an error occurred, the output included the entire SQL statement, which could be very lengthy. The update now shows only the relevant line(s) with the issue. ## Problem For large DDL files, any linting errors resulted in the full SQL being displayed in the output, making it difficult to identify the exact problematic lines in lengthy scripts. **Example File**: ```sql create table test_table ( col1 varchar(255), col2 varchar(255), col3 varchar(255) --- other columns ); ``` **Previous Output** Before the change, the output included the full SQL statement, repeated for each warning: ``` .tmp/big-int.sql:1:0: warning: prefer-text-field 1 | create table test_table ( 2 | col1 varchar(255), 3 | col2 varchar(255), 4 | col3 varchar(255) 5 | --- other columns 6 | ); note: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock. help: Use a text field with a check constraint. .tmp/big-int.sql:1:0: warning: prefer-text-field 1 | create table test_table ( 2 | col1 varchar(255), 3 | col2 varchar(255), 4 | col3 varchar(255) 5 | --- other columns 6 | ); note: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock. help: Use a text field with a check constraint. .tmp/big-int.sql:1:0: warning: prefer-text-field 1 | create table test_table ( 2 | col1 varchar(255), 3 | col2 varchar(255), 4 | col3 varchar(255) 5 | --- other columns 6 | ); note: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock. help: Use a text field with a check constraint. find detailed examples and solutions for each rule at https://squawkhq.com/docs/rules Found 3 issues in 1 file (checked 1 source file) ``` **New Output** After the update, only the relevant lines are displayed, providing a cleaner and more focused output: ``` .tmp/big-int.sql:2:0: warning: prefer-text-field 2 | col1 varchar(255), note: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock. help: Use a text field with a check constraint. .tmp/big-int.sql:3:0: warning: prefer-text-field 3 | col2 varchar(255), note: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock. help: Use a text field with a check constraint. .tmp/big-int.sql:4:0: warning: prefer-text-field 4 | col3 varchar(255) note: Changing the size of a varchar field requires an ACCESS EXCLUSIVE lock. help: Use a text field with a check constraint. find detailed examples and solutions for each rule at https://squawkhq.com/docs/rules Found 3 issues in 1 file (checked 1 source file) ``` ## Additional Information This improvement significantly reduces the noise in the output, making it easier to identify issues in large SQL files by only showing the lines related to the warning or error. Let me know if you’d like any changes!
1 parent 3a31b17 commit 8a4d0ad

18 files changed

+150
-149
lines changed

.github/workflows/python.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
uses: PyO3/maturin-action@v1
5050
with:
5151
target: ${{ matrix.platform.target }}
52+
maturin-version: v1.7.1
5253
working-directory: cli
5354
args: --release --out dist ${{ matrix.platform.maturin-options }}
5455
manylinux: ${{ matrix.platform.manylinux }}

cli/src/reporter.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,18 @@ pub fn pretty_violations(
386386
#[allow(clippy::cast_sign_loss)]
387387
let start = start as usize;
388388

389-
#[allow(clippy::cast_sign_loss)]
390-
let len = len.unwrap_or(0) as usize;
391-
392389
// 1-indexed
393-
let lineno = sql[..start].lines().count() + 1;
394-
395-
let content = &sql[start..=start + len];
390+
// remove the leading whitespace on last line
391+
let lineno = sql[..start].trim_end().lines().count() + 1;
392+
393+
let content = if let Some(len) = len {
394+
#[allow(clippy::cast_sign_loss)]
395+
&sql[start..=start + len as usize]
396+
} else {
397+
// Use current line
398+
let tail = sql[start..].find('\n').unwrap_or(sql.len() - start);
399+
&sql[start..=start + tail]
400+
};
396401

397402
// TODO(sbdchd): could remove the leading whitespace and comments to
398403
// get cleaner reports

linter/src/rules/ban_char_field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn ban_char_type(
2222
if field_type_name.string.sval == "bpchar" {
2323
errs.push(RuleViolation::new(
2424
RuleViolationKind::BanCharField,
25-
raw_stmt.into(),
25+
column_def.into(),
2626
None,
2727
));
2828
}

linter/src/rules/prefer_big_int.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn prefer_big_int(
1818
let mut errs = vec![];
1919
for raw_stmt in tree {
2020
for column in columns_create_or_modified(&raw_stmt.stmt) {
21-
check_column_def(&mut errs, raw_stmt, column);
21+
check_column_def(&mut errs, column);
2222
}
2323
}
2424
errs
@@ -37,12 +37,12 @@ lazy_static! {
3737
]);
3838
}
3939

40-
fn check_column_def(errs: &mut Vec<RuleViolation>, raw_stmt: &RawStmt, column_def: &ColumnDef) {
40+
fn check_column_def(errs: &mut Vec<RuleViolation>, column_def: &ColumnDef) {
4141
if let Some(column_name) = column_def.type_name.names.last() {
4242
if SMALL_INT_TYPES.contains(column_name.string.sval.as_str()) {
4343
errs.push(RuleViolation::new(
4444
RuleViolationKind::PreferBigInt,
45-
raw_stmt.into(),
45+
column_def.into(),
4646
None,
4747
));
4848
}
@@ -126,4 +126,15 @@ create table users (
126126
);
127127
assert_debug_snapshot!(res);
128128
}
129+
#[test]
130+
fn test_create_table_many_errors() {
131+
let bad_sql = r"
132+
create table users (
133+
foo integer,
134+
bar serial
135+
);
136+
";
137+
let res = lint_sql(bad_sql);
138+
assert_debug_snapshot!(res);
139+
}
129140
}

linter/src/rules/prefer_bigint_over_int.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn prefer_bigint_over_int(
1818
let mut errs = vec![];
1919
for raw_stmt in tree {
2020
for column in columns_create_or_modified(&raw_stmt.stmt) {
21-
check_column_def(&mut errs, raw_stmt, column);
21+
check_column_def(&mut errs, column);
2222
}
2323
}
2424
errs
@@ -29,12 +29,12 @@ lazy_static! {
2929
HashSet::from(["integer", "int4", "serial", "serial4",]);
3030
}
3131

32-
fn check_column_def(errs: &mut Vec<RuleViolation>, raw_stmt: &RawStmt, column_def: &ColumnDef) {
32+
fn check_column_def(errs: &mut Vec<RuleViolation>, column_def: &ColumnDef) {
3333
if let Some(column_name) = column_def.type_name.names.last() {
3434
if INT_TYPES.contains(column_name.string.sval.as_str()) {
3535
errs.push(RuleViolation::new(
3636
RuleViolationKind::PreferBigintOverInt,
37-
raw_stmt.into(),
37+
column_def.into(),
3838
None,
3939
));
4040
}

linter/src/rules/prefer_bigint_over_smallint.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn prefer_bigint_over_smallint(
1818
let mut errs = vec![];
1919
for raw_stmt in tree {
2020
for column in columns_create_or_modified(&raw_stmt.stmt) {
21-
check_column_def(&mut errs, raw_stmt, column);
21+
check_column_def(&mut errs, column);
2222
}
2323
}
2424
errs
@@ -29,12 +29,12 @@ lazy_static! {
2929
HashSet::from(["smallint", "int2", "smallserial", "serial2",]);
3030
}
3131

32-
fn check_column_def(errs: &mut Vec<RuleViolation>, raw_stmt: &RawStmt, column_def: &ColumnDef) {
32+
fn check_column_def(errs: &mut Vec<RuleViolation>, column_def: &ColumnDef) {
3333
if let Some(column_name) = column_def.type_name.names.last() {
3434
if SMALL_INT_TYPES.contains(column_name.string.sval.as_str()) {
3535
errs.push(RuleViolation::new(
3636
RuleViolationKind::PreferBigintOverSmallint,
37-
raw_stmt.into(),
37+
column_def.into(),
3838
None,
3939
));
4040
}

linter/src/rules/prefer_identity.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn prefer_identity(
1818
let mut errs = vec![];
1919
for raw_stmt in tree {
2020
for column in columns_create_or_modified(&raw_stmt.stmt) {
21-
check_column_def(&mut errs, raw_stmt, column);
21+
check_column_def(&mut errs, column);
2222
}
2323
}
2424
errs
@@ -35,12 +35,12 @@ lazy_static! {
3535
]);
3636
}
3737

38-
fn check_column_def(errs: &mut Vec<RuleViolation>, raw_stmt: &RawStmt, column_def: &ColumnDef) {
38+
fn check_column_def(errs: &mut Vec<RuleViolation>, column_def: &ColumnDef) {
3939
if let Some(column_name) = column_def.type_name.names.last() {
4040
if SERIAL_TYPES.contains(column_name.string.sval.as_str()) {
4141
errs.push(RuleViolation::new(
4242
RuleViolationKind::PreferIdentity,
43-
raw_stmt.into(),
43+
column_def.into(),
4444
None,
4545
));
4646
}

linter/src/rules/prefer_text_field.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ pub fn prefer_text_field(
1919
let mut errs = vec![];
2020
for raw_stmt in tree {
2121
for column in columns_create_or_modified(&raw_stmt.stmt) {
22-
check_column_def(&mut errs, raw_stmt, column);
22+
check_column_def(&mut errs, column);
2323
}
2424
}
2525
errs
2626
}
2727

28-
fn check_column_def(errs: &mut Vec<RuleViolation>, raw_stmt: &RawStmt, column_def: &ColumnDef) {
28+
fn check_column_def(errs: &mut Vec<RuleViolation>, column_def: &ColumnDef) {
2929
let type_name = &column_def.type_name;
3030
for field_type_name in &type_name.names {
3131
if field_type_name.string.sval == "varchar" && !type_name.typmods.is_empty() {
3232
errs.push(RuleViolation::new(
3333
RuleViolationKind::PreferTextField,
34-
raw_stmt.into(),
34+
column_def.into(),
3535
None,
3636
));
3737
}
@@ -68,10 +68,8 @@ COMMIT;
6868
RuleViolation {
6969
kind: PreferTextField,
7070
span: Span {
71-
start: 7,
72-
len: Some(
73-
123,
74-
),
71+
start: 77,
72+
len: None,
7573
},
7674
messages: [
7775
Note(
@@ -104,10 +102,8 @@ COMMIT;
104102
RuleViolation {
105103
kind: PreferTextField,
106104
span: Span {
107-
start: 7,
108-
len: Some(
109-
127,
110-
),
105+
start: 103,
106+
len: None,
111107
},
112108
messages: [
113109
Note(

linter/src/rules/prefer_timestamptz.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ pub fn prefer_timestamptz(
1616
let mut errs = vec![];
1717
for raw_stmt in tree {
1818
for column in columns_create_or_modified(&raw_stmt.stmt) {
19-
check_column_def(&mut errs, raw_stmt, column);
19+
check_column_def(&mut errs, column);
2020
}
2121
}
2222
errs
2323
}
2424

25-
fn check_column_def(errs: &mut Vec<RuleViolation>, raw_stmt: &RawStmt, column_def: &ColumnDef) {
25+
fn check_column_def(errs: &mut Vec<RuleViolation>, column_def: &ColumnDef) {
2626
if let Some(type_name) = column_def.type_name.names.last() {
2727
if type_name.string.sval == "timestamp" {
2828
errs.push(RuleViolation::new(
2929
RuleViolationKind::PreferTimestampTz,
30-
raw_stmt.into(),
30+
column_def.into(),
3131
None,
3232
));
3333
}

linter/src/rules/snapshots/squawk_linter__rules__ban_char_field__test_rules__creating_table_with_char_errors.snap

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ expression: lint_sql(sql)
66
RuleViolation {
77
kind: BanCharField,
88
span: Span {
9-
start: 7,
10-
len: Some(
11-
194,
12-
),
9+
start: 76,
10+
len: None,
1311
},
1412
messages: [
1513
Help(
@@ -20,10 +18,8 @@ expression: lint_sql(sql)
2018
RuleViolation {
2119
kind: BanCharField,
2220
span: Span {
23-
start: 7,
24-
len: Some(
25-
194,
26-
),
21+
start: 108,
22+
len: None,
2723
},
2824
messages: [
2925
Help(
@@ -34,10 +30,8 @@ expression: lint_sql(sql)
3430
RuleViolation {
3531
kind: BanCharField,
3632
span: Span {
37-
start: 7,
38-
len: Some(
39-
194,
40-
),
33+
start: 144,
34+
len: None,
4135
},
4236
messages: [
4337
Help(
@@ -48,10 +42,8 @@ expression: lint_sql(sql)
4842
RuleViolation {
4943
kind: BanCharField,
5044
span: Span {
51-
start: 7,
52-
len: Some(
53-
194,
54-
),
45+
start: 173,
46+
len: None,
5547
},
5648
messages: [
5749
Help(

0 commit comments

Comments
 (0)