Creating Go programs that use Cloud SQL

9/12/15: The code works in this section, but there's little explanatory text because I'm doing the examples first. Explanations will come later

Example programs in this chapter

Obtaining the MySQL driver using go get

To use MySQL with Go you need a driver. Go MySQL Driver is a popular and well-supported one.

# May need to precede with sudo
$ go get github.com/go-sql-driver/mysql

go get "status 69" error message

If you get a status 69 error message as shown below, precede the go get statement with sudo and enter your adminstrative password when asked.

# cd .; git clone https://github.com/go-sql-driver/mysql /Users/tom/go/src/github.com/go-sql-driver/mysql

Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.

package github.com/go-sql-driver/mysql: exit status 69

Example cloudsql1.go: Create a Google Cloud SQL table with options set at the command line

For me, half the battle was just getting a working sample of connecting to CloudSQL-the sql.Open() examples that I could find never showed the real thing.

This shows how to create the right connection string, open a database connection, create a table named exercisemysql1, and exit.

The values used for the user name, database name, and so on are const strings in which you will overwrite the values with your own confidential ones:

    // REPLACE WITH YOUR OWN VALUES
    // User created in Cloud SQL dashboard
    const dbUserName = "sampleuser"

    // Database created in Cloud SQL dashboard
    const dbName = "tomsdatabase"

    // Password for Cloud SQL database
    const dbPassword = "Samplepassword45"

    // IP address of Cloud SQL database
    const dbIP = "tcp(173.194.255.122:3306)"

They will be generated in this format for the call to sql.Open():

sampleuser:Samplepassword45@tcp(173.194.255.122:3306)/tomsdatabase
// cloudsql1.go - Creates Google Cloud SQL table
package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "log"
)

func main() {
    const dbUserName = "sampleuser"
    const dbName = "tomsdatabase"
    //const dbIP = "2001:4860:4864:1:de34:1928:6ae4:7058"
    const dbIP = "tcp(169.191.255.122:3306)"
    const dbOpenString = dbUserName + ":" + dbPassword + "@" + dbIP + "/" +
    db, err := sql.Open("mysql", dbOpenString);
    if err != nil {
        log.Println("sql.Open(" +
            dbOpenString +
            "\"mysql, \"")
    }
    defer db.Close()
    log.Println("Pinging database. This may take a moment.")
    err = db.Ping()
    if err != nil {
        log.Println("db.Ping() call failed:");
        log.Println(err)
    }
    _, err = db.Exec(
        `CREATE TABLE IF NOT EXISTS exercisecloudsql101
        (id INT NOT NULL AUTO_INCREMENT,
        name VARCHAR(100) NOT NULL,
        description TEXT, PRIMARY KEY (id))`)

    if err != nil {
        log.Println("CREATE TABLE failed:")
        log.Println(err) }
    }
`

Example cloudsql2.go: Create a Google Cloud SQL table with options set at the command line

The example cloudsql2.go shows how to create the right connection string, open a database connection, create a table named exercisemysql2, and exit. That's if you use the default values. All options are now configurable via command line, so, for example, this would create a sample table named customer.

$ ./cloudsql2 -table customer

`
// cloudsql2.go - Creates Google Cloud SQL database
// Can pass the following as command line parameters:
// Google Cloud SQL user name
// Google Cloud SQL database name
// Google Cloud SQL password
// IP address of Google Cloud SQL database instance
// Google Cloud SQL port to use for connection
// Name of table to create inside the database

// Examples:
// $ ./cloudsql2 -table customer
// Default:
// db, err := sql.Open(
//   "mysql",
//   "sampleuser:Foobar1@tcp(173.194.255.122:3306)/tomsdatabase"

package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "log"
    "flag"
)

