Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions examples/data-types/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"cloud.google.com/go/civil"
"cloud.google.com/go/spanner"
"github.com/google/uuid"
spannerdriver "github.com/googleapis/go-sql-spanner"
"github.com/googleapis/go-sql-spanner/examples"
)
Expand All @@ -38,6 +39,7 @@ var createTableStatement = `CREATE TABLE AllTypes (
numeric NUMERIC,
date DATE,
timestamp TIMESTAMP,
col_uuid UUID,
boolArray ARRAY<BOOL>,
stringArray ARRAY<STRING(MAX)>,
bytesArray ARRAY<BYTES(MAX)>,
Expand All @@ -47,6 +49,7 @@ var createTableStatement = `CREATE TABLE AllTypes (
numericArray ARRAY<NUMERIC>,
dateArray ARRAY<DATE>,
timestampArray ARRAY<TIMESTAMP>,
uuidArray ARRAY<UUID>,
) PRIMARY KEY (key)`

// Sample showing how to work with the different data types that are supported by Cloud Spanner:
Expand All @@ -68,15 +71,16 @@ func dataTypes(projectId, instanceId, databaseId string) error {

// Insert a test row with all non-null values using DML and native types.
if _, err := db.ExecContext(ctx, `INSERT INTO AllTypes (
key, bool, string, bytes, int64, float32, float64, numeric, date, timestamp,
boolArray, stringArray, bytesArray, int64Array, float32Array, float64Array, numericArray, dateArray, timestampArray)
VALUES (@key, @bool, @string, @bytes, @int64, @float32, @float64, @numeric, @date, @timestamp,
@boolArray, @stringArray, @bytesArray, @int64Array, @float32Array, @float64Array, @numericArray, @dateArray, @timestampArray)`,
1, true, "string", []byte("bytes"), 100, float32(3.14), 3.14, *big.NewRat(1, 1), civil.DateOf(time.Now()), time.Now(),
key, bool, string, bytes, int64, float32, float64, numeric, date, timestamp, col_uuid,
boolArray, stringArray, bytesArray, int64Array, float32Array, float64Array, numericArray, dateArray, timestampArray, uuidArray)
VALUES (@key, @bool, @string, @bytes, @int64, @float32, @float64, @numeric, @date, @timestamp, @uuid,
@boolArray, @stringArray, @bytesArray, @int64Array, @float32Array, @float64Array, @numericArray, @dateArray, @timestampArray, @uuidArray)`,
1, true, "string", []byte("bytes"), 100, float32(3.14), 3.14, *big.NewRat(1, 1), civil.DateOf(time.Now()), time.Now(), uuid.New(),
[]bool{true, false}, []string{"s1", "s2"}, [][]byte{[]byte("b1"), []byte("b2")}, []int64{1, 2},
[]float32{1.1, 2.2}, []float64{1.1, 2.2}, []big.Rat{*big.NewRat(1, 2), *big.NewRat(1, 3)},
[]civil.Date{{Year: 2021, Month: 10, Day: 12}, {Year: 2021, Month: 10, Day: 13}},
[]time.Time{time.Now(), time.Now().Add(24 * time.Hour)}); err != nil {
[]time.Time{time.Now(), time.Now().Add(24 * time.Hour)},
[]uuid.UUID{uuid.New(), uuid.New()}); err != nil {
return fmt.Errorf("failed to insert a record with all non-null values using DML: %v", err)
}
fmt.Print("Inserted a test record with all non-null values\n")
Expand Down Expand Up @@ -121,8 +125,8 @@ func dataTypes(projectId, instanceId, databaseId string) error {
"SELECT * FROM AllTypes WHERE key=@key",
spannerdriver.ExecOptions{DecodeToNativeArrays: true},
1).Scan(
&r1.key, &r1.bool, &r1.string, &r1.bytes, &r1.int64, &r1.float32, &r1.float64, &r1.numeric, &r1.date, &r1.timestamp,
&r1.boolArray, &r1.stringArray, &r1.bytesArray, &r1.int64Array, &r1.float32Array, &r1.float64Array, &r1.numericArray, &r1.dateArray, &r1.timestampArray,
&r1.key, &r1.bool, &r1.string, &r1.bytes, &r1.int64, &r1.float32, &r1.float64, &r1.numeric, &r1.date, &r1.timestamp, &r1.uuid,
&r1.boolArray, &r1.stringArray, &r1.bytesArray, &r1.int64Array, &r1.float32Array, &r1.float64Array, &r1.numericArray, &r1.dateArray, &r1.timestampArray, &r1.uuidArray,
); err != nil {
return fmt.Errorf("failed to get row with non-null values: %v", err)
}
Expand All @@ -131,8 +135,8 @@ func dataTypes(projectId, instanceId, databaseId string) error {
// You can also use the spanner.Null* types to get data. These types can store both non-null and null values.
var r2 nullTypes
if err := db.QueryRowContext(ctx, "SELECT * FROM AllTypes WHERE key=@key", 1).Scan(
&r2.key, &r2.bool, &r2.string, &r2.bytes, &r2.int64, &r2.float32, &r2.float64, &r2.numeric, &r2.date, &r2.timestamp,
&r2.boolArray, &r2.stringArray, &r2.bytesArray, &r2.int64Array, &r2.float32Array, &r2.float64Array, &r2.numericArray, &r2.dateArray, &r2.timestampArray,
&r2.key, &r2.bool, &r2.string, &r2.bytes, &r2.int64, &r2.float32, &r2.float64, &r2.numeric, &r2.date, &r2.timestamp, &r2.uuid,
&r2.boolArray, &r2.stringArray, &r2.bytesArray, &r2.int64Array, &r2.float32Array, &r2.float64Array, &r2.numericArray, &r2.dateArray, &r2.timestampArray, &r2.uuidArray,
); err != nil {
return fmt.Errorf("failed to get row with null values: %v", err)
}
Expand All @@ -143,8 +147,8 @@ func dataTypes(projectId, instanceId, databaseId string) error {
// use spanner.NullNumeric and spanner.NullDate.
var r3 sqlNullTypes
if err := db.QueryRowContext(ctx, "SELECT * FROM AllTypes WHERE key=@key", 1).Scan(
&r3.key, &r3.bool, &r3.string, &r3.bytes, &r3.int64, &r3.float32, &r3.float64, &r3.numeric, &r3.date, &r3.timestamp,
&r3.boolArray, &r3.stringArray, &r3.bytesArray, &r3.int64Array, &r3.float32Array, &r3.float64Array, &r3.numericArray, &r3.dateArray, &r3.timestampArray,
&r3.key, &r3.bool, &r3.string, &r3.bytes, &r3.int64, &r3.float32, &r3.float64, &r3.numeric, &r3.date, &r3.timestamp, &r3.uuid,
&r3.boolArray, &r3.stringArray, &r3.bytesArray, &r3.int64Array, &r3.float32Array, &r3.float64Array, &r3.numericArray, &r3.dateArray, &r3.timestampArray, &r3.uuidArray,
); err != nil {
return fmt.Errorf("failed to get row with null values using Go sql null types: %v", err)
}
Expand All @@ -164,6 +168,7 @@ type nativeTypes struct {
numeric big.Rat
date civil.Date
timestamp time.Time
uuid uuid.UUID
// Array types use Null* types by default, because an array may always
// contain NULL elements in the array itself (even if the ARRAY column is
// defined as NOT NULL). The Spanner database/sql driver can also return
Expand All @@ -179,6 +184,7 @@ type nativeTypes struct {
numericArray []spanner.NullNumeric
dateArray []civil.Date
timestampArray []time.Time
uuidArray []uuid.UUID
}

type nullTypes struct {
Expand All @@ -192,6 +198,7 @@ type nullTypes struct {
numeric spanner.NullNumeric
date spanner.NullDate
timestamp spanner.NullTime
uuid spanner.NullUUID
boolArray []spanner.NullBool
stringArray []spanner.NullString
bytesArray [][]byte
Expand All @@ -201,6 +208,7 @@ type nullTypes struct {
numericArray []spanner.NullNumeric
dateArray []spanner.NullDate
timestampArray []spanner.NullTime
uuidArray []uuid.UUID
}

type sqlNullTypes struct {
Expand All @@ -214,6 +222,7 @@ type sqlNullTypes struct {
numeric spanner.NullNumeric // There is no sql.NullNumeric type
date spanner.NullDate // There is no sql.NullDate type
timestamp sql.NullTime
uuid spanner.NullUUID // There is no sql.NullUUID type
// Array types must always use the spanner.Null* structs.
boolArray []spanner.NullBool
stringArray []spanner.NullString
Expand All @@ -224,6 +233,7 @@ type sqlNullTypes struct {
numericArray []spanner.NullNumeric
dateArray []spanner.NullDate
timestampArray []spanner.NullTime
uuidArray []uuid.UUID
}

func main() {
Expand Down
27 changes: 23 additions & 4 deletions examples/emulator_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ import (
"os"
"time"

"cloud.google.com/go/spanner"
database "cloud.google.com/go/spanner/admin/database/apiv1"
databasepb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
"cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
instance "cloud.google.com/go/spanner/admin/instance/apiv1"
instancepb "cloud.google.com/go/spanner/admin/instance/apiv1/instancepb"
"cloud.google.com/go/spanner/admin/instance/apiv1/instancepb"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"google.golang.org/grpc/codes"
)

var cli *client.Client
Expand Down Expand Up @@ -69,6 +71,10 @@ func RunSampleOnEmulatorWithDialect(sample func(string, string, string) error, d
}

func startEmulator() error {
if os.Getenv("SPANNER_EMULATOR_HOST") != "" {
return nil
}

ctx := context.Background()
if err := os.Setenv("SPANNER_EMULATOR_HOST", "localhost:9010"); err != nil {
return err
Expand Down Expand Up @@ -130,7 +136,7 @@ func createInstance(projectId, instanceId string) error {
if err != nil {
return err
}
defer instanceAdmin.Close()
defer silentClose(instanceAdmin)
op, err := instanceAdmin.CreateInstance(ctx, &instancepb.CreateInstanceRequest{
Parent: fmt.Sprintf("projects/%s", projectId),
InstanceId: instanceId,
Expand All @@ -141,6 +147,9 @@ func createInstance(projectId, instanceId string) error {
},
})
if err != nil {
if spanner.ErrCode(err) == codes.AlreadyExists {
return nil
}
return fmt.Errorf("could not create instance %s: %v", fmt.Sprintf("projects/%s/instances/%s", projectId, instanceId), err)
}
// Wait for the instance creation to finish.
Expand All @@ -156,7 +165,13 @@ func createSampleDB(projectId, instanceId, databaseId string, dialect databasepb
if err != nil {
return err
}
defer databaseAdminClient.Close()
defer silentClose(databaseAdminClient)

// Drop the database if it already exists.
_ = databaseAdminClient.DropDatabase(ctx, &databasepb.DropDatabaseRequest{
Database: fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId),
})

var createStatement string
if dialect == databasepb.DatabaseDialect_POSTGRESQL {
createStatement = fmt.Sprintf(`CREATE DATABASE "%s"`, databaseId)
Expand Down Expand Up @@ -189,3 +204,7 @@ func stopEmulator() {
log.Printf("failed to stop emulator: %v\n", err)
}
}

func silentClose(c io.Closer) {
_ = c.Close()
}
Loading