Skip to content

Commit

Permalink
Add support for sqlx NamedStmt (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
Thiht authored Sep 4, 2023
1 parent 1116461 commit f6bc14a
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 23 deletions.
6 changes: 3 additions & 3 deletions pgx_examples_results.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# github.com/ryanrolds/sqlclosecheck/testdata/pgx_examples
testdata/pgx_examples/missing_close.go:8:26: Rows/Stmt was not closed
testdata/pgx_examples/missing_close.go:17:28: Rows/Stmt was not closed
testdata/pgx_examples/missing_close.go:26:28: Rows/Stmt was not closed
testdata/pgx_examples/missing_close.go:8:26: Rows/Stmt/NamedStmt was not closed
testdata/pgx_examples/missing_close.go:17:28: Rows/Stmt/NamedStmt was not closed
testdata/pgx_examples/missing_close.go:26:28: Rows/Stmt/NamedStmt was not closed
18 changes: 12 additions & 6 deletions pkg/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import (
)

const (
rowsName = "Rows"
stmtName = "Stmt"
closeMethod = "Close"
rowsName = "Rows"
stmtName = "Stmt"
namedStmtName = "NamedStmt"
closeMethod = "Close"
)

type action uint8
Expand Down Expand Up @@ -39,7 +40,7 @@ var (
func NewAnalyzer() *analysis.Analyzer {
return &analysis.Analyzer{
Name: "sqlclosecheck",
Doc: "Checks that sql.Rows, sql.Stmt, pgx.Query are closed.",
Doc: "Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed.",
Run: run,
Requires: []*analysis.Analyzer{
buildssa.Analyzer,
Expand Down Expand Up @@ -76,7 +77,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
refs := (*targetValue.value).Referrers()
isClosed := checkClosed(refs, targetTypes)
if !isClosed {
pass.Reportf((targetValue.instr).Pos(), "Rows/Stmt was not closed")
pass.Reportf((targetValue.instr).Pos(), "Rows/Stmt/NamedStmt was not closed")
}

checkDeferred(pass, refs, targetTypes, false)
Expand Down Expand Up @@ -112,6 +113,11 @@ func getTargetTypes(pssa *buildssa.SSA, targetPackages []string) []any {
if stmtType != nil {
targets = append(targets, stmtType)
}

namedStmtType := getTypePointerFromName(pkg, namedStmtName)
if namedStmtType != nil {
targets = append(targets, namedStmtType)
}
}

return targets
Expand All @@ -120,7 +126,7 @@ func getTargetTypes(pssa *buildssa.SSA, targetPackages []string) []any {
func getTypePointerFromName(pkg *ssa.Package, name string) *types.Pointer {
pkgType := pkg.Type(name)
if pkgType == nil {
// this package does not use Rows/Stmt
// this package does not use Rows/Stmt/NamedStmt
return nil
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/analyzer/testdata/pgx/missing_close.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

func missingCloseTx() {
rows, err := pgxTx.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt was not closed"
rows, err := pgxTx.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand All @@ -14,7 +14,7 @@ func missingCloseTx() {
}

func missingCloseConn() {
rows, err := pgxConn.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt was not closed"
rows, err := pgxConn.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand All @@ -23,7 +23,7 @@ func missingCloseConn() {
}

func missingClosePgxPool() {
rows, err := pgxPool.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt was not closed"
rows, err := pgxPool.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/analyzer/testdata/rows/missing_close.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func missingClose() {
age := 27
rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age) // want "Rows/Stmt was not closed"
rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age) // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/analyzer/testdata/stmt/missing_close.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func missingClose() {
// In normal use, create one Stmt when your process starts.
stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?") // want "Rows/Stmt was not closed"
stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand Down
6 changes: 3 additions & 3 deletions testdata/pgx_examples/expected_results.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# github.com/ryanrolds/sqlclosecheck/testdata/pgx_examples
testdata/pgx_examples/missing_close.go:8:26: Rows/Stmt was not closed
testdata/pgx_examples/missing_close.go:17:28: Rows/Stmt was not closed
testdata/pgx_examples/missing_close.go:26:28: Rows/Stmt was not closed
testdata/pgx_examples/missing_close.go:8:26: Rows/Stmt/NamedStmt was not closed
testdata/pgx_examples/missing_close.go:17:28: Rows/Stmt/NamedStmt was not closed
testdata/pgx_examples/missing_close.go:26:28: Rows/Stmt/NamedStmt was not closed
6 changes: 3 additions & 3 deletions testdata/pgx_examples/missing_close.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

func missingCloseTx() {
rows, err := pgxTx.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt was not closed"
rows, err := pgxTx.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand All @@ -14,7 +14,7 @@ func missingCloseTx() {
}

func missingCloseConn() {
rows, err := pgxConn.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt was not closed"
rows, err := pgxConn.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand All @@ -23,7 +23,7 @@ func missingCloseConn() {
}

func missingClosePgxPool() {
rows, err := pgxPool.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt was not closed"
rows, err := pgxPool.Query(ctx, "SELECT username FROM users") // want "Rows/Stmt/NamedStmt was not closed"
if err != nil {
log.Fatal(err)
}
Expand Down
7 changes: 4 additions & 3 deletions testdata/sqlx_examples/expected_results.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# github.com/ryanrolds/sqlclosecheck/testdata/sqlx_examples
testdata/sqlx_examples/failure_generics.go:6:21: Rows/Stmt was not closed
testdata/sqlx_examples/failure_generics.go:13:21: Rows/Stmt was not closed
testdata/sqlx_examples/missing_close.go:10:24: Rows/Stmt was not closed
testdata/sqlx_examples/failure_generics.go:6:21: Rows/Stmt/NamedStmt was not closed
testdata/sqlx_examples/failure_generics.go:13:21: Rows/Stmt/NamedStmt was not closed
testdata/sqlx_examples/missing_close.go:10:24: Rows/Stmt/NamedStmt was not closed
testdata/sqlx_examples/missing_close_named_stmt.go:8:30: Rows/Stmt/NamedStmt was not closed
testdata/sqlx_examples/non_defer_close.go:30:12: Close should use defer
16 changes: 16 additions & 0 deletions testdata/sqlx_examples/missing_close_named_stmt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package sqlx_examples

import (
"log"
)

func missingCloseNamedStmt() {
stmt, err := db.PrepareNamed("SELECT * FROM users WHERE id = :id")
if err != nil {
log.Fatal(err)
}

// defer stmt.Close()

_ = stmt // No need to use stmt
}

0 comments on commit f6bc14a

Please sign in to comment.