func main() {

    // Command-line flags

    var cmdLine string;

    // Username, like mysql -u option
    uOption := flag.String("u", "sampleuser", "Database username, equivalent to mysql -u option")

    // Database name, similar to mysql -database options
    databaseOption := flag.String("database", "tomsdatabase", "CloudSQL database to open")

    // Password for Cloud SQL database, similar to the mysql -p option.
    passwordOption := flag.String("password", "Foobar1", "Cloud SQL port to use for connection")

    // IP address of Cloud SQL database instance to connect to, like mysql --bind-address option
    bindAddressOption := flag.String("bind-address", "173.194.255.122", "--bind-address is the IP address of the Cloud SQL server instance")

    // Server's port number to use for connection. Equivalent to mysql --port option
    portOption := flag.String("port", "3306", "--port is the port used on the Cloud SQL server instance");

    // Name of table to create
    tableName := flag.String("table", "exercisecloudsql2", "--table is the name of the table to create")

    // Parse command-line flags. Use default values or replace with those specified.
    flag.Parse();

    // Build intializer for sqlOpen() and display it for educational purposes.
    cmdLine = *uOption+":"+*passwordOption+"@tcp("+*bindAddressOption+":"+*portOption+")/"+*databaseOption
    log.Println("sqlOpen(): " + cmdLine + "\n"); 

    // Create database connection & 
    // create connection pool.
    // Does not do an actual database open, despite the name. 
    // Do this only once.
    db, err := sql.Open("mysql",
        cmdLine)    

    // Check for error before the defer.
    if err != nil {
        log.Println(err)
    }

    // Close connection & return database resources
    // when function exits. Normally a database
    // connection lasts much longer.
    defer db.Close()

    // Verify the data source is valid.
    log.Println("Pinging the database. This may take a moment...")
    err = db.Ping()
    if err != nil {
        log.Println(err)
    } else {
        // Create a table named by the --table option.
        _, err = db.Exec(
            "CREATE TABLE IF NOT EXISTS " + *tableName + " " +
            "(id INT NOT NULL AUTO_INCREMENT, " + 
            "name VARCHAR(100) NOT NULL, " + 
            "description TEXT, PRIMARY KEY (id))")

        if err != nil {
            log.Println(err)
        }
    }
}
`

Example cloudsql3.go: Create a Google Cloud SQL table and add a record, with options set at the command line

The example cloudsql3.go builds on the previous example and now inserts a record into the database.

// cloudsql3.go - Creates Google Cloud SQL database table &
// adds a record
// Can pass the following as command line parameters:
// Google Cloud SQL user name
// Google Cloud SQL database name
// Google Cloud SQL password
// IP address of Google Cloud SQL database instance
// Google Cloud SQL port to use for connection
// Name of table to create inside the database

// Examples:
// $ ./cloudsql3 -table customer

//
// $
// Default:
// sampleuser:Foobar1@tcp(173.194.255.122:3306)/tomsdatabase

package main

import (
    "database/sql"
    "flag"
    _ "github.com/go-sql-driver/mysql"
    "log"
)

func main() {

    // Command-line flags

    var cmdLine string
    // Username, like mysql -u option
    uOption := flag.String(
        "u",
        "sampleuser",
        "Database username, equivalent to mysql -u option")

    // Database name, similar to mysql -database options
    databaseOption := flag.String(
        "database",
        "tomsdatabase",
        "CloudSQL database to open")

    // Password for Cloud SQL database, similar to the
    // mysql -p option.
    passwordOption := flag.String(
        "password",
        "Foobar1",
        "Cloud SQL port to use for connection")

    // IP address of Cloud SQL database instance to
    // connect to, like mysql --bind-address option
    bindAddressOption := flag.String(
        "bind-address",
        "173.194.256.122",
        "--bind-address IP addrs of Cloud SQL instance")

    // Server's port number to use for connection.
    // Equivalent to mysql --port option
    portOption := flag.String(
        "port",
        "3306",
        "--port Port used on the Cloud SQL instance")

    // Name of table to create
    tableName := flag.String(
        "table",
        "exercisecloudsql3",
        "--table Name of database table to create")

    // Parse command-line flags.
    // Use default values or replace with those specified.
    flag.Parse()

    // Build intializer for sqlOpen() and display it for
    // educational purposes.
    cmdLine =
        *uOption + ":" +
            *passwordOption +
            "@tcp(" + *bindAddressOption +
            ":" + *portOption + ")/" +
            *databaseOption

    log.Println("sqlOpen(): " + cmdLine + "\n")

    // Create database connection &
    // create connection pool.
    // Does not do an actual database open, despite its name
    db, err := sql.Open("mysql", cmdLine)
    // Check for error before the defer.
    if err != nil {
        log.Println(err)
    }
    // Close connection & return database resources
    // when function exits. Normally a database
    // connection lasts much longer.
    defer db.Close()
    // Verify the data source is valid.
    log.Println("Opening database. Please wait...")
    err = db.Ping()
    if err != nil {
        log.Println(err)
    } else {
        // Create a table named by the --table option.
        _, err = db.Exec(
            "CREATE TABLE IF NOT EXISTS " + 
                *tableName + " " +
                "(id INT NOT NULL AUTO_INCREMENT, " +
                "name VARCHAR(100) NOT NULL, " +
                "description TEXT, PRIMARY KEY (id))")
        if err != nil {
            log.Println(err)
        }
    }

    // Prepare to add a record. Leave placeholders. 
    // These will be used to fill in both 
    // non autoincrement fields.
    stmt, err := db.Prepare("INSERT INTO " +
        *tableName + "(name, description) VALUES(?, ?)")
    if err != nil {
        log.Fatal(err)
    }

    // Insert data where the placeholders were.
    res, err := stmt.Exec(
        "Cajun Mens Boots",
        "Swamp tested and alligator approved")
    if err != nil {
        log.Fatal(err)
    }

    lastId, err := res.LastInsertId()
    if err != nil {
        log.Fatal(err)
    }

    // First variable is # of rows changed by 
    // this operation.
    _, err = res.RowsAffected()
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Updated record # %d.\n", lastId)
}

`

Example cloudsql4.go: Query a Google Cloud SQL table and display the results.

The example cloudsql4.go inserts a record into a database, then searches for that record with a SQL query, showing all returned rows.

// cloudsql4.go - Creates Google Cloud SQL database table &
// adds a record, then does a query and returns all matching rows.
// TODO:
// Document the query it does
// Maybe add some better sample data since right now
// it's just a bunch of duplicated records.
// Can pass the following as command line parameters:
// Google Cloud SQL user name
// Google Cloud SQL database name
// Google Cloud SQL password
// IP address of Google Cloud SQL database instance
// Google Cloud SQL port to use for connection
// Name of table to create inside the database

// Examples:
// $ ./cloudsql4 -table customer

//
// $
// Default:
// sampleuser:Foobar1@tcp(173.194.255.122:3306)/tomsdatabase

package main

import (
    "fmt"
   //"io/ioutil"
    "database/sql"
    "flag"
    _ "github.com/go-sql-driver/mysql"
    "log"
)

type Product struct {
    Name string
    Description []byte
}


func main() {

    // Command-line flags

    var cmdLine string
    // Username, like mysql -u option
    uOption := flag.String(
        "u",
        "sampleuser",
        "Database username, equivalent to mysql -u option")

    // Database name, similar to mysql -database options
    databaseOption := flag.String(
        "database",
        "tomsdatabase",
        "CloudSQL database to open")

    // Password for Cloud SQL database, similar to the
    // mysql -p option.
    passwordOption := flag.String(
        "password",
        "Foobar1",
        "Cloud SQL port to use for connection")

    // IP address of Cloud SQL database instance to
    // connect to, like mysql --bind-address option
    bindAddressOption := flag.String(
        "bind-address",
        "173.194.256.122",
        "--bind-address IP addrs of Cloud SQL instance")

    // Server's port number to us:e for connection.
    // Equivalent to mysql --port option
    portOption := flag.String(
        "port",
        "3306",
        "--port Port used on the Cloud SQL instance")

    // Name of table to create
    tableName := flag.String(
        "table",
        "exercisemysql3",
        "--table Name of database table to create")

    // Parse command-line flags.
    // Use default values or replace with those specified.
    flag.Parse()

    // Build intializer for sqlOpen() and display it for
    // educational purposes.
    cmdLine =
        *uOption + ":" +
            *passwordOption +
            "@tcp(" + *bindAddressOption +
            ":" + *portOption + ")/" +
            *databaseOption

    log.Println("sqlOpen(): " + cmdLine + "\n")

    // Create database connection &
    // create connection pool.
    // Does not do an actual database open, despite its name
    db, err := sql.Open("mysql", cmdLine)
    // Check for error before the defer.
    if err != nil {
        log.Println(err)
    }
    // Close connection & return database resources
    // when function exits. Normally a database
    // connection lasts much longer.
    defer db.Close()
    // Verify the data source is valid.
    log.Println("Opening database. Please wait...")
    err = db.Ping()
    if err != nil {
        log.Println(err)
    } else {
        // Create a table named by the --table option.
        _, err = db.Exec(
            "CREATE TABLE IF NOT EXISTS " + 
                *tableName + " " +
                "(id INT NOT NULL AUTO_INCREMENT, " +
                "name VARCHAR(100) NOT NULL, " +
                "description TEXT, PRIMARY KEY (id))")
        if err != nil {
            log.Println(err)
        }
    }

    // Prepare to add a record. Leave placeholders. 
    // These will be used to fill in both 
    // non autoincrement fields.
    stmt, err := db.Prepare("INSERT INTO " +
        *tableName + "(name, description) VALUES(?, ?)")
    if err != nil {
        log.Fatal(err)
    }

    // Insert data where the placeholders were.
    res, err := stmt.Exec(
        "Cajun Mens Boots",
        "Swamp tested and alligator approved")
    if err != nil {
        log.Fatal(err)
    }

    lastId, err := res.LastInsertId()
    if err != nil {
        log.Fatal(err)
    }

    // First variable is # of rows changed by 
    // this operation.
    _, err = res.RowsAffected()
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Updated record # %d.\n", lastId)


    rows, err := db.Query(
        "SELECT * from " +
        *tableName + " " +
        "WHERE NAME LIKE '%Cajun%'")
    if err != nil {
        log.Fatal(err)
    }

    for rows.Next() {
        var description string
        var id int
        var name string
        if err := rows.Scan(&id, &name, &description); err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s\n", name)
    }   

    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
}

`

Example cloudsql6.go: Search Google Cloud SQL table and displaly matching records

The example cloudsql6.go Creates a table, inserts some sample records, and searches for a value in that table.

// cloudsql6.go - Creates Google Cloud SQL database table &
// adds multiple records, queries for the word Cajun
// (can change on command line) and returns all matching rows.
// TODO:
// Document the query it does
// Maybe add some better sample data since right now
// it's just a bunch of duplicated records.
// Can pass the following as command line parameters:
// Google Cloud SQL user name
// Google Cloud SQL database name
// Google Cloud SQL password
// IP address of Google Cloud SQL database instance
// Google Cloud SQL port to use for connection
// Name of table to create inside the database

// Examples:
// $ ./cloudsql6 -table customer
// $ ./cloudsql6 --bind-address "173.194.255.122" --search Camouflage
//
// Default:
// sampleuser:Foobar1@tcp(173.194.255.122:3306)/tomsdatabase

package main

import (
    "fmt"
    "database/sql"
    "flag"
    _ "github.com/go-sql-driver/mysql"
    "log"
)

// Go representation of database record for a Product item
type Product struct {
    Name        string
    Description []byte
}

func main() {


    // Command-line flags
    // Username, like mysql -u option
    uOption := flag.String(
        "u",
        "sampleuser",
        "Database username, equivalent to mysql -u option")

    // Database name, similar to mysql -database options
    databaseOption := flag.String(
        "database",
        "tomsdatabase",
        "CloudSQL database to open")

    // Password for Cloud SQL database, similar to the
    // mysql -p option.
    passwordOption := flag.String(
        "password",
        "Foobar1",
        "Cloud SQL port to use for connection")

    // IP address of Cloud SQL database instance to
    // connect to, like mysql --bind-address option
    bindAddressOption := flag.String(
        "bind-address",
        "173.194.256.122",
        "--bind-address IP addrs of Cloud SQL instance")

    // Server's port number to us:e for connection.
    // Equivalent to mysql --port option
    portOption := flag.String(
        "port",
        "3306",
        "--port Port used on the Cloud SQL instance")

    // Name of table to create
    tableName := flag.String(
        "table",
        "exercisemysql6",
        "--table Name of database table to create")

    // Search term (search is run after records are added
    // to database).
    searchTerm := flag.String(
        "search",
        "Cajun",
        "--Search for this after records added to database")
    // Parse command-line flags.
    // Use default values or replace with those specified.
    flag.Parse()

    // Build parameter string for sqlOpen() and display it for
    // educational purposes.
    cmdLine :=
        *uOption + ":" +
            *passwordOption +
            "@tcp(" + *bindAddressOption +
            ":" + *portOption + ")/" +
            *databaseOption

    log.Println("sqlOpen(): " + cmdLine + "\n")

    // Create database connection &
    // create connection pool.
    // Does not do an actual database open, despite its name
    db, err := sql.Open("mysql", cmdLine)
    // Check for error before the defer.
    if err != nil {
        log.Println(err)
    }

    // Close connection & return database resources
    // when function exits. Normally a database
    // connection lasts much longer.
    defer db.Close()
    // Verify the data source is valid.
    log.Println("Opening database. Please wait...")
    err = db.Ping()
    if err != nil {
        log.Println(err)
    } else {
        // Create a table named by the --table option.
        _, err = db.Exec(
            "CREATE TABLE IF NOT EXISTS " +
                *tableName + " " +
                "(id INT NOT NULL AUTO_INCREMENT, " +
                "name VARCHAR(100) NOT NULL, " +
                "description TEXT, PRIMARY KEY (id))")
        if err != nil {
            log.Println(err)
        }
    }

    // Populate database with a few records. 
    res, err := db.Exec("INSERT INTO " +
        *tableName + "(name, description) VALUES " +
        "('Cajun Boots for Men', 'Alligator-tough'), " +
        "('Camouflage 2 Person Tent', 'No-mallet setup'), " +
        "('Cajun Boots for Women', 'Lighter no-sweat fabric ');")
    if err != nil {
        log.Fatal(err)
    }

    lastId, err := res.LastInsertId()
    if err != nil {
        log.Fatal(err)
    }

    // First variable is # of rows changed by
    // this operation.
    affected, err := res.RowsAffected()
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Updated record # %d\n", lastId)
    log.Printf("Rows affected: %d\n", affected)

    // Search the name column for a record in the database
    rows, err := db.Query(
        "SELECT * from " +
            *tableName + " " +
            "WHERE NAME LIKE '%" + *searchTerm + "%'")
    if err != nil {
        log.Fatal(err)
    }

    // Display all rows matching the search
    log.Printf("Results of search for %s:\n", *searchTerm)
    for rows.Next() {
        var description string
        var id int
        var name string
        if err := rows.Scan(&id, &name, &description); err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s\n", name)
    }

    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
}

`

results matching ""

    No results matching ""