github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/test/testdata/sqlclosecheck.go (about)

     1  //golangcitest:args -Esqlclosecheck
     2  package testdata
     3  
     4  import (
     5  	"context"
     6  	"database/sql"
     7  	"log"
     8  	"strings"
     9  )
    10  
    11  var (
    12  	ctx    context.Context
    13  	db     *sql.DB
    14  	age    = 27
    15  	userID = 43
    16  )
    17  
    18  func rowsCorrectDeferBlock() {
    19  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
    20  	if err != nil {
    21  		log.Fatal(err)
    22  	}
    23  
    24  	defer func() {
    25  		err := rows.Close()
    26  		if err != nil {
    27  			log.Print("problem closing rows")
    28  		}
    29  	}()
    30  
    31  	names := make([]string, 0)
    32  	for rows.Next() {
    33  		var name string
    34  		if err := rows.Scan(&name); err != nil {
    35  			log.Fatal(err)
    36  		}
    37  		names = append(names, name)
    38  	}
    39  
    40  	// Check for errors from iterating over rows.
    41  	if err := rows.Err(); err != nil {
    42  		log.Fatal(err)
    43  	}
    44  	log.Printf("%s are %d years old", strings.Join(names, ", "), age)
    45  }
    46  
    47  func rowsCorrectDefer() {
    48  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
    49  	if err != nil {
    50  		log.Fatal(err)
    51  	}
    52  	defer rows.Close()
    53  
    54  	names := make([]string, 0)
    55  	for rows.Next() {
    56  		var name string
    57  		if err := rows.Scan(&name); err != nil {
    58  			log.Fatal(err)
    59  		}
    60  		names = append(names, name)
    61  	}
    62  
    63  	// Check for errors from iterating over rows.
    64  	if err := rows.Err(); err != nil {
    65  		log.Fatal(err)
    66  	}
    67  	log.Printf("%s are %d years old", strings.Join(names, ", "), age)
    68  }
    69  
    70  func rowsMissingClose() {
    71  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age) // want "Rows/Stmt/NamedStmt was not closed"
    72  	if err != nil {
    73  		log.Fatal(err)
    74  	}
    75  	// defer rows.Close()
    76  
    77  	names := make([]string, 0)
    78  	for rows.Next() {
    79  		var name string
    80  		if err := rows.Scan(&name); err != nil {
    81  			log.Fatal(err)
    82  		}
    83  		names = append(names, name)
    84  	}
    85  
    86  	// Check for errors from iterating over rows.
    87  	if err := rows.Err(); err != nil {
    88  		log.Fatal(err)
    89  	}
    90  	log.Printf("%s are %d years old", strings.Join(names, ", "), age)
    91  }
    92  
    93  func rowsMissingCloseG[T ~int64](db *sql.DB, a T) {
    94  	rows, _ := db.Query("select id from tb") // want "Rows/Stmt/NamedStmt was not closed"
    95  	for rows.Next() {
    96  		// ...
    97  	}
    98  }
    99  
   100  func rowsNonDeferClose() {
   101  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
   102  	if err != nil {
   103  		log.Fatal(err)
   104  	}
   105  
   106  	names := make([]string, 0)
   107  	for rows.Next() {
   108  		var name string
   109  		if err := rows.Scan(&name); err != nil {
   110  			log.Fatal(err)
   111  		}
   112  		names = append(names, name)
   113  	}
   114  
   115  	// Check for errors from iterating over rows.
   116  	if err := rows.Err(); err != nil {
   117  		log.Fatal(err)
   118  	}
   119  	log.Printf("%s are %d years old", strings.Join(names, ", "), age)
   120  
   121  	rows.Close() // want "Close should use defer"
   122  }
   123  
   124  func rowsPassedAndClosed() {
   125  	rows, err := db.QueryContext(ctx, "SELECT name FROM users")
   126  	if err != nil {
   127  		log.Fatal(err)
   128  	}
   129  
   130  	rowsClosedPassed(rows)
   131  }
   132  
   133  func rowsClosedPassed(rows *sql.Rows) {
   134  	rows.Close()
   135  }
   136  
   137  func rowsPassedAndNotClosed(rows *sql.Rows) {
   138  	rows, err := db.QueryContext(ctx, "SELECT name FROM users")
   139  	if err != nil {
   140  		log.Fatal(err)
   141  	}
   142  
   143  	rowsDontClosedPassed(rows)
   144  }
   145  
   146  func rowsDontClosedPassed(*sql.Rows) {
   147  
   148  }
   149  
   150  func rowsReturn() (*sql.Rows, error) {
   151  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
   152  	if err != nil {
   153  		log.Fatal(err)
   154  	}
   155  	return rows, nil
   156  }
   157  
   158  func rowsReturnShort() (*sql.Rows, error) {
   159  	return db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
   160  }
   161  
   162  func stmtCorrectDeferBlock() {
   163  	// In normal use, create one Stmt when your process starts.
   164  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   165  	if err != nil {
   166  		log.Fatal(err)
   167  	}
   168  	defer func() {
   169  		err := stmt.Close()
   170  		if err != nil {
   171  			log.Print("problem closing stmt")
   172  		}
   173  	}()
   174  
   175  	// Then reuse it each time you need to issue the query.
   176  	var username string
   177  	err = stmt.QueryRowContext(ctx, userID).Scan(&username)
   178  	switch {
   179  	case err == sql.ErrNoRows:
   180  		log.Fatalf("no user with id %d", userID)
   181  	case err != nil:
   182  		log.Fatal(err)
   183  	default:
   184  		log.Printf("username is %s\n", username)
   185  	}
   186  }
   187  
   188  func stmtCorrectDefer() {
   189  	// In normal use, create one Stmt when your process starts.
   190  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   191  	if err != nil {
   192  		log.Fatal(err)
   193  	}
   194  	defer stmt.Close()
   195  
   196  	// Then reuse it each time you need to issue the query.
   197  	var username string
   198  	err = stmt.QueryRowContext(ctx, userID).Scan(&username)
   199  	switch {
   200  	case err == sql.ErrNoRows:
   201  		log.Fatalf("no user with id %d", userID)
   202  	case err != nil:
   203  		log.Fatal(err)
   204  	default:
   205  		log.Printf("username is %s\n", username)
   206  	}
   207  }
   208  
   209  func stmtMissingClose() {
   210  	// In normal use, create one Stmt when your process starts.
   211  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?") // want "Rows/Stmt/NamedStmt was not closed"
   212  	if err != nil {
   213  		log.Fatal(err)
   214  	}
   215  	// defer stmt.Close()
   216  
   217  	// Then reuse it each time you need to issue the query.
   218  	var username string
   219  	err = stmt.QueryRowContext(ctx, userID).Scan(&username)
   220  	switch {
   221  	case err == sql.ErrNoRows:
   222  		log.Fatalf("no user with id %d", userID)
   223  	case err != nil:
   224  		log.Fatal(err)
   225  	default:
   226  		log.Printf("username is %s\n", username)
   227  	}
   228  }
   229  
   230  func stmtNonDeferClose() {
   231  	// In normal use, create one Stmt when your process starts.
   232  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   233  	if err != nil {
   234  		log.Fatal(err)
   235  	}
   236  
   237  	// Then reuse it each time you need to issue the query.
   238  	var username string
   239  	err = stmt.QueryRowContext(ctx, userID).Scan(&username)
   240  	switch {
   241  	case err == sql.ErrNoRows:
   242  		log.Fatalf("no user with id %d", userID)
   243  	case err != nil:
   244  		log.Fatal(err)
   245  	default:
   246  		log.Printf("username is %s\n", username)
   247  	}
   248  
   249  	stmt.Close() // want "Close should use defer"
   250  }
   251  
   252  func stmtReturn() (*sql.Stmt, error) {
   253  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	return stmt, nil
   259  }
   260  
   261  func stmtReturnShort() (*sql.Stmt, error) {
   262  	return db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   263  }