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 }