blob: 2bf2a9fccf2594d271e0e128fbd4e73ee332577a [file] [log] [blame]
Brent Austinba3052e2015-04-21 16:08:23 -07001// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package sql_test
6
7import (
Dan Willemsenc7413322018-08-27 23:21:26 -07008 "context"
Brent Austinba3052e2015-04-21 16:08:23 -07009 "database/sql"
10 "fmt"
11 "log"
Dan Willemsenc7413322018-08-27 23:21:26 -070012 "strings"
13 "time"
Brent Austinba3052e2015-04-21 16:08:23 -070014)
15
Colin Crossd9c6b802019-03-19 21:10:31 -070016var (
17 ctx context.Context
18 db *sql.DB
19)
Brent Austinba3052e2015-04-21 16:08:23 -070020
Dan Willemsenc7413322018-08-27 23:21:26 -070021func ExampleDB_QueryContext() {
Brent Austinba3052e2015-04-21 16:08:23 -070022 age := 27
Dan Willemsenc7413322018-08-27 23:21:26 -070023 rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
Brent Austinba3052e2015-04-21 16:08:23 -070024 if err != nil {
25 log.Fatal(err)
26 }
27 defer rows.Close()
Dan Willemsenc7413322018-08-27 23:21:26 -070028 names := make([]string, 0)
Colin Crossd9c6b802019-03-19 21:10:31 -070029
Brent Austinba3052e2015-04-21 16:08:23 -070030 for rows.Next() {
31 var name string
32 if err := rows.Scan(&name); err != nil {
Colin Crossd9c6b802019-03-19 21:10:31 -070033 // Check for a scan error.
34 // Query rows will be closed with defer.
Brent Austinba3052e2015-04-21 16:08:23 -070035 log.Fatal(err)
36 }
Dan Willemsenc7413322018-08-27 23:21:26 -070037 names = append(names, name)
Brent Austinba3052e2015-04-21 16:08:23 -070038 }
Colin Crossd9c6b802019-03-19 21:10:31 -070039 // If the database is being written to ensure to check for Close
40 // errors that may be returned from the driver. The query may
41 // encounter an auto-commit error and be forced to rollback changes.
42 rerr := rows.Close()
43 if rerr != nil {
44 log.Fatal(err)
45 }
46
47 // Rows.Err will report the last error encountered by Rows.Scan.
Brent Austinba3052e2015-04-21 16:08:23 -070048 if err := rows.Err(); err != nil {
49 log.Fatal(err)
50 }
Dan Willemsenc7413322018-08-27 23:21:26 -070051 fmt.Printf("%s are %d years old", strings.Join(names, ", "), age)
Brent Austinba3052e2015-04-21 16:08:23 -070052}
53
Dan Willemsenc7413322018-08-27 23:21:26 -070054func ExampleDB_QueryRowContext() {
Brent Austinba3052e2015-04-21 16:08:23 -070055 id := 123
56 var username string
Dan Willemsenc7413322018-08-27 23:21:26 -070057 var created time.Time
58 err := db.QueryRowContext(ctx, "SELECT username, created_at FROM users WHERE id=?", id).Scan(&username, &created)
Brent Austinba3052e2015-04-21 16:08:23 -070059 switch {
60 case err == sql.ErrNoRows:
Colin Crossd9c6b802019-03-19 21:10:31 -070061 log.Printf("no user with id %d\n", id)
Brent Austinba3052e2015-04-21 16:08:23 -070062 case err != nil:
Colin Crossd9c6b802019-03-19 21:10:31 -070063 log.Fatalf("query error: %v\n", err)
Brent Austinba3052e2015-04-21 16:08:23 -070064 default:
Colin Crossd9c6b802019-03-19 21:10:31 -070065 log.Printf("username is %q, account created on %s\n", username, created)
Dan Willemsenc7413322018-08-27 23:21:26 -070066 }
67}
68
69func ExampleDB_ExecContext() {
70 id := 47
71 result, err := db.ExecContext(ctx, "UPDATE balances SET balance = balance + 10 WHERE user_id = ?", id)
72 if err != nil {
73 log.Fatal(err)
74 }
75 rows, err := result.RowsAffected()
76 if err != nil {
77 log.Fatal(err)
78 }
79 if rows != 1 {
Colin Crossd9c6b802019-03-19 21:10:31 -070080 log.Fatalf("expected to affect 1 row, affected %d", rows)
Brent Austinba3052e2015-04-21 16:08:23 -070081 }
82}
Dan Willemsenebae3022017-01-13 23:01:08 -080083
84func ExampleDB_Query_multipleResultSets() {
85 age := 27
86 q := `
87create temp table uid (id bigint); -- Create temp table for queries.
88insert into uid
89select id from users where age < ?; -- Populate temp table.
90
91-- First result set.
92select
93 users.id, name
94from
95 users
96 join uid on users.id = uid.id
97;
98
99-- Second result set.
100select
101 ur.user, ur.role
102from
103 user_roles as ur
104 join uid on uid.id = ur.user
105;
106 `
107 rows, err := db.Query(q, age)
108 if err != nil {
109 log.Fatal(err)
110 }
111 defer rows.Close()
112
113 for rows.Next() {
114 var (
115 id int64
116 name string
117 )
118 if err := rows.Scan(&id, &name); err != nil {
119 log.Fatal(err)
120 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700121 log.Printf("id %d name is %s\n", id, name)
Dan Willemsenebae3022017-01-13 23:01:08 -0800122 }
123 if !rows.NextResultSet() {
Colin Crossd9c6b802019-03-19 21:10:31 -0700124 log.Fatalf("expected more result sets: %v", rows.Err())
Dan Willemsenebae3022017-01-13 23:01:08 -0800125 }
126 var roleMap = map[int64]string{
127 1: "user",
128 2: "admin",
129 3: "gopher",
130 }
131 for rows.Next() {
132 var (
133 id int64
134 role int64
135 )
136 if err := rows.Scan(&id, &role); err != nil {
137 log.Fatal(err)
138 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700139 log.Printf("id %d has role %s\n", id, roleMap[role])
Dan Willemsenebae3022017-01-13 23:01:08 -0800140 }
141 if err := rows.Err(); err != nil {
142 log.Fatal(err)
143 }
144}
Dan Willemsenc7413322018-08-27 23:21:26 -0700145
146func ExampleDB_PingContext() {
Colin Crossd9c6b802019-03-19 21:10:31 -0700147 // Ping and PingContext may be used to determine if communication with
148 // the database server is still possible.
149 //
150 // When used in a command line application Ping may be used to establish
151 // that further queries are possible; that the provided DSN is valid.
152 //
153 // When used in long running service Ping may be part of the health
154 // checking system.
155
Dan Willemsenc7413322018-08-27 23:21:26 -0700156 ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
157 defer cancel()
Colin Crossd9c6b802019-03-19 21:10:31 -0700158
159 status := "up"
Dan Willemsenc7413322018-08-27 23:21:26 -0700160 if err := db.PingContext(ctx); err != nil {
Colin Crossd9c6b802019-03-19 21:10:31 -0700161 status = "down"
Dan Willemsenc7413322018-08-27 23:21:26 -0700162 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700163 log.Println(status)
Dan Willemsenc7413322018-08-27 23:21:26 -0700164}
165
Colin Cross430342c2019-09-07 08:36:04 -0700166func ExampleDB_Prepare() {
167 projects := []struct {
168 mascot string
169 release int
170 }{
171 {"tux", 1991},
172 {"duke", 1996},
173 {"gopher", 2009},
174 {"moby dock", 2013},
175 }
176
177 stmt, err := db.Prepare("INSERT INTO projects(id, mascot, release, category) VALUES( ?, ?, ?, ? )")
178 if err != nil {
179 log.Fatal(err)
180 }
181 defer stmt.Close() // Prepared statements take up server resources and should be closed after use.
182
183 for id, project := range projects {
184 if _, err := stmt.Exec(id+1, project.mascot, project.release, "open source"); err != nil {
185 log.Fatal(err)
186 }
187 }
188}
189
190func ExampleTx_Prepare() {
191 projects := []struct {
192 mascot string
193 release int
194 }{
195 {"tux", 1991},
196 {"duke", 1996},
197 {"gopher", 2009},
198 {"moby dock", 2013},
199 }
200
201 tx, err := db.Begin()
202 if err != nil {
203 log.Fatal(err)
204 }
205 defer tx.Rollback() // The rollback will be ignored if the tx has been committed later in the function.
206
207 stmt, err := tx.Prepare("INSERT INTO projects(id, mascot, release, category) VALUES( ?, ?, ?, ? )")
208 if err != nil {
209 log.Fatal(err)
210 }
211 defer stmt.Close() // Prepared statements take up server resources and should be closed after use.
212
213 for id, project := range projects {
214 if _, err := stmt.Exec(id+1, project.mascot, project.release, "open source"); err != nil {
215 log.Fatal(err)
216 }
217 }
218 if err := tx.Commit(); err != nil {
219 log.Fatal(err)
220 }
221}
222
Dan Willemsenc7413322018-08-27 23:21:26 -0700223func ExampleConn_BeginTx() {
224 tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
225 if err != nil {
226 log.Fatal(err)
227 }
228 id := 37
229 _, execErr := tx.Exec(`UPDATE users SET status = ? WHERE id = ?`, "paid", id)
230 if execErr != nil {
231 _ = tx.Rollback()
232 log.Fatal(execErr)
233 }
234 if err := tx.Commit(); err != nil {
235 log.Fatal(err)
236 }
237}
238
239func ExampleConn_ExecContext() {
240 // A *DB is a pool of connections. Call Conn to reserve a connection for
241 // exclusive use.
242 conn, err := db.Conn(ctx)
243 if err != nil {
244 log.Fatal(err)
245 }
246 defer conn.Close() // Return the connection to the pool.
247 id := 41
Colin Crossd9c6b802019-03-19 21:10:31 -0700248 result, err := conn.ExecContext(ctx, `UPDATE balances SET balance = balance + 10 WHERE user_id = ?;`, id)
Dan Willemsenc7413322018-08-27 23:21:26 -0700249 if err != nil {
250 log.Fatal(err)
251 }
252 rows, err := result.RowsAffected()
253 if err != nil {
254 log.Fatal(err)
255 }
256 if rows != 1 {
Colin Crossd9c6b802019-03-19 21:10:31 -0700257 log.Fatalf("expected single row affected, got %d rows affected", rows)
Dan Willemsenc7413322018-08-27 23:21:26 -0700258 }
259}
260
261func ExampleTx_ExecContext() {
262 tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
263 if err != nil {
264 log.Fatal(err)
265 }
266 id := 37
267 _, execErr := tx.ExecContext(ctx, "UPDATE users SET status = ? WHERE id = ?", "paid", id)
268 if execErr != nil {
269 if rollbackErr := tx.Rollback(); rollbackErr != nil {
Colin Crossd9c6b802019-03-19 21:10:31 -0700270 log.Fatalf("update failed: %v, unable to rollback: %v\n", execErr, rollbackErr)
Dan Willemsenc7413322018-08-27 23:21:26 -0700271 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700272 log.Fatalf("update failed: %v", execErr)
Dan Willemsenc7413322018-08-27 23:21:26 -0700273 }
274 if err := tx.Commit(); err != nil {
275 log.Fatal(err)
276 }
277}
278
279func ExampleTx_Rollback() {
280 tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
281 if err != nil {
282 log.Fatal(err)
283 }
284 id := 53
Colin Crossd9c6b802019-03-19 21:10:31 -0700285 _, err = tx.ExecContext(ctx, "UPDATE drivers SET status = ? WHERE id = ?;", "assigned", id)
Dan Willemsenc7413322018-08-27 23:21:26 -0700286 if err != nil {
287 if rollbackErr := tx.Rollback(); rollbackErr != nil {
Colin Crossd9c6b802019-03-19 21:10:31 -0700288 log.Fatalf("update drivers: unable to rollback: %v", rollbackErr)
Dan Willemsenc7413322018-08-27 23:21:26 -0700289 }
290 log.Fatal(err)
291 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700292 _, err = tx.ExecContext(ctx, "UPDATE pickups SET driver_id = $1;", id)
Dan Willemsenc7413322018-08-27 23:21:26 -0700293 if err != nil {
294 if rollbackErr := tx.Rollback(); rollbackErr != nil {
Colin Crossd9c6b802019-03-19 21:10:31 -0700295 log.Fatalf("update failed: %v, unable to back: %v", err, rollbackErr)
Dan Willemsenc7413322018-08-27 23:21:26 -0700296 }
297 log.Fatal(err)
298 }
299 if err := tx.Commit(); err != nil {
300 log.Fatal(err)
301 }
302}
303
304func ExampleStmt() {
305 // In normal use, create one Stmt when your process starts.
306 stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
307 if err != nil {
308 log.Fatal(err)
309 }
310 defer stmt.Close()
Colin Crossd9c6b802019-03-19 21:10:31 -0700311
Dan Willemsenc7413322018-08-27 23:21:26 -0700312 // Then reuse it each time you need to issue the query.
313 id := 43
314 var username string
315 err = stmt.QueryRowContext(ctx, id).Scan(&username)
316 switch {
317 case err == sql.ErrNoRows:
Colin Crossd9c6b802019-03-19 21:10:31 -0700318 log.Fatalf("no user with id %d", id)
Dan Willemsenc7413322018-08-27 23:21:26 -0700319 case err != nil:
320 log.Fatal(err)
321 default:
Colin Crossd9c6b802019-03-19 21:10:31 -0700322 log.Printf("username is %s\n", username)
Dan Willemsenc7413322018-08-27 23:21:26 -0700323 }
324}
325
326func ExampleStmt_QueryRowContext() {
327 // In normal use, create one Stmt when your process starts.
328 stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
329 if err != nil {
330 log.Fatal(err)
331 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700332 defer stmt.Close()
333
Dan Willemsenc7413322018-08-27 23:21:26 -0700334 // Then reuse it each time you need to issue the query.
335 id := 43
336 var username string
337 err = stmt.QueryRowContext(ctx, id).Scan(&username)
338 switch {
339 case err == sql.ErrNoRows:
Colin Crossd9c6b802019-03-19 21:10:31 -0700340 log.Fatalf("no user with id %d", id)
Dan Willemsenc7413322018-08-27 23:21:26 -0700341 case err != nil:
342 log.Fatal(err)
343 default:
Colin Crossd9c6b802019-03-19 21:10:31 -0700344 log.Printf("username is %s\n", username)
Dan Willemsenc7413322018-08-27 23:21:26 -0700345 }
346}
347
348func ExampleRows() {
349 age := 27
350 rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
351 if err != nil {
352 log.Fatal(err)
353 }
354 defer rows.Close()
Colin Crossd9c6b802019-03-19 21:10:31 -0700355
Dan Willemsenc7413322018-08-27 23:21:26 -0700356 names := make([]string, 0)
357 for rows.Next() {
358 var name string
359 if err := rows.Scan(&name); err != nil {
360 log.Fatal(err)
361 }
362 names = append(names, name)
363 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700364 // Check for errors from iterating over rows.
Dan Willemsenc7413322018-08-27 23:21:26 -0700365 if err := rows.Err(); err != nil {
366 log.Fatal(err)
367 }
Colin Crossd9c6b802019-03-19 21:10:31 -0700368 log.Printf("%s are %d years old", strings.Join(names, ", "), age)
Dan Willemsenc7413322018-08-27 23:21:26 -0700369}