@@ -11,6 +11,7 @@ import (
11
11
"os"
12
12
"path/filepath"
13
13
"runtime/trace"
14
+ "slices"
14
15
"strings"
15
16
"time"
16
17
@@ -538,11 +539,23 @@ func (c *checker) checkSQL(ctx context.Context, s config.SQL) error {
538
539
req := codeGenRequest (result , combo )
539
540
cfg := vetConfig (req )
540
541
for i , query := range req .Queries {
541
- if result .Queries [i ].Metadata .Flags [QueryFlagSqlcVetDisable ] {
542
- if debug .Active {
543
- log .Printf ("Skipping vet rules for query: %s\n " , query .Name )
542
+ md := result .Queries [i ].Metadata
543
+ if md .Flags [QueryFlagSqlcVetDisable ] {
544
+ // If the vet disable flag is specified without any rules listed, all rules are ignored.
545
+ if len (md .RuleSkiplist ) == 0 {
546
+ if debug .Active {
547
+ log .Printf ("Skipping all vet rules for query: %s\n " , query .Name )
548
+ }
549
+ continue
550
+ }
551
+
552
+ // Rules which are listed to be disabled but not declared in the config file are rejected.
553
+ for r := range md .RuleSkiplist {
554
+ if ! slices .Contains (s .Rules , r ) {
555
+ fmt .Fprintf (c .Stderr , "%s: %s: rule-check error: rule %q does not exist in the config file\n " , query .Filename , query .Name , r )
556
+ errored = true
557
+ }
544
558
}
545
- continue
546
559
}
547
560
548
561
evalMap := map [string ]any {
@@ -551,74 +564,81 @@ func (c *checker) checkSQL(ctx context.Context, s config.SQL) error {
551
564
}
552
565
553
566
for _ , name := range s .Rules {
554
- rule , ok := c .Rules [name ]
555
- if ! ok {
556
- return fmt .Errorf ("type-check error: a rule with the name '%s' does not exist" , name )
557
- }
558
-
559
- if rule .NeedsPrepare {
560
- if prep == nil {
561
- fmt .Fprintf (c .Stderr , "%s: %s: %s: error preparing query: database connection required\n " , query .Filename , query .Name , name )
562
- errored = true
563
- continue
567
+ if _ , skip := md .RuleSkiplist [name ]; skip {
568
+ if debug .Active {
569
+ log .Printf ("Skipping vet rule %q for query: %s\n " , name , query .Name )
564
570
}
565
- prepName := fmt .Sprintf ("sqlc_vet_%d_%d" , time .Now ().Unix (), i )
566
- if err := prep .Prepare (ctx , prepName , query .Text ); err != nil {
567
- fmt .Fprintf (c .Stderr , "%s: %s: %s: error preparing query: %s\n " , query .Filename , query .Name , name , err )
568
- errored = true
569
- continue
571
+ } else {
572
+ rule , ok := c .Rules [name ]
573
+ if ! ok {
574
+ return fmt .Errorf ("type-check error: a rule with the name '%s' does not exist" , name )
570
575
}
571
- }
572
576
573
- // short-circuit for "sqlc/db-prepare" rule which doesn't have a CEL program
574
- if rule .Program == nil {
575
- continue
576
- }
577
-
578
- // Get explain output for this query if we need it
579
- _ , pgsqlOK := evalMap ["postgresql" ]
580
- _ , mysqlOK := evalMap ["mysql" ]
581
- if rule .NeedsExplain && ! (pgsqlOK || mysqlOK ) {
582
- if expl == nil {
583
- fmt .Fprintf (c .Stderr , "%s: %s: %s: error explaining query: database connection required\n " , query .Filename , query .Name , name )
584
- errored = true
585
- continue
577
+ if rule .NeedsPrepare {
578
+ if prep == nil {
579
+ fmt .Fprintf (c .Stderr , "%s: %s: %s: error preparing query: database connection required\n " , query .Filename , query .Name , name )
580
+ errored = true
581
+ continue
582
+ }
583
+ prepName := fmt .Sprintf ("sqlc_vet_%d_%d" , time .Now ().Unix (), i )
584
+ if err := prep .Prepare (ctx , prepName , query .Text ); err != nil {
585
+ fmt .Fprintf (c .Stderr , "%s: %s: %s: error preparing query: %s\n " , query .Filename , query .Name , name , err )
586
+ errored = true
587
+ continue
588
+ }
586
589
}
587
- engineOutput , err := expl .Explain (ctx , query .Text , query .Params ... )
588
- if err != nil {
589
- fmt .Fprintf (c .Stderr , "%s: %s: %s: error explaining query: %s\n " , query .Filename , query .Name , name , err )
590
- errored = true
590
+
591
+ // short-circuit for "sqlc/db-prepare" rule which doesn't have a CEL program
592
+ if rule .Program == nil {
591
593
continue
592
594
}
593
595
594
- evalMap ["postgresql" ] = engineOutput .PostgreSQL
595
- evalMap ["mysql" ] = engineOutput .MySQL
596
- }
596
+ // Get explain output for this query if we need it
597
+ _ , pgsqlOK := evalMap ["postgresql" ]
598
+ _ , mysqlOK := evalMap ["mysql" ]
599
+ if rule .NeedsExplain && ! (pgsqlOK || mysqlOK ) {
600
+ if expl == nil {
601
+ fmt .Fprintf (c .Stderr , "%s: %s: %s: error explaining query: database connection required\n " , query .Filename , query .Name , name )
602
+ errored = true
603
+ continue
604
+ }
605
+ engineOutput , err := expl .Explain (ctx , query .Text , query .Params ... )
606
+ if err != nil {
607
+ fmt .Fprintf (c .Stderr , "%s: %s: %s: error explaining query: %s\n " , query .Filename , query .Name , name , err )
608
+ errored = true
609
+ continue
610
+ }
611
+
612
+ evalMap ["postgresql" ] = engineOutput .PostgreSQL
613
+ evalMap ["mysql" ] = engineOutput .MySQL
614
+ }
597
615
598
- if debug .Debug .DumpVetEnv {
599
- fmt .Printf ("vars for rule '%s' evaluating against query '%s':\n " , name , query .Name )
600
- debug .DumpAsJSON (evalMap )
601
- }
616
+ if debug .Debug .DumpVetEnv {
617
+ fmt .Printf ("vars for rule '%s' evaluating against query '%s':\n " , name , query .Name )
618
+ debug .DumpAsJSON (evalMap )
619
+ }
602
620
603
- out , _ , err := (* rule .Program ).Eval (evalMap )
604
- if err != nil {
605
- return err
606
- }
607
- tripped , ok := out .Value ().(bool )
608
- if ! ok {
609
- return fmt .Errorf ("expression returned non-bool value: %v" , out .Value ())
610
- }
611
- if tripped {
612
- // TODO: Get line numbers in the output
613
- if rule .Message == "" {
614
- fmt .Fprintf (c .Stderr , "%s: %s: %s\n " , query .Filename , query .Name , name )
615
- } else {
616
- fmt .Fprintf (c .Stderr , "%s: %s: %s: %s\n " , query .Filename , query .Name , name , rule .Message )
621
+ out , _ , err := (* rule .Program ).Eval (evalMap )
622
+ if err != nil {
623
+ return err
624
+ }
625
+ tripped , ok := out .Value ().(bool )
626
+ if ! ok {
627
+ return fmt .Errorf ("expression returned non-bool value: %v" , out .Value ())
628
+ }
629
+ if tripped {
630
+ // TODO: Get line numbers in the output
631
+ if rule .Message == "" {
632
+ fmt .Fprintf (c .Stderr , "%s: %s: %s\n " , query .Filename , query .Name , name )
633
+ } else {
634
+ fmt .Fprintf (c .Stderr , "%s: %s: %s: %s\n " , query .Filename , query .Name , name , rule .Message )
635
+ }
636
+ errored = true
617
637
}
618
- errored = true
619
638
}
620
639
}
621
640
}
641
+
622
642
if errored {
623
643
return ErrFailedChecks
624
644
}
0 commit comments