Analyzer: helps uncover bugs by reporting a diagnostic for mistakes of *sql.Rows usage.

sqlrows

CircleCI

sqlrows is a static code analyzer which helps uncover bugs by reporting a diagnostic for mistakes of sql.Rows usage.

Install

You can get sqlrows by go get command.

$ go get -u github.com/gostaticanalysis/sqlrows

QuickStart

sqlrows run with go vet as below when Go is 1.12 and higher.

$ go vet -vettool=$(which sqlrows) github.com/you/sample_api/...

When Go is lower than 1.12, just run sqlrows command with the package name (import path).

But it cannot accept some options such as --tags.

$ sqlrows github.com/you/sample_api/...

Analyzer

sqlrows checks a common mistake when using *sql.Rows.

At first, you must call rows.Close() in a defer function. A connection will not be reused if you unexpectedly failed to scan records and forgot to close *sql.Rows.

rows, err := db.QueryContext(ctx, "SELECT * FROM users")
if err != nil {
    return nil, err
}

for rows.Next() {
	err = rows.Scan(...)
	if err != nil {
		return nil, err // NG: this return will not release a connection.
	}
}

And, if you defer a function call to close the *sql.Rows before checking the error that determines whether the return is valid, it will mean you dually call rows.Close().

rows, err := db.QueryContext(ctx, "SELECT * FROM users")
defer rows.Close() // NG: using rows before checking for errors
if err != nil {
    return nil, err
}

It may cause panic and nil-pointer reference but it won't clearly teach you that is due to them.

Owner
GoStaticAnalysis
Static Analysis Tools for Go
GoStaticAnalysis
Comments
  • False positives and false negatives

    False positives and false negatives

    I believe the program does not function like it should. It only works if I put rows.Close directly under the line of the query (which is not good). If I make that a defer rows.Close() I get: ./main.go:16:8: using rows before checking for errors which you should expect

            rows, err := readDB.Query("SELECT 1")
            if err != nil {
                    panic(err)
            }
            defer rows.Close()
    

    $ go vet -vettool=$(which sqlrows) ./... #./main.go:15:27: rows.Close must be called

    Source code

    package main
      
    import (
            "database/sql"
            _ "github.com/go-sql-driver/mysql"
    )
    
    func main(){
            
            readDB, err := sql.Open("mysql", "root:root@tcp(localhost:3306)/mysql?parseTime=true&charset=utf8mb4")
            if err != nil {
                    panic(err.Error()) 
            }       
            
            rows, err := readDB.Query("SELECT 1")
            // rows.Close() // no warnings, which is incorrect
            // defer rows.Close() // gives ./main.go:16:8: using rows before checking for errors
            if err != nil {
                    panic(err)
            }
            defer rows.Close() // correct but does not get noticed
    
    }
    
  • prevent panic when refs is nil

    prevent panic when refs is nil

    This PR prevents a panic when *refs is nil. I've no idea why it's nil. Sometimes it seems to get confused when the rows, err := assignment, error checking and the usage of rows.Next are far apart or somehow in a different block. Will check if I can improve the check some other day. At least this fix prevents from the whole tool crashing and not have any output at all.

    Issue: #9

  • panic: *ssa.Phi during rows declaration without assignment

    panic: *ssa.Phi during rows declaration without assignment

    sqlrows panics when parsing the following code:

    var rows *sql.Rows
    if foo {
        rows, err = queryFoo()
    } else {
        rows, err = queryBar()
    }
    if err != nil { return err }
    defer rows.Close()
    

    After digging in, it seems this is because var rows *sql.Rows comes in as an *ssa.Phi rather than an *ssa.Extract.

  • panic: *ssa.UnOp during rows.Close()

    panic: *ssa.UnOp during rows.Close()

    The following code seems to cause sqlrows to panic:

    rows, err := db.Query(a, b, c)
    if err != nil {
        return err
    }
    func() {
        defer rows.Close()
    
        // read from rows...
    }()
    

    After digging in some, it seems that the deferred rows.Close() call inside of the closure is dereferencing the *sql.Rows value, because it comes out as an *ssa.UnOp instead of an *ssa.Extract.

  • Add ability to check closing of transactions

    Add ability to check closing of transactions

    Hi, thanks for creating this. I would love to use this tool if this supports checking transactions too. Usually, rows.Close() is something that is not missed. But I miss closing transactions often.

    I would want to check that transactions are always either committed or rolled back before the function returns.

    Something like

    tx, err := db.Begin()
    if err != nil {
    	return err
    }
    err = doSomething()
    if err != nil {
    	tx.Rollback()
    	return err
    }
    return nil // error !! We are not doing tx.Commit() before returning.
    

    Will it be possible to add something like this ? Thanks.

💥 A lightweight DSL & ORM which helps you to write SQL in Go.
💥 A lightweight DSL & ORM which helps you to write SQL in Go.

sqlingo is a SQL DSL (a.k.a. SQL Builder or ORM) library in Go. It generates code from the database and lets you write SQL queries in an elegant way.

Jan 2, 2023
Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server

About xo xo is a command-line tool to generate Go code based on a database schema or a custom query. xo works by using database metadata and SQL intro

Jan 8, 2023
Go fearless SQL. Sqlvet performs static analysis on raw SQL queries in your Go code base.

Sqlvet Sqlvet performs static analysis on raw SQL queries in your Go code base to surface potential runtime errors at build time. Feature highlights:

Dec 19, 2022
A Golang library for using SQL.

dotsql A Golang library for using SQL. It is not an ORM, it is not a query builder. Dotsql is a library that helps you keep sql files in one place and

Dec 27, 2022
a golang library for sql builder

Gendry gendry is a Go library that helps you operate database. Based on go-sql-driver/mysql, it provides a series of simple but useful tools to prepar

Dec 26, 2022
Database Abstraction Layer (dbal) for Go. Support SQL builder and get result easily (now only support mysql)

godbal Database Abstraction Layer (dbal) for go (now only support mysql) Motivation I wanted a DBAL that No ORM、No Reflect、Concurrency Save, support S

Nov 17, 2022
SQL builder and query library for golang

__ _ ___ __ _ _ _ / _` |/ _ \ / _` | | | | | (_| | (_) | (_| | |_| | \__, |\___/ \__, |\__,_| |___/ |_| goqu is an expressive SQL bu

Dec 30, 2022
SQL query builder for Go

GoSQL Query builder with some handy utility functions. Documentation For full documentation see the pkg.go.dev or GitBook. Examples // Open database a

Dec 12, 2022
Type safe SQL builder with code generation and automatic query result data mapping
Type safe SQL builder with code generation and automatic query result data mapping

Jet Jet is a complete solution for efficient and high performance database access, consisting of type-safe SQL builder with code generation and automa

Jan 6, 2023
A Go (golang) package that enhances the standard database/sql package by providing powerful data retrieval methods as well as DB-agnostic query building capabilities.

ozzo-dbx Summary Description Requirements Installation Supported Databases Getting Started Connecting to Database Executing Queries Binding Parameters

Dec 31, 2022
Write your SQL queries in raw files with all benefits of modern IDEs, use them in an easy way inside your application with all the profit of compile time constants

About qry is a general purpose library for storing your raw database queries in .sql files with all benefits of modern IDEs, instead of strings and co

Dec 25, 2022
Type safe SQL query builder and struct mapper for Go

sq (Structured Query) ?? ?? sq is a code-generated, type safe query builder and struct mapper for Go. ?? ?? Documentation • Reference • Examples This

Dec 19, 2022
Fast SQL query builder for Go

sqlf A fast SQL query builder for Go. sqlf statement builder provides a way to: Combine SQL statements from fragments of raw SQL and arguments that ma

Dec 23, 2022
Fluent SQL generation for golang

sqrl - fat-free version of squirrel - fluent SQL generator for Go Non thread safe fork of squirrel. The same handy fluffy helper, but with extra lette

Dec 16, 2022
Fluent SQL generation for golang

Squirrel is "complete". Bug fixes will still be merged (slowly). Bug reports are welcome, but I will not necessarily respond to them. If another fork

Jan 6, 2023
GraphJin - Build APIs in 5 minutes with GraphQL. An instant GraphQL to SQL compiler.
GraphJin - Build APIs in 5 minutes with GraphQL. An instant GraphQL to SQL compiler.

GraphJin - Build APIs in 5 minutes GraphJin gives you a high performance GraphQL API without you having to write any code. GraphQL is automagically co

Jan 4, 2023
golang orm and sql builder

gosql gosql is a easy ORM library for Golang. Style: var userList []UserModel err := db.FetchAll(&userList, gosql.Columns("id","name"), gosql.

Dec 22, 2022
LBADD: An experimental, distributed SQL database
LBADD: An experimental, distributed SQL database

LBADD Let's build a distributed database. LBADD is an experimental distributed SQL database, written in Go. The goal of this project is to build a dat

Nov 29, 2022
A Go library for collecting sql.DBStats in Prometheus format

sqlstats A Go library for collecting sql.DBStats and exporting them in Prometheus format. A sql.DB object represents a pool of zero or more underlying

Dec 4, 2022