Source file src/database/sql/example_test.go

     1  // 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  
     5  package sql_test
     6  
     7  import (
     8  	"context"
     9  	"database/sql"
    10  	"fmt"
    11  	"log"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  var (
    17  	ctx context.Context
    18  	db  *sql.DB
    19  )
    20  
    21  func ExampleDB_QueryContext() {
    22  	age := 27
    23  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
    24  	if err != nil {
    25  		log.Fatal(err)
    26  	}
    27  	defer rows.Close()
    28  	names := make([]string, 0)
    29  
    30  	for rows.Next() {
    31  		var name string
    32  		if err := rows.Scan(&name); err != nil {
    33  			// Check for a scan error.
    34  			// Query rows will be closed with defer.
    35  			log.Fatal(err)
    36  		}
    37  		names = append(names, name)
    38  	}
    39  	// 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(rerr)
    45  	}
    46  
    47  	// Rows.Err will report the last error encountered by Rows.Scan.
    48  	if err := rows.Err(); err != nil {
    49  		log.Fatal(err)
    50  	}
    51  	fmt.Printf("%s are %d years old", strings.Join(names, ", "), age)
    52  }
    53  
    54  func ExampleDB_QueryRowContext() {
    55  	id := 123
    56  	var username string
    57  	var created time.Time
    58  	err := db.QueryRowContext(ctx, "SELECT username, created_at FROM users WHERE id=?", id).Scan(&username, &created)
    59  	switch {
    60  	case err == sql.ErrNoRows:
    61  		log.Printf("no user with id %d\n", id)
    62  	case err != nil:
    63  		log.Fatalf("query error: %v\n", err)
    64  	default:
    65  		log.Printf("username is %q, account created on %s\n", username, created)
    66  	}
    67  }
    68  
    69  func 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 {
    80  		log.Fatalf("expected to affect 1 row, affected %d", rows)
    81  	}
    82  }
    83  
    84  func ExampleDB_Query_multipleResultSets() {
    85  	age := 27
    86  	q := `
    87  create temp table uid (id bigint); -- Create temp table for queries.
    88  insert into uid
    89  select id from users where age < ?; -- Populate temp table.
    90  
    91  -- First result set.
    92  select
    93  	users.id, name
    94  from
    95  	users
    96  	join uid on users.id = uid.id
    97  ;
    98  
    99  -- Second result set.
   100  select
   101  	ur.user, ur.role
   102  from
   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  		}
   121  		log.Printf("id %d name is %s\n", id, name)
   122  	}
   123  	if !rows.NextResultSet() {
   124  		log.Fatalf("expected more result sets: %v", rows.Err())
   125  	}
   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  		}
   139  		log.Printf("id %d has role %s\n", id, roleMap[role])
   140  	}
   141  	if err := rows.Err(); err != nil {
   142  		log.Fatal(err)
   143  	}
   144  }
   145  
   146  func ExampleDB_PingContext() {
   147  	// 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  
   156  	ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
   157  	defer cancel()
   158  
   159  	status := "up"
   160  	if err := db.PingContext(ctx); err != nil {
   161  		status = "down"
   162  	}
   163  	log.Println(status)
   164  }
   165  
   166  func 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  
   190  func 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  
   223  func ExampleDB_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  
   239  func 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
   248  	result, err := conn.ExecContext(ctx, `UPDATE balances SET balance = balance + 10 WHERE user_id = ?;`, id)
   249  	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 {
   257  		log.Fatalf("expected single row affected, got %d rows affected", rows)
   258  	}
   259  }
   260  
   261  func 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 {
   270  			log.Fatalf("update failed: %v, unable to rollback: %v\n", execErr, rollbackErr)
   271  		}
   272  		log.Fatalf("update failed: %v", execErr)
   273  	}
   274  	if err := tx.Commit(); err != nil {
   275  		log.Fatal(err)
   276  	}
   277  }
   278  
   279  func 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
   285  	_, err = tx.ExecContext(ctx, "UPDATE drivers SET status = ? WHERE id = ?;", "assigned", id)
   286  	if err != nil {
   287  		if rollbackErr := tx.Rollback(); rollbackErr != nil {
   288  			log.Fatalf("update drivers: unable to rollback: %v", rollbackErr)
   289  		}
   290  		log.Fatal(err)
   291  	}
   292  	_, err = tx.ExecContext(ctx, "UPDATE pickups SET driver_id = $1;", id)
   293  	if err != nil {
   294  		if rollbackErr := tx.Rollback(); rollbackErr != nil {
   295  			log.Fatalf("update failed: %v, unable to back: %v", err, rollbackErr)
   296  		}
   297  		log.Fatal(err)
   298  	}
   299  	if err := tx.Commit(); err != nil {
   300  		log.Fatal(err)
   301  	}
   302  }
   303  
   304  func 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()
   311  
   312  	// 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:
   318  		log.Fatalf("no user with id %d", id)
   319  	case err != nil:
   320  		log.Fatal(err)
   321  	default:
   322  		log.Printf("username is %s\n", username)
   323  	}
   324  }
   325  
   326  func 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  	}
   332  	defer stmt.Close()
   333  
   334  	// 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:
   340  		log.Fatalf("no user with id %d", id)
   341  	case err != nil:
   342  		log.Fatal(err)
   343  	default:
   344  		log.Printf("username is %s\n", username)
   345  	}
   346  }
   347  
   348  func 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()
   355  
   356  	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  	}
   364  	// Check for errors from iterating over rows.
   365  	if err := rows.Err(); err != nil {
   366  		log.Fatal(err)
   367  	}
   368  	log.Printf("%s are %d years old", strings.Join(names, ", "), age)
   369  }
   370  

View as plain text