http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/driver_phoenix_test.go
----------------------------------------------------------------------
diff --git a/driver_phoenix_test.go b/driver_phoenix_test.go
new file mode 100644
index 0000000..b33830b
--- /dev/null
+++ b/driver_phoenix_test.go
@@ -0,0 +1,1044 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package avatica
+
+import (
+       "bytes"
+       "crypto/sha256"
+       "database/sql"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "testing"
+       "time"
+
+       "github.com/apache/calcite-avatica-go/errors"
+)
+
+func skipTestIfNotPhoenix(t *testing.T) {
+
+       val := os.Getenv("AVATICA_FLAVOR")
+
+       if val != "PHOENIX" {
+               t.Skip("Skipping Apache Phoenix test")
+       }
+}
+
+func TestPhoenixConnectionMustBeOpenedWithAutoCommitTrue(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec("CREATE TABLE " + dbt.tableName + " (id BIGINT 
PRIMARY KEY, val VARCHAR) TRANSACTIONAL=false")
+
+               dbt.mustExec("UPSERT INTO " + dbt.tableName + " VALUES (1,'A')")
+
+               dbt.mustExec("UPSERT INTO " + dbt.tableName + " VALUES (2,'B')")
+
+               rows := dbt.mustQuery("SELECT COUNT(*) FROM " + dbt.tableName)
+               defer rows.Close()
+
+               for rows.Next() {
+
+                       var count int
+
+                       err := rows.Scan(&count)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+
+                       if count != 2 {
+                               dbt.Fatalf("There should be 2 rows, got %d", 
count)
+                       }
+               }
+
+       })
+}
+
+func TestPhoenixZeroValues(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec("CREATE TABLE " + dbt.tableName + " (int INTEGER 
PRIMARY KEY, flt FLOAT, bool BOOLEAN, str VARCHAR) TRANSACTIONAL=false")
+
+               dbt.mustExec("UPSERT INTO " + dbt.tableName + " VALUES (0, 0.0, 
false, '')")
+
+               rows := dbt.mustQuery("SELECT * FROM " + dbt.tableName)
+               defer rows.Close()
+
+               for rows.Next() {
+
+                       var i int
+                       var flt float64
+                       var b bool
+                       var s string
+
+                       err := rows.Scan(&i, &flt, &b, &s)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+
+                       if i != 0 {
+                               dbt.Fatalf("Integer should be 0, got %v", i)
+                       }
+
+                       if flt != 0.0 {
+                               dbt.Fatalf("Float should be 0.0, got %v", flt)
+                       }
+
+                       if b != false {
+                               dbt.Fatalf("Boolean should be false, got %v", b)
+                       }
+
+                       if s != "" {
+                               dbt.Fatalf("String should be \"\", got %v", s)
+                       }
+               }
+
+       })
+}
+
+func TestPhoenixDataTypes(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY,
+                               uint UNSIGNED_INT,
+                               bint BIGINT,
+                               ulong UNSIGNED_LONG,
+                               tint TINYINT,
+                               utint UNSIGNED_TINYINT,
+                               sint SMALLINT,
+                               usint UNSIGNED_SMALLINT,
+                               flt FLOAT,
+                               uflt UNSIGNED_FLOAT,
+                               dbl DOUBLE,
+                               udbl UNSIGNED_DOUBLE,
+                               dec DECIMAL,
+                               bool BOOLEAN,
+                               tm TIME,
+                               dt DATE,
+                               tmstmp TIMESTAMP,
+                               utm UNSIGNED_TIME,
+                               udt UNSIGNED_DATE,
+                               utmstmp UNSIGNED_TIMESTAMP,
+                               var VARCHAR,
+                               ch CHAR(3),
+                               bin BINARY(20),
+                               varbin VARBINARY
+                           ) TRANSACTIONAL=false`)
+
+               var (
+                       integerValue  int       = -20
+                       uintegerValue int       = 5
+                       bintValue     int       = -9223372036854775807
+                       ulongValue    int       = 9223372036854775807
+                       tintValue     int       = -128
+                       utintValue    int       = 126
+                       sintValue     int       = -32768
+                       usintValue    int       = 32767
+                       fltValue      float64   = -3.555
+                       ufltValue     float64   = 3.555
+                       dblValue      float64   = -9.555
+                       udblValue     float64   = 9.555
+                       decValue      string    = "1.333"
+                       booleanValue  bool      = true
+                       tmValue       time.Time = time.Date(0, 1, 1, 21, 21, 
21, 222000000, time.UTC)
+                       dtValue       time.Time = time.Date(2100, 2, 1, 0, 0, 
0, 0, time.UTC)
+                       tmstmpValue   time.Time = time.Date(2100, 2, 1, 21, 21, 
21, 222000000, time.UTC)
+                       utmValue      time.Time = time.Date(0, 1, 1, 21, 21, 
21, 222000000, time.UTC)
+                       udtValue      time.Time = time.Date(2100, 2, 1, 0, 0, 
0, 0, time.UTC)
+                       utmstmpValue  time.Time = time.Date(2100, 2, 1, 21, 21, 
21, 222000000, time.UTC)
+                       varcharValue  string    = "test string"
+                       chValue       string    = "a"
+                       binValue      []byte    = make([]byte, 20, 20)
+                       varbinValue   []byte    = []byte("testtesttest")
+               )
+
+               copy(binValue[:], []byte("test"))
+
+               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?, ?, ?, 
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+                       integerValue,
+                       uintegerValue,
+                       bintValue,
+                       ulongValue,
+                       tintValue,
+                       utintValue,
+                       sintValue,
+                       usintValue,
+                       fltValue,
+                       ufltValue,
+                       dblValue,
+                       udblValue,
+                       decValue,
+                       booleanValue,
+                       tmValue,
+                       dtValue,
+                       tmstmpValue,
+                       utmValue,
+                       udtValue,
+                       utmstmpValue,
+                       varcharValue,
+                       chValue,
+                       binValue,
+                       varbinValue,
+               )
+
+               rows := dbt.mustQuery("SELECT * FROM " + dbt.tableName)
+               defer rows.Close()
+
+               var (
+                       integer  int
+                       uinteger int
+                       bint     int
+                       ulong    int
+                       tint     int
+                       utint    int
+                       sint     int
+                       usint    int
+                       flt      float64
+                       uflt     float64
+                       dbl      float64
+                       udbl     float64
+                       dec      string
+                       boolean  bool
+                       tm       time.Time
+                       dt       time.Time
+                       tmstmp   time.Time
+                       utm      time.Time
+                       udt      time.Time
+                       utmstmp  time.Time
+                       varchar  string
+                       ch       string
+                       bin      []byte
+                       varbin   []byte
+               )
+
+               for rows.Next() {
+
+                       err := rows.Scan(&integer, &uinteger, &bint, &ulong, 
&tint, &utint, &sint, &usint, &flt, &uflt, &dbl, &udbl, &dec, &boolean, &tm, 
&dt, &tmstmp, &utm, &udt, &utmstmp, &varchar, &ch, &bin, &varbin)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               comparisons := []struct {
+                       result   interface{}
+                       expected interface{}
+               }{
+                       {integer, integerValue},
+                       {uinteger, uintegerValue},
+                       {bint, bintValue},
+                       {ulong, ulongValue},
+                       {tint, tintValue},
+                       {utint, utintValue},
+                       {sint, sintValue},
+                       {usint, usintValue},
+                       {flt, fltValue},
+                       {uflt, ufltValue},
+                       {dbl, dblValue},
+                       {udbl, udblValue},
+                       {dec, decValue},
+                       {boolean, booleanValue},
+                       {tm, tmValue},
+                       {dt, dtValue},
+                       {tmstmp, tmstmpValue},
+                       {utm, utmValue},
+                       {udt, udtValue},
+                       {utmstmp, utmstmpValue},
+                       {varchar, varcharValue},
+                       {ch, chValue},
+                       {bin, binValue},
+                       {varbin, varbinValue},
+               }
+
+               for _, tt := range comparisons {
+
+                       if v, ok := tt.expected.(time.Time); ok {
+
+                               if !v.Equal(tt.result.(time.Time)) {
+                                       dbt.Fatalf("Expected %v, got %v.", 
tt.expected, tt.result)
+                               }
+
+                       } else if v, ok := tt.expected.([]byte); ok {
+
+                               if !bytes.Equal(v, tt.result.([]byte)) {
+                                       dbt.Fatalf("Expected %v, got %v.", 
tt.expected, tt.result)
+                               }
+
+                       } else if tt.expected != tt.result {
+                               dbt.Errorf("Expected %v, got %v.", tt.expected, 
tt.result)
+                       }
+               }
+       })
+}
+
+func TestPhoenixLocations(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       query := "?location=Australia/Melbourne"
+
+       runTests(t, dsn+query, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               tm TIME PRIMARY KEY,
+                               dt DATE,
+                               tmstmp TIMESTAMP
+                           ) TRANSACTIONAL=false`)
+
+               loc, err := time.LoadLocation("Australia/Melbourne")
+
+               if err != nil {
+                       dbt.Fatalf("Unexpected error: %s", err)
+               }
+
+               var (
+                       tmValue     time.Time = time.Date(0, 1, 1, 21, 21, 21, 
222000000, loc)
+                       dtValue     time.Time = time.Date(2100, 2, 1, 0, 0, 0, 
0, loc)
+                       tmstmpValue time.Time = time.Date(2100, 2, 1, 21, 21, 
21, 222000000, loc)
+               )
+
+               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?, ?)`,
+                       tmValue,
+                       dtValue,
+                       tmstmpValue,
+               )
+
+               rows := dbt.mustQuery("SELECT * FROM " + dbt.tableName)
+               defer rows.Close()
+
+               var (
+                       tm     time.Time
+                       dt     time.Time
+                       tmstmp time.Time
+               )
+
+               for rows.Next() {
+
+                       err := rows.Scan(&tm, &dt, &tmstmp)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               comparisons := []struct {
+                       result   time.Time
+                       expected time.Time
+               }{
+                       {tm, tmValue},
+                       {dt, dtValue},
+                       {tmstmp, tmstmpValue},
+               }
+
+               for _, tt := range comparisons {
+
+                       if !tt.result.Equal(tt.expected) {
+                               dbt.Fatalf("Expected %v, got %v.", tt.expected, 
tt.result)
+                       }
+               }
+       })
+}
+
+func TestPhoenixDateAndTimestampsBefore1970(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY,
+                               dt DATE,
+                               tmstmp TIMESTAMP
+                           ) TRANSACTIONAL=false`)
+
+               var (
+                       integerValue int       = 1
+                       dtValue      time.Time = time.Date(1945, 5, 20, 0, 0, 
0, 0, time.UTC)
+                       tmstmpValue  time.Time = time.Date(1911, 5, 20, 21, 21, 
21, 222000000, time.UTC)
+               )
+
+               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?, ?)`,
+                       integerValue,
+                       dtValue,
+                       tmstmpValue,
+               )
+
+               rows := dbt.mustQuery("SELECT dt, tmstmp FROM " + dbt.tableName)
+               defer rows.Close()
+
+               var (
+                       dt     time.Time
+                       tmstmp time.Time
+               )
+
+               for rows.Next() {
+                       err := rows.Scan(&dt, &tmstmp)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               comparisons := []struct {
+                       result   time.Time
+                       expected time.Time
+               }{
+                       {dt, dtValue},
+                       {tmstmp, tmstmpValue},
+               }
+
+               for _, tt := range comparisons {
+                       if !tt.expected.Equal(tt.result) {
+                               dbt.Fatalf("Expected %v, got %v.", tt.expected, 
tt.result)
+                       }
+               }
+       })
+}
+
+func TestPhoenixStoreAndRetrieveBinaryData(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY,
+                               bin VARBINARY
+                           ) TRANSACTIONAL=false`)
+
+               filePath := filepath.Join("test-fixtures", "gopher.png")
+
+               file, err := ioutil.ReadFile(filePath)
+
+               if err != nil {
+                       t.Fatalf("Unable to read text-fixture: %s", filePath)
+               }
+
+               hash := sha256.Sum256(file)
+
+               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?)`,
+                       1,
+                       file,
+               )
+
+               rows := dbt.mustQuery("SELECT bin FROM " + dbt.tableName)
+               defer rows.Close()
+
+               var receivedFile []byte
+
+               for rows.Next() {
+
+                       err := rows.Scan(&receivedFile)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               ioutil.WriteFile("test-fixtures/gopher.png", receivedFile, 
os.ModePerm)
+
+               receivedHash := sha256.Sum256(receivedFile)
+
+               if !bytes.Equal(hash[:], receivedHash[:]) {
+                       t.Fatalf("Hash of stored file (%x) does not equal hash 
of retrieved file (%x).", hash[:], receivedHash[:])
+               }
+       })
+}
+
+func TestPhoenixCommittingTransactions(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       query := "?transactionIsolation=4"
+
+       runTests(t, dsn+query, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=true`)
+
+               tx, err := dbt.db.Begin()
+
+               if err != nil {
+                       t.Fatalf("Unable to create transaction: %s", err)
+               }
+
+               stmt, err := tx.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
+
+               if err != nil {
+                       t.Fatalf("Could not prepare statement: %s", err)
+               }
+
+               totalRows := 6
+
+               for i := 1; i <= totalRows; i++ {
+                       _, err := stmt.Exec(i)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               r := tx.QueryRow("SELECT COUNT(*) FROM " + dbt.tableName)
+
+               var count int
+
+               err = r.Scan(&count)
+
+               if err != nil {
+                       t.Fatalf("Unable to scan row result: %s", err)
+               }
+
+               if count != totalRows {
+                       t.Fatalf("Expected %d rows, got %d", totalRows, count)
+               }
+
+               // Commit the transaction
+               tx.Commit()
+
+               rows := dbt.mustQuery("SELECT COUNT(*) FROM " + dbt.tableName)
+
+               var countAfterRollback int
+
+               for rows.Next() {
+                       err := rows.Scan(&countAfterRollback)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               if countAfterRollback != totalRows {
+                       t.Fatalf("Expected %d rows, got %d", totalRows, 
countAfterRollback)
+               }
+       })
+}
+
+func TestPhoenixRollingBackTransactions(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       query := "?transactionIsolation=4"
+
+       runTests(t, dsn+query, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=true`)
+
+               tx, err := dbt.db.Begin()
+
+               if err != nil {
+                       t.Fatalf("Unable to create transaction: %s", err)
+               }
+
+               stmt, err := tx.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
+
+               if err != nil {
+                       t.Fatalf("Could not prepare statement: %s", err)
+               }
+
+               totalRows := 6
+
+               for i := 1; i <= totalRows; i++ {
+                       _, err := stmt.Exec(i)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               r := tx.QueryRow(`SELECT COUNT(*) FROM ` + dbt.tableName)
+
+               var count int
+
+               err = r.Scan(&count)
+
+               if err != nil {
+                       t.Fatalf("Unable to scan row result: %s", err)
+               }
+
+               if count != totalRows {
+                       t.Fatalf("Expected %d rows, got %d", totalRows, count)
+               }
+
+               // Rollback the transaction
+               tx.Rollback()
+
+               rows := dbt.mustQuery(`SELECT COUNT(*) FROM ` + dbt.tableName)
+
+               var countAfterRollback int
+
+               for rows.Next() {
+                       err := rows.Scan(&countAfterRollback)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               if countAfterRollback != 0 {
+                       t.Fatalf("Expected %d rows, got %d", 0, 
countAfterRollback)
+               }
+       })
+}
+
+func TestPhoenixPreparedStatements(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=false`)
+
+               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               totalRows := 6
+
+               for i := 1; i <= totalRows; i++ {
+                       _, err := stmt.Exec(i)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               queryStmt, err := dbt.db.Prepare(`SELECT * FROM ` + 
dbt.tableName + ` WHERE int = ?`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               var res int
+
+               for i := 1; i <= totalRows; i++ {
+
+                       err := queryStmt.QueryRow(i).Scan(&res)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+
+                       if res != i {
+                               dbt.Fatalf("Unexpected query result. Expected 
%d, got %d.", i, res)
+                       }
+               }
+       })
+}
+
+func TestPhoenixFetchingMoreRows(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       query := "?maxRowsTotal=-1&frameMaxSize=1"
+
+       runTests(t, dsn+query, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=false`)
+
+               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               totalRows := 6
+
+               for i := 1; i <= totalRows; i++ {
+                       _, err := stmt.Exec(i)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               rows := dbt.mustQuery(`SELECT * FROM ` + dbt.tableName)
+               defer rows.Close()
+
+               count := 0
+
+               for rows.Next() {
+                       count++
+               }
+
+               if count != totalRows {
+                       dbt.Fatalf("Expected %d rows to be retrieved, retrieved 
%d", totalRows, count)
+               }
+       })
+}
+
+func TestPhoenixExecuteShortcut(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=false`)
+
+               res, err := dbt.db.Exec(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(1)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               affected, err := res.RowsAffected()
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               if affected != 1 {
+                       dbt.Fatalf("Expected 1 row to be affected, %d 
affected", affected)
+               }
+       })
+}
+
+func TestPhoenixQueryShortcut(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       query := "?maxRowsTotal=-1&frameMaxSize=1"
+
+       runTests(t, dsn+query, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=false`)
+
+               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               totalRows := 6
+
+               for i := 1; i <= totalRows; i++ {
+                       _, err := stmt.Exec(i)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               rows := dbt.mustQuery(`SELECT * FROM ` + dbt.tableName)
+               defer rows.Close()
+
+               count := 0
+
+               for rows.Next() {
+                       count++
+               }
+
+               if count != totalRows {
+                       dbt.Fatalf("Expected %d rows to be retrieved, retrieved 
%d", totalRows, count)
+               }
+       })
+}
+
+func TestPhoenixOptimisticConcurrency(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       query := "?transactionIsolation=4"
+
+       runTests(t, dsn+query, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               id INTEGER PRIMARY KEY,
+                               msg VARCHAR,
+                               version INTEGER
+                           ) TRANSACTIONAL=true`)
+
+               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?, ?, ?)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               totalRows := 6
+
+               for i := 1; i <= totalRows; i++ {
+                       _, err := stmt.Exec(i, fmt.Sprintf("message version 
%d", i), i)
+
+                       if err != nil {
+                               dbt.Fatal(err)
+                       }
+               }
+
+               // Start the transactions
+               tx1, err := dbt.db.Begin()
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               tx2, err := dbt.db.Begin()
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               // Select from first transaction
+               _ = tx1.QueryRow(`SELECT MAX(version) FROM ` + dbt.tableName)
+
+               // Modify using second transaction
+               _, err = tx2.Exec(`UPSERT INTO `+dbt.tableName+` VALUES(?, ?, 
?)`, 7, "message value 7", 7)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               err = tx2.Commit()
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               // Modify using tx1
+               _, err = tx1.Exec(`UPSERT INTO `+dbt.tableName+` VALUES(?, ?, 
?)`, 7, "message value 7", 7)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               err = tx1.Commit()
+
+               if err == nil {
+                       dbt.Fatal("Expected an error, but did not receive any.")
+               }
+
+               errName := err.(errors.ResponseError).Name
+
+               if errName != "transaction_conflict_exception" {
+                       dbt.Fatal("Expected transaction_conflict")
+               }
+       })
+}
+
+func TestPhoenixLastInsertIDShouldReturnError(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       runTests(t, dsn, func(dbt *DBTest) {
+
+               dbt.mustExec(`DROP SEQUENCE IF EXISTS test_sequence`)
+
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               id INTEGER PRIMARY KEY,
+                               msg VARCHAR,
+                               version INTEGER
+                           ) TRANSACTIONAL=false`)
+
+               dbt.mustExec(`CREATE SEQUENCE test_sequence`)
+
+               res, err := dbt.db.Exec(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(NEXT VALUE FOR test_sequence, 'abc', 1)`)
+
+               dbt.mustExec(`DROP SEQUENCE test_sequence`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               _, err = res.LastInsertId()
+
+               if err == nil {
+                       dbt.Fatal("Expected an error as Avatica does not 
support LastInsertId(), but there was no error.")
+               }
+       })
+}
+
+func TestPhoenixSchemaSupport(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       db, err := sql.Open("avatica", dsn)
+
+       if err != nil {
+               t.Fatalf("error connecting: %s", err.Error())
+       }
+
+       defer db.Close()
+
+       _, err = db.Exec("CREATE SCHEMA IF NOT EXISTS avaticatest")
+
+       if err != nil {
+               t.Fatalf("error creating schema: %s", err)
+       }
+
+       defer db.Exec("DROP SCHEMA IF EXISTS avaticatest")
+
+       path := "/avaticatest"
+
+       runTests(t, dsn+path, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=false`)
+
+               defer dbt.mustExec(`DROP TABLE IF EXISTS ` + dbt.tableName)
+
+               _, err := dbt.db.Exec(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(1)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               rows := dbt.mustQuery(`SELECT * FROM avaticatest.` + 
dbt.tableName)
+               defer rows.Close()
+
+               count := 0
+
+               for rows.Next() {
+                       count++
+               }
+
+               if count != 1 {
+                       dbt.Errorf("Expected 1 row, got %d rows back,", count)
+               }
+       })
+}
+
+func TestPhoenixMultipleSchemaSupport(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       db, err := sql.Open("avatica", dsn)
+
+       if err != nil {
+               t.Fatalf("error connecting: %s", err.Error())
+       }
+
+       defer db.Close()
+
+       _, err = db.Exec("CREATE SCHEMA IF NOT EXISTS avaticatest1")
+
+       if err != nil {
+               t.Fatalf("error creating schema: %s", err)
+       }
+
+       defer db.Exec("DROP SCHEMA IF EXISTS avaticatest1")
+
+       _, err = db.Exec("CREATE SCHEMA IF NOT EXISTS avaticatest2")
+
+       if err != nil {
+               t.Fatalf("error creating schema: %s", err)
+       }
+
+       defer db.Exec("DROP SCHEMA IF EXISTS avaticatest2")
+
+       path := "/avaticatest1"
+
+       runTests(t, dsn+path, func(dbt *DBTest) {
+
+               // Create and seed table
+               dbt.mustExec(`CREATE TABLE avaticatest2.` + dbt.tableName + ` (
+                               int INTEGER PRIMARY KEY
+                           ) TRANSACTIONAL=false`)
+
+               defer dbt.mustExec(`DROP TABLE IF EXISTS avaticatest2.` + 
dbt.tableName)
+
+               _, err := dbt.db.Exec(`UPSERT INTO avaticatest2.` + 
dbt.tableName + ` VALUES(1)`)
+
+               if err != nil {
+                       dbt.Fatal(err)
+               }
+
+               rows := dbt.mustQuery(`SELECT * FROM avaticatest2.` + 
dbt.tableName)
+               defer rows.Close()
+
+               count := 0
+
+               for rows.Next() {
+                       count++
+               }
+
+               if count != 1 {
+                       dbt.Errorf("Expected 1 row, got %d rows back,", count)
+               }
+       })
+}
+
+func TestPhoenixErrorCodeParsing(t *testing.T) {
+
+       skipTestIfNotPhoenix(t)
+
+       db, err := sql.Open("avatica", dsn)
+
+       if err != nil {
+               t.Fatalf("error connecting: %s", err.Error())
+       }
+
+       defer db.Close()
+
+       _, err = db.Query("SELECT * FROM table_that_does_not_exist")
+
+       if err == nil {
+               t.Error("Expected error due to selecting from non-existent 
table, but there was no error.")
+       }
+
+       resErr, ok := err.(errors.ResponseError)
+
+       if !ok {
+               t.Fatalf("Error type was not ResponseError")
+       }
+
+       if resErr.ErrorCode != 1012 {
+               t.Errorf("Expected error code to be %d, got %d.", 1012, 
resErr.ErrorCode)
+       }
+
+       if resErr.SqlState != "42M03" {
+               t.Errorf("Expected SQL state to be %s, got %s.", "42M03", 
resErr.SqlState)
+       }
+}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/driver_test.go
----------------------------------------------------------------------
diff --git a/driver_test.go b/driver_test.go
index 2d0f8b0..39f648a 100644
--- a/driver_test.go
+++ b/driver_test.go
@@ -18,16 +18,12 @@
 package avatica
 
 import (
-       "bytes"
        "context"
-       "crypto/sha256"
        "database/sql"
        "fmt"
-       "io/ioutil"
        "math/rand"
        "net/http"
        "os"
-       "path/filepath"
        "testing"
        "time"
 )
@@ -46,9 +42,19 @@ func init() {
                return defaultValue
        }
 
-       dsn = env("AVATICA_HOST", "http://phoenix:8765";)
+       var serverAddr string
 
-       // Wait for the phoenix server to be ready
+       if val := os.Getenv("AVATICA_FLAVOR"); val == "PHOENIX" {
+               serverAddr = env("PHOENIX_HOST", "http://phoenix:8765";)
+       } else if val == "HSQLDB" {
+               serverAddr = env("HSQLDB_HOST", "http://hsqldb:8765";)
+       } else {
+               panic("The AVATICA_FLAVOR environment variable should be either 
PHOENIX or HSQLDB")
+       }
+
+       dsn = serverAddr
+
+       // Wait for the avatica server to be ready
        ctx, _ := context.WithTimeout(context.Background(), 5*time.Minute)
        ticker := time.NewTicker(2 * time.Second)
 
@@ -56,10 +62,10 @@ func init() {
 
                select {
                case <-ctx.Done():
-                       panic("Timed out while waiting for the phoenix server 
to be ready after 5 minutes.")
+                       panic("Timed out while waiting for the avatica server 
to be ready after 5 minutes.")
 
                case <-ticker.C:
-                       resp, err := http.Get(dsn)
+                       resp, err := http.Get(serverAddr)
 
                        if err == nil {
                                resp.Body.Close()
@@ -131,837 +137,6 @@ func runTests(t *testing.T, dsn string, tests ...func(dbt 
*DBTest)) {
        }
 }
 
-func TestConnectionMustBeOpenedWithAutoCommitTrue(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec("CREATE TABLE " + dbt.tableName + " (id BIGINT 
PRIMARY KEY, val VARCHAR) TRANSACTIONAL=false")
-
-               dbt.mustExec("UPSERT INTO " + dbt.tableName + " VALUES (1,'A')")
-
-               dbt.mustExec("UPSERT INTO " + dbt.tableName + " VALUES (2,'B')")
-
-               rows := dbt.mustQuery("SELECT COUNT(*) FROM " + dbt.tableName)
-               defer rows.Close()
-
-               for rows.Next() {
-
-                       var count int
-
-                       err := rows.Scan(&count)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-
-                       if count != 2 {
-                               dbt.Fatalf("There should be 2 rows, got %d", 
count)
-                       }
-               }
-
-       })
-}
-
-func TestZeroValues(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec("CREATE TABLE " + dbt.tableName + " (int INTEGER 
PRIMARY KEY, flt FLOAT, bool BOOLEAN, str VARCHAR) TRANSACTIONAL=false")
-
-               dbt.mustExec("UPSERT INTO " + dbt.tableName + " VALUES (0, 0.0, 
false, '')")
-
-               rows := dbt.mustQuery("SELECT * FROM " + dbt.tableName)
-               defer rows.Close()
-
-               for rows.Next() {
-
-                       var i int
-                       var flt float64
-                       var b bool
-                       var s string
-
-                       err := rows.Scan(&i, &flt, &b, &s)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-
-                       if i != 0 {
-                               dbt.Fatalf("Integer should be 0, got %v", i)
-                       }
-
-                       if flt != 0.0 {
-                               dbt.Fatalf("Float should be 0.0, got %v", flt)
-                       }
-
-                       if b != false {
-                               dbt.Fatalf("Boolean should be false, got %v", b)
-                       }
-
-                       if s != "" {
-                               dbt.Fatalf("String should be \"\", got %v", s)
-                       }
-               }
-
-       })
-}
-
-func TestDataTypes(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY,
-                               uint UNSIGNED_INT,
-                               bint BIGINT,
-                               ulong UNSIGNED_LONG,
-                               tint TINYINT,
-                               utint UNSIGNED_TINYINT,
-                               sint SMALLINT,
-                               usint UNSIGNED_SMALLINT,
-                               flt FLOAT,
-                               uflt UNSIGNED_FLOAT,
-                               dbl DOUBLE,
-                               udbl UNSIGNED_DOUBLE,
-                               dec DECIMAL,
-                               bool BOOLEAN,
-                               tm TIME,
-                               dt DATE,
-                               tmstmp TIMESTAMP,
-                               utm UNSIGNED_TIME,
-                               udt UNSIGNED_DATE,
-                               utmstmp UNSIGNED_TIMESTAMP,
-                               var VARCHAR,
-                               ch CHAR(3),
-                               bin BINARY(20),
-                               varbin VARBINARY
-                           ) TRANSACTIONAL=false`)
-
-               var (
-                       integerValue  int       = -20
-                       uintegerValue int       = 5
-                       bintValue     int       = -9223372036854775807
-                       ulongValue    int       = 9223372036854775807
-                       tintValue     int       = -128
-                       utintValue    int       = 126
-                       sintValue     int       = -32768
-                       usintValue    int       = 32767
-                       fltValue      float64   = -3.555
-                       ufltValue     float64   = 3.555
-                       dblValue      float64   = -9.555
-                       udblValue     float64   = 9.555
-                       decValue      string    = "1.333"
-                       booleanValue  bool      = true
-                       tmValue       time.Time = time.Date(0, 1, 1, 21, 21, 
21, 222000000, time.UTC)
-                       dtValue       time.Time = time.Date(2100, 2, 1, 0, 0, 
0, 0, time.UTC)
-                       tmstmpValue   time.Time = time.Date(2100, 2, 1, 21, 21, 
21, 222000000, time.UTC)
-                       utmValue      time.Time = time.Date(0, 1, 1, 21, 21, 
21, 222000000, time.UTC)
-                       udtValue      time.Time = time.Date(2100, 2, 1, 0, 0, 
0, 0, time.UTC)
-                       utmstmpValue  time.Time = time.Date(2100, 2, 1, 21, 21, 
21, 222000000, time.UTC)
-                       varcharValue  string    = "test string"
-                       chValue       string    = "a"
-                       binValue      []byte    = make([]byte, 20, 20)
-                       varbinValue   []byte    = []byte("testtesttest")
-               )
-
-               copy(binValue[:], []byte("test"))
-
-               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?, ?, ?, 
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
-                       integerValue,
-                       uintegerValue,
-                       bintValue,
-                       ulongValue,
-                       tintValue,
-                       utintValue,
-                       sintValue,
-                       usintValue,
-                       fltValue,
-                       ufltValue,
-                       dblValue,
-                       udblValue,
-                       decValue,
-                       booleanValue,
-                       tmValue,
-                       dtValue,
-                       tmstmpValue,
-                       utmValue,
-                       udtValue,
-                       utmstmpValue,
-                       varcharValue,
-                       chValue,
-                       binValue,
-                       varbinValue,
-               )
-
-               rows := dbt.mustQuery("SELECT * FROM " + dbt.tableName)
-               defer rows.Close()
-
-               var (
-                       integer  int
-                       uinteger int
-                       bint     int
-                       ulong    int
-                       tint     int
-                       utint    int
-                       sint     int
-                       usint    int
-                       flt      float64
-                       uflt     float64
-                       dbl      float64
-                       udbl     float64
-                       dec      string
-                       boolean  bool
-                       tm       time.Time
-                       dt       time.Time
-                       tmstmp   time.Time
-                       utm      time.Time
-                       udt      time.Time
-                       utmstmp  time.Time
-                       varchar  string
-                       ch       string
-                       bin      []byte
-                       varbin   []byte
-               )
-
-               for rows.Next() {
-
-                       err := rows.Scan(&integer, &uinteger, &bint, &ulong, 
&tint, &utint, &sint, &usint, &flt, &uflt, &dbl, &udbl, &dec, &boolean, &tm, 
&dt, &tmstmp, &utm, &udt, &utmstmp, &varchar, &ch, &bin, &varbin)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               comparisons := []struct {
-                       result   interface{}
-                       expected interface{}
-               }{
-                       {integer, integerValue},
-                       {uinteger, uintegerValue},
-                       {bint, bintValue},
-                       {ulong, ulongValue},
-                       {tint, tintValue},
-                       {utint, utintValue},
-                       {sint, sintValue},
-                       {usint, usintValue},
-                       {flt, fltValue},
-                       {uflt, ufltValue},
-                       {dbl, dblValue},
-                       {udbl, udblValue},
-                       {dec, decValue},
-                       {boolean, booleanValue},
-                       {tm, tmValue},
-                       {dt, dtValue},
-                       {tmstmp, tmstmpValue},
-                       {utm, utmValue},
-                       {udt, udtValue},
-                       {utmstmp, utmstmpValue},
-                       {varchar, varcharValue},
-                       {ch, chValue},
-                       {bin, binValue},
-                       {varbin, varbinValue},
-               }
-
-               for _, tt := range comparisons {
-
-                       if v, ok := tt.expected.(time.Time); ok {
-
-                               if !v.Equal(tt.result.(time.Time)) {
-                                       dbt.Fatalf("Expected %v, got %v.", 
tt.expected, tt.result)
-                               }
-
-                       } else if v, ok := tt.expected.([]byte); ok {
-
-                               if !bytes.Equal(v, tt.result.([]byte)) {
-                                       dbt.Fatalf("Expected %v, got %v.", 
tt.expected, tt.result)
-                               }
-
-                       } else if tt.expected != tt.result {
-
-                               dbt.Fatalf("Expected %v, got %v.", tt.expected, 
tt.result)
-                       }
-               }
-       })
-}
-
-func TestLocations(t *testing.T) {
-
-       query := "?location=Australia/Melbourne"
-
-       runTests(t, dsn+query, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               tm TIME PRIMARY KEY,
-                               dt DATE,
-                               tmstmp TIMESTAMP
-                           ) TRANSACTIONAL=false`)
-
-               loc, err := time.LoadLocation("Australia/Melbourne")
-
-               if err != nil {
-                       dbt.Fatalf("Unexpected error: %s", err)
-               }
-
-               var (
-                       tmValue     time.Time = time.Date(0, 1, 1, 21, 21, 21, 
222000000, loc)
-                       dtValue     time.Time = time.Date(2100, 2, 1, 0, 0, 0, 
0, loc)
-                       tmstmpValue time.Time = time.Date(2100, 2, 1, 21, 21, 
21, 222000000, loc)
-               )
-
-               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?, ?)`,
-                       tmValue,
-                       dtValue,
-                       tmstmpValue,
-               )
-
-               rows := dbt.mustQuery("SELECT * FROM " + dbt.tableName)
-               defer rows.Close()
-
-               var (
-                       tm     time.Time
-                       dt     time.Time
-                       tmstmp time.Time
-               )
-
-               for rows.Next() {
-
-                       err := rows.Scan(&tm, &dt, &tmstmp)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               comparisons := []struct {
-                       result   time.Time
-                       expected time.Time
-               }{
-                       {tm, tmValue},
-                       {dt, dtValue},
-                       {tmstmp, tmstmpValue},
-               }
-
-               for _, tt := range comparisons {
-
-                       if !tt.result.Equal(tt.expected) {
-                               dbt.Fatalf("Expected %v, got %v.", tt.expected, 
tt.result)
-                       }
-               }
-       })
-}
-
-func TestDateAndTimestampsBefore1970(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY,
-                               dt DATE,
-                               tmstmp TIMESTAMP
-                           ) TRANSACTIONAL=false`)
-
-               var (
-                       integerValue int       = 1
-                       dtValue      time.Time = time.Date(1945, 5, 20, 0, 0, 
0, 0, time.UTC)
-                       tmstmpValue  time.Time = time.Date(1911, 5, 20, 21, 21, 
21, 222000000, time.UTC)
-               )
-
-               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?, ?)`,
-                       integerValue,
-                       dtValue,
-                       tmstmpValue,
-               )
-
-               rows := dbt.mustQuery("SELECT dt, tmstmp FROM " + dbt.tableName)
-               defer rows.Close()
-
-               var (
-                       dt     time.Time
-                       tmstmp time.Time
-               )
-
-               for rows.Next() {
-                       err := rows.Scan(&dt, &tmstmp)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               comparisons := []struct {
-                       result   time.Time
-                       expected time.Time
-               }{
-                       {dt, dtValue},
-                       {tmstmp, tmstmpValue},
-               }
-
-               for _, tt := range comparisons {
-                       if !tt.expected.Equal(tt.result) {
-                               dbt.Fatalf("Expected %v, got %v.", tt.expected, 
tt.result)
-                       }
-               }
-       })
-}
-
-func TestStoreAndRetrieveBinaryData(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY,
-                               bin VARBINARY
-                           ) TRANSACTIONAL=false`)
-
-               filePath := filepath.Join("test-fixtures", "gopher.png")
-
-               file, err := ioutil.ReadFile(filePath)
-
-               if err != nil {
-                       t.Fatalf("Unable to read text-fixture: %s", filePath)
-               }
-
-               hash := sha256.Sum256(file)
-
-               dbt.mustExec(`UPSERT INTO `+dbt.tableName+` VALUES (?, ?)`,
-                       1,
-                       file,
-               )
-
-               rows := dbt.mustQuery("SELECT bin FROM " + dbt.tableName)
-               defer rows.Close()
-
-               var receivedFile []byte
-
-               for rows.Next() {
-
-                       err := rows.Scan(&receivedFile)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               ioutil.WriteFile("test-fixtures/gopher.png", receivedFile, 
os.ModePerm)
-
-               receivedHash := sha256.Sum256(receivedFile)
-
-               if !bytes.Equal(hash[:], receivedHash[:]) {
-                       t.Fatalf("Hash of stored file (%x) does not equal hash 
of retrieved file (%x).", hash[:], receivedHash[:])
-               }
-       })
-}
-
-func TestCommittingTransactions(t *testing.T) {
-
-       query := "?transactionIsolation=4"
-
-       runTests(t, dsn+query, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=true`)
-
-               tx, err := dbt.db.Begin()
-
-               if err != nil {
-                       t.Fatalf("Unable to create transaction: %s", err)
-               }
-
-               stmt, err := tx.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
-
-               if err != nil {
-                       t.Fatalf("Could not prepare statement: %s", err)
-               }
-
-               totalRows := 6
-
-               for i := 1; i <= totalRows; i++ {
-                       _, err := stmt.Exec(i)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               r := tx.QueryRow("SELECT COUNT(*) FROM " + dbt.tableName)
-
-               var count int
-
-               err = r.Scan(&count)
-
-               if err != nil {
-                       t.Fatalf("Unable to scan row result: %s", err)
-               }
-
-               if count != totalRows {
-                       t.Fatalf("Expected %d rows, got %d", totalRows, count)
-               }
-
-               // Commit the transaction
-               tx.Commit()
-
-               rows := dbt.mustQuery("SELECT COUNT(*) FROM " + dbt.tableName)
-
-               var countAfterRollback int
-
-               for rows.Next() {
-                       err := rows.Scan(&countAfterRollback)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               if countAfterRollback != totalRows {
-                       t.Fatalf("Expected %d rows, got %d", totalRows, 
countAfterRollback)
-               }
-       })
-}
-
-func TestRollingBackTransactions(t *testing.T) {
-
-       query := "?transactionIsolation=4"
-
-       runTests(t, dsn+query, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=true`)
-
-               tx, err := dbt.db.Begin()
-
-               if err != nil {
-                       t.Fatalf("Unable to create transaction: %s", err)
-               }
-
-               stmt, err := tx.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
-
-               if err != nil {
-                       t.Fatalf("Could not prepare statement: %s", err)
-               }
-
-               totalRows := 6
-
-               for i := 1; i <= totalRows; i++ {
-                       _, err := stmt.Exec(i)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               r := tx.QueryRow(`SELECT COUNT(*) FROM ` + dbt.tableName)
-
-               var count int
-
-               err = r.Scan(&count)
-
-               if err != nil {
-                       t.Fatalf("Unable to scan row result: %s", err)
-               }
-
-               if count != totalRows {
-                       t.Fatalf("Expected %d rows, got %d", totalRows, count)
-               }
-
-               // Rollback the transaction
-               tx.Rollback()
-
-               rows := dbt.mustQuery(`SELECT COUNT(*) FROM ` + dbt.tableName)
-
-               var countAfterRollback int
-
-               for rows.Next() {
-                       err := rows.Scan(&countAfterRollback)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               if countAfterRollback != 0 {
-                       t.Fatalf("Expected %d rows, got %d", 0, 
countAfterRollback)
-               }
-       })
-}
-
-func TestPreparedStatements(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=false`)
-
-               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               totalRows := 6
-
-               for i := 1; i <= totalRows; i++ {
-                       _, err := stmt.Exec(i)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               queryStmt, err := dbt.db.Prepare(`SELECT * FROM ` + 
dbt.tableName + ` WHERE int = ?`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               var res int
-
-               for i := 1; i <= totalRows; i++ {
-
-                       err := queryStmt.QueryRow(i).Scan(&res)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-
-                       if res != i {
-                               dbt.Fatalf("Unexpected query result. Expected 
%d, got %d.", i, res)
-                       }
-               }
-       })
-}
-
-func TestFetchingMoreRows(t *testing.T) {
-
-       query := "?maxRowsTotal=-1&frameMaxSize=1"
-
-       runTests(t, dsn+query, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=false`)
-
-               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               totalRows := 6
-
-               for i := 1; i <= totalRows; i++ {
-                       _, err := stmt.Exec(i)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               rows := dbt.mustQuery(`SELECT * FROM ` + dbt.tableName)
-               defer rows.Close()
-
-               count := 0
-
-               for rows.Next() {
-                       count++
-               }
-
-               if count != totalRows {
-                       dbt.Fatalf("Expected %d rows to be retrieved, retrieved 
%d", totalRows, count)
-               }
-       })
-}
-
-func TestExecuteShortcut(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=false`)
-
-               res, err := dbt.db.Exec(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(1)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               affected, err := res.RowsAffected()
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               if affected != 1 {
-                       dbt.Fatalf("Expected 1 row to be affected, %d 
affected", affected)
-               }
-       })
-}
-
-func TestQueryShortcut(t *testing.T) {
-
-       query := "?maxRowsTotal=-1&frameMaxSize=1"
-
-       runTests(t, dsn+query, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=false`)
-
-               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               totalRows := 6
-
-               for i := 1; i <= totalRows; i++ {
-                       _, err := stmt.Exec(i)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               rows := dbt.mustQuery(`SELECT * FROM ` + dbt.tableName)
-               defer rows.Close()
-
-               count := 0
-
-               for rows.Next() {
-                       count++
-               }
-
-               if count != totalRows {
-                       dbt.Fatalf("Expected %d rows to be retrieved, retrieved 
%d", totalRows, count)
-               }
-       })
-}
-
-func TestOptimisticConcurrency(t *testing.T) {
-
-       query := "?transactionIsolation=4"
-
-       runTests(t, dsn+query, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               id INTEGER PRIMARY KEY,
-                               msg VARCHAR,
-                               version INTEGER
-                           ) TRANSACTIONAL=true`)
-
-               stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(?, ?, ?)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               totalRows := 6
-
-               for i := 1; i <= totalRows; i++ {
-                       _, err := stmt.Exec(i, fmt.Sprintf("message version 
%d", i), i)
-
-                       if err != nil {
-                               dbt.Fatal(err)
-                       }
-               }
-
-               // Start the transactions
-               tx1, err := dbt.db.Begin()
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               tx2, err := dbt.db.Begin()
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               // Select from first transaction
-               _ = tx1.QueryRow(`SELECT MAX(version) FROM ` + dbt.tableName)
-
-               // Modify using second transaction
-               _, err = tx2.Exec(`UPSERT INTO `+dbt.tableName+` VALUES(?, ?, 
?)`, 7, "message value 7", 7)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               err = tx2.Commit()
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               // Modify using tx1
-               _, err = tx1.Exec(`UPSERT INTO `+dbt.tableName+` VALUES(?, ?, 
?)`, 7, "message value 7", 7)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               err = tx1.Commit()
-
-               if err == nil {
-                       dbt.Fatal("Expected an error, but did not receive any.")
-               }
-
-               errName := err.(ResponseError).Name()
-
-               if errName != "transaction_conflict_exception" {
-                       dbt.Fatal("Expected transaction_conflict")
-               }
-       })
-}
-
-func TestLastInsertIDShouldReturnError(t *testing.T) {
-
-       runTests(t, dsn, func(dbt *DBTest) {
-
-               dbt.mustExec(`DROP SEQUENCE IF EXISTS test_sequence`)
-
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               id INTEGER PRIMARY KEY,
-                               msg VARCHAR,
-                               version INTEGER
-                           ) TRANSACTIONAL=false`)
-
-               dbt.mustExec(`CREATE SEQUENCE test_sequence`)
-
-               res, err := dbt.db.Exec(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(NEXT VALUE FOR test_sequence, 'abc', 1)`)
-
-               dbt.mustExec(`DROP SEQUENCE test_sequence`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               _, err = res.LastInsertId()
-
-               if err == nil {
-                       dbt.Fatal("Expected an error as Avatica does not 
support LastInsertId(), but there was no error.")
-               }
-       })
-}
-
 func TestConnectionToInvalidServerShouldReturnError(t *testing.T) {
 
        runTests(t, "http://invalid-server:8765";, func(dbt *DBTest) {
@@ -976,127 +151,3 @@ func TestConnectionToInvalidServerShouldReturnError(t 
*testing.T) {
                }
        })
 }
-
-func TestSchemaSupport(t *testing.T) {
-
-       db, err := sql.Open("avatica", dsn)
-
-       if err != nil {
-               t.Fatalf("error connecting: %s", err.Error())
-       }
-
-       defer db.Close()
-
-       db.Exec("CREATE SCHEMA IF NOT EXISTS avaticatest")
-       defer db.Exec("DROP SCHEMA IF EXISTS avaticatest")
-
-       path := "/avaticatest"
-
-       runTests(t, dsn+path, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=false`)
-
-               defer dbt.mustExec(`DROP TABLE IF EXISTS ` + dbt.tableName)
-
-               _, err := dbt.db.Exec(`UPSERT INTO ` + dbt.tableName + ` 
VALUES(1)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               rows := dbt.mustQuery(`SELECT * FROM avaticatest.` + 
dbt.tableName)
-               defer rows.Close()
-
-               count := 0
-
-               for rows.Next() {
-                       count++
-               }
-
-               if count != 1 {
-                       dbt.Errorf("Expected 1 row, got %d rows back,", count)
-               }
-       })
-}
-
-func TestMultipleSchemaSupport(t *testing.T) {
-
-       db, err := sql.Open("avatica", dsn)
-
-       if err != nil {
-               t.Fatalf("error connecting: %s", err.Error())
-       }
-
-       defer db.Close()
-
-       db.Exec("CREATE SCHEMA IF NOT EXISTS avaticatest1")
-       defer db.Exec("DROP SCHEMA IF EXISTS avaticatest1")
-
-       db.Exec("CREATE SCHEMA IF NOT EXISTS avaticatest2")
-       defer db.Exec("DROP SCHEMA IF EXISTS avaticatest2")
-
-       path := "/avaticatest1"
-
-       runTests(t, dsn+path, func(dbt *DBTest) {
-
-               // Create and seed table
-               dbt.mustExec(`CREATE TABLE avaticatest2.` + dbt.tableName + ` (
-                               int INTEGER PRIMARY KEY
-                           ) TRANSACTIONAL=false`)
-
-               defer dbt.mustExec(`DROP TABLE IF EXISTS avaticatest2.` + 
dbt.tableName)
-
-               _, err := dbt.db.Exec(`UPSERT INTO avaticatest2.` + 
dbt.tableName + ` VALUES(1)`)
-
-               if err != nil {
-                       dbt.Fatal(err)
-               }
-
-               rows := dbt.mustQuery(`SELECT * FROM avaticatest2.` + 
dbt.tableName)
-               defer rows.Close()
-
-               count := 0
-
-               for rows.Next() {
-                       count++
-               }
-
-               if count != 1 {
-                       dbt.Errorf("Expected 1 row, got %d rows back,", count)
-               }
-       })
-}
-
-func TestErrorCodeParsing(t *testing.T) {
-
-       db, err := sql.Open("avatica", dsn)
-
-       if err != nil {
-               t.Fatalf("error connecting: %s", err.Error())
-       }
-
-       defer db.Close()
-
-       _, err = db.Query("SELECT * FROM table_that_does_not_exist")
-
-       if err == nil {
-               t.Error("Expected error due to selecting from non-existent 
table, but there was no error.")
-       }
-
-       resErr, ok := err.(ResponseError)
-
-       if !ok {
-               t.Fatalf("Error type was not ResponseError")
-       }
-
-       if resErr.ErrorCode != 1012 {
-               t.Errorf("Expected error code to be %d, got %d.", 1012, 
resErr.ErrorCode)
-       }
-
-       if resErr.SqlState != "42M03" {
-               t.Errorf("Expected SQL state to be %s, got %s.", "42M03", 
resErr.SqlState)
-       }
-}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/errors.go
----------------------------------------------------------------------
diff --git a/errors.go b/errors.go
deleted file mode 100644
index 16a842a..0000000
--- a/errors.go
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package avatica
-
-import (
-       "regexp"
-       "strconv"
-
-       "github.com/apache/calcite-avatica-go/message"
-)
-
-// Error severity codes
-const (
-       Eunknown int8 = iota
-       Efatal
-       Eerror
-       Ewarning
-)
-
-// RPCMetadata contains metadata about the call that caused the error.
-type RPCMetadata struct {
-       ServerAddress string
-}
-
-// ErrorCode represents the error code returned by the avatica server
-type ErrorCode uint32
-
-// SQLState represents the SQL code returned by the avatica server
-type SQLState string
-
-// ResponseError is an error type that contains detailed information on
-// what caused the server to return an error.
-type ResponseError struct {
-       Exceptions    []string
-       HasExceptions bool
-       ErrorMessage  string
-       Severity      int8
-       ErrorCode     ErrorCode
-       SqlState      SQLState
-       Metadata      *RPCMetadata
-}
-
-func (r ResponseError) Error() string {
-
-       msg := "An error was encountered while processing your request"
-
-       if r.ErrorMessage != "" {
-               msg += ": " + r.ErrorMessage
-       } else if len(r.Exceptions) > 0 {
-               msg += ":\n" + r.Exceptions[0]
-       }
-
-       return msg
-}
-
-// Name returns the name of the error encountered by the server.
-func (r ResponseError) Name() string {
-       return errorCodeNames[r.ErrorCode]
-}
-
-// errorResponseToReponseError converts an error protocol buffer response
-// to a native golang error.
-func errorResponseToResponseError(message *message.ErrorResponse) 
ResponseError {
-
-       var (
-               errorCode int
-               sqlState  string
-       )
-
-       re := regexp.MustCompile(`ERROR (\d+) \(([0-9a-zA-Z]+)\)`)
-       codes := re.FindStringSubmatch(message.ErrorMessage)
-
-       if len(codes) > 1 {
-               errorCode, _ = strconv.Atoi(codes[1])
-       }
-
-       if len(codes) > 2 {
-               sqlState = codes[2]
-       }
-
-       err := ResponseError{
-               Exceptions:   message.Exceptions,
-               ErrorMessage: message.ErrorMessage,
-               Severity:     int8(message.Severity),
-               ErrorCode:    ErrorCode(errorCode),
-               SqlState:     SQLState(sqlState),
-               Metadata: &RPCMetadata{
-                       ServerAddress: message.GetMetadata().ServerAddress,
-               },
-       }
-
-       return err
-}
-
-var errorCodeNames = map[ErrorCode]string{
-       // Connection exceptions (errorcode 01, sqlstate 08)
-       101: "io_exception",
-       102: "malformed_connection_url",
-       103: "cannot_establish_connection",
-
-       // Data exceptions (errorcode 02, sqlstate 22)
-       201: "illegal_data",
-       202: "divide_by_zero",
-       203: "type_mismatch",
-       204: "value_in_upsert_not_constant",
-       205: "malformed_url",
-       206: "data_exceeds_max_capacity",
-       207: "missing_max_length",
-       208: "nonpositive_max_length",
-       209: "decimal_precision_out_of_range",
-       212: "server_arithmetic_error",
-       213: "value_outside_range",
-       214: "value_in_list_not_constant",
-       215: "single_row_subquery_returns_multiple_rows",
-       216: "subquery_returns_different_number_of_fields",
-       217: "ambiguous_join_condition",
-       218: "constraint_violation",
-
-       301: "concurrent_table_mutation",
-       302: "cannot_index_column_on_type",
-
-       // Invalid cursor state (errorcode 04, sqlstate 24)
-       401: "cursor_before_first_row",
-       402: "cursor_past_last_row",
-
-       // Syntax error or access rule violation (errorcode 05, sqlstate 42)
-       501: "ambiguous_table",
-       502: "ambiguous_column",
-       503: "index_missing_pk_columns",
-       504: "column_not_found",
-       505: "read_only_table",
-       506: "cannot_drop_pk",
-       509: "primary_key_missing",
-       510: "primary_key_already_exists",
-       511: "order_by_not_in_select_distinct",
-       512: "invalid_primary_key_constraint",
-       513: "array_not_allowed_in_primary_key",
-       514: "column_exist_in_def",
-       515: "order_by_array_not_supported",
-       516: "non_equality_array_comparison",
-       517: "invalid_not_null_constraint",
-
-       // Invalid transaction state (errorcode 05, sqlstate 25)
-       518: "read_only_connection",
-       519: "varbinary_array_not_supported",
-
-       // Expression index exceptions
-       520: "aggregate_expression_not_allowed_in_index",
-       521: "non_deterministic_expression_not_allowed_in_index",
-       522: "stateless_expression_not_allowed_in_index",
-
-       // Transaction exceptions
-       523: "transaction_conflict_exception",
-       524: "transaction_exception",
-
-       // Union all related errors
-       525: "select_column_num_in_unionall_diffs",
-       526: "select_column_type_in_unionall_diffs",
-
-       // Row timestamp column related errors
-       527: "rowtimestamp_one_pk_col_only",
-       528: "rowtimestamp_pk_col_only",
-       529: "rowtimestamp_create_only",
-       530: "rowtimestamp_col_invalid_type",
-       531: "rowtimestamp_not_allowed_on_view",
-       532: "invalid_scn",
-
-       // Column family related exceptions
-       1000: "single_pk_may_not_be_null",
-       1001: "column_family_not_found",
-       1002: "properties_for_family",
-       1003: "primary_key_with_family_name",
-       1004: "primary_key_out_of_order",
-       1005: "varbinary_in_row_key",
-       1006: "not_nullable_column_in_row_key",
-       1015: "varbinary_last_pk",
-       1023: "nullable_fixed_width_last_pk",
-       1036: "cannot_modify_view_pk",
-       1037: "base_table_column",
-
-       // Key/value column related errors
-       1007: "key_value_not_null",
-
-       // View related errors
-       1008: "view_with_table_config",
-       1009: "view_with_properties",
-
-       // Table related errors that are not in standard code
-       1010: "cannot_mutate_table",
-       1011: "unexpected_mutation_code",
-       1012: "table_undefined",
-       1013: "table_already_exist",
-
-       // Syntax error
-       1014: "type_not_supported_for_operator",
-       1016: "aggregate_in_group_by",
-       1017: "aggregate_in_where",
-       1018: "aggregate_with_not_group_by_column",
-       1019: "only_aggregate_in_having_clause",
-       1020: "upsert_column_numbers_mismatch",
-
-       // Table properties exception
-       1021: "invalid_bucket_num",
-       1022: "no_splits_on_salted_table",
-       1024: "salt_only_on_create_table",
-       1025: "set_unsupported_prop_on_alter_table",
-       1038: "cannot_add_not_nullable_column",
-       1026: "no_mutable_indexes",
-       1028: "invalid_index_state_transition",
-       1029: "invalid_mutable_index_config",
-       1030: "cannot_create_tenant_specific_table",
-       1034: "default_column_family_only_on_create_table",
-       1040: "insufficient_multi_tenant_columns",
-       1041: "tenantid_is_of_wrong_type",
-       1045: "view_where_is_constant",
-       1046: "cannot_update_view_column",
-       1047: "too_many_indexes",
-       1048: "no_local_index_on_table_with_immutable_rows",
-       1049: "column_family_not_allowed_table_property",
-       1050: "column_family_not_allowed_for_ttl",
-       1051: "cannot_alter_property",
-       1052: "cannot_set_property_for_column_not_added",
-       1053: "cannot_set_table_property_add_column",
-       1054: "no_local_indexes",
-       1055: "unallowed_local_indexes",
-       1056: "desc_varbinary_not_supported",
-       1057: "no_table_specified_for_wildcard_select",
-       1058: "unsupported_group_by_expressions",
-       1069: "default_column_family_on_shared_table",
-       1070: "only_table_may_be_declared_transactional",
-       1071: "tx_may_not_switch_to_non_tx",
-       1072: "store_nulls_must_be_true_for_transactional",
-       1073: "cannot_start_transaction_with_scn_set",
-       1074: "tx_max_versions_must_be_greater_than_one",
-       1075: "cannot_specify_scn_for_txn_table",
-       1076: "null_transaction_context",
-       1077: "transaction_failed",
-       1078: "cannot_create_txn_table_if_txns_disabled",
-       1079: "cannot_alter_to_be_txn_if_txns_disabled",
-       1080: "cannot_create_txn_table_with_row_timestamp",
-       1081: "cannot_alter_to_be_txn_with_row_timestamp",
-       1082: "tx_must_be_enabled_to_set_tx_context",
-       1083: "tx_must_be_enabled_to_set_auto_flush",
-       1084: "tx_must_be_enabled_to_set_isolation_level",
-       1085: "tx_unable_to_get_write_fence",
-       1086: "sequence_not_castable_to_auto_partition_id_column",
-       1087: "cannot_coerce_auto_partition_id",
-
-       // Sequence related
-       1200: "sequence_already_exist",
-       1201: "sequence_undefined",
-       1202: "start_with_must_be_constant",
-       1203: "increment_by_must_be_constant",
-       1204: "cache_must_be_non_negative_constant",
-       1205: "invalid_use_of_next_value_for",
-       1206: "cannot_call_current_before_next_value",
-       1207: "empty_sequence_cache",
-       1208: "minvalue_must_be_constant",
-       1209: "maxvalue_must_be_constant",
-       1210: "minvalue_must_be_less_than_or_equal_to_maxvalue",
-       1211: "starts_with_must_be_between_min_max_value",
-       1212: "sequence_val_reached_max_value",
-       1213: "sequence_val_reached_min_value",
-       1214: "increment_by_must_not_be_zero",
-       1215: "num_seq_to_allocate_must_be_constant",
-       1216: "num_seq_to_allocate_not_supported",
-       1217: "auto_partition_sequence_undefined",
-
-       // Parser error. (errorcode 06, sqlstate 42p)
-       601: "parser_error",
-       602: "missing_token",
-       603: "unwanted_token",
-       604: "mismatched_token",
-       605: "unknown_function",
-
-       // Implementation defined class. execution exceptions (errorcode 11, 
sqlstate xcl)
-       1101: "resultset_closed",
-       1102: "get_table_regions_fail",
-       1103: "execute_query_not_applicable",
-       1104: "execute_update_not_applicable",
-       1105: "split_point_not_constant",
-       1106: "batch_exception",
-       1107: "execute_update_with_non_empty_batch",
-       1108: "stale_region_boundary_cache",
-       1109: "cannot_split_local_index",
-       1110: "cannot_salt_local_index",
-       1120: "index_failure_block_write",
-       1130: "update_cache_frequency_invalid",
-       1131: "cannot_drop_col_append_only_schema",
-       1132: "view_append_only_schema",
-
-       // Implementation defined class. phoenix internal error. (errorcode 20, 
sqlstate int)
-       2001: "cannot_call_method_on_type",
-       2002: "class_not_unwrappable",
-       2003: "param_index_out_of_bound",
-       2004: "param_value_unbound",
-       2005: "interrupted_exception",
-       2006: "incompatible_client_server_jar",
-       2007: "outdated_jars",
-       2008: "index_metadata_not_found",
-       2009: "unknown_error_code",
-       6000: "operation_timed_out",
-       6001: "function_undefined",
-       6002: "function_already_exist",
-       6003: "unallowed_user_defined_functions",
-       721:  "schema_already_exists",
-       722:  "schema_not_found",
-       723:  "cannot_mutate_schema",
-}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/errors/errors.go
----------------------------------------------------------------------
diff --git a/errors/errors.go b/errors/errors.go
new file mode 100644
index 0000000..ee79af9
--- /dev/null
+++ b/errors/errors.go
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package errors
+
+// Error severity codes
+const (
+       Eunknown int8 = iota
+       Efatal
+       Eerror
+       Ewarning
+)
+
+// RPCMetadata contains metadata about the call that caused the error.
+type RPCMetadata struct {
+       ServerAddress string
+}
+
+// ErrorCode represents the error code returned by the avatica server
+type ErrorCode uint32
+
+// SQLState represents the SQL code returned by the avatica server
+type SQLState string
+
+// ResponseError is an error type that contains detailed information on
+// what caused the server to return an error.
+type ResponseError struct {
+       Exceptions    []string
+       HasExceptions bool
+       ErrorMessage  string
+       Severity      int8
+       ErrorCode     ErrorCode
+       SqlState      SQLState
+       Metadata      *RPCMetadata
+       Name          string
+}
+
+func (r ResponseError) Error() string {
+
+       msg := "An error was encountered while processing your request"
+
+       if r.ErrorMessage != "" {
+               msg += ": " + r.ErrorMessage
+       } else if len(r.Exceptions) > 0 {
+               msg += ":\n" + r.Exceptions[0]
+       }
+
+       return msg
+}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/gen-protobuf.bat
----------------------------------------------------------------------
diff --git a/gen-protobuf.bat b/gen-protobuf.bat
index 143b6dc..83c51cc 100644
--- a/gen-protobuf.bat
+++ b/gen-protobuf.bat
@@ -14,7 +14,7 @@ rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.
 rem See the License for the specific language governing permissions and
 rem limitations under the License.
 
-SET AVATICA_VER=rel/avatica-1.10.0
+SET AVATICA_VER=rel/avatica-1.11.0
 
 IF EXIST message\ rmdir /Q /S message
 IF EXIST avatica-tmp\ rmdir /Q /S avatica-tmp

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/gen-protobuf.sh
----------------------------------------------------------------------
diff --git a/gen-protobuf.sh b/gen-protobuf.sh
index 73d9793..55b236f 100644
--- a/gen-protobuf.sh
+++ b/gen-protobuf.sh
@@ -18,7 +18,7 @@ set -e
 
 rm -rf message avatica-tmp
 
-export AVATICA_VER="rel/avatica-1.10.0"
+export AVATICA_VER="rel/avatica-1.11.0"
 
 mkdir -p avatica-tmp
 pushd avatica-tmp &> /dev/null

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/generic/generic.go
----------------------------------------------------------------------
diff --git a/generic/generic.go b/generic/generic.go
new file mode 100644
index 0000000..8629375
--- /dev/null
+++ b/generic/generic.go
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package generic
+
+import (
+       "fmt"
+       "math"
+       "reflect"
+       "time"
+
+       "github.com/apache/calcite-avatica-go/errors"
+       "github.com/apache/calcite-avatica-go/internal"
+       "github.com/apache/calcite-avatica-go/message"
+)
+
+type Adapter struct {
+}
+
+func (a Adapter) GetPingStatement() string {
+       return "SELECT 1"
+}
+
+func (a Adapter) GetColumnTypeDefinition(col *message.ColumnMetaData) 
*internal.Column {
+
+       column := &internal.Column{
+               Name:     col.ColumnName,
+               TypeName: col.Type.Name,
+               Nullable: col.Nullable != 0,
+       }
+
+       // Handle precision and length
+       switch col.Type.Name {
+       case "DECIMAL":
+
+               precision := int64(col.Precision)
+
+               if precision == 0 {
+                       precision = math.MaxInt64
+               }
+
+               scale := int64(col.Scale)
+
+               if scale == 0 {
+                       scale = math.MaxInt64
+               }
+
+               column.PrecisionScale = &internal.PrecisionScale{
+                       Precision: precision,
+                       Scale:     scale,
+               }
+       case "VARCHAR", "CHARACTER VARYING", "CHAR", "CHARACTER", "BINARY", 
"VARBINARY", "BINARY VARYING":
+               column.Length = int64(col.Precision)
+       }
+
+       // Handle scan types
+       switch col.Type.Name {
+       case "INTEGER", "BIGINT", "TINYINT", "SMALLINT":
+               column.ScanType = reflect.TypeOf(int64(0))
+
+       case "REAL", "FLOAT", "DOUBLE":
+               column.ScanType = reflect.TypeOf(float64(0))
+
+       case "DECIMAL", "NUMERIC", "VARCHAR", "CHAR", "CHARACTER", "CHARACTER 
VARYING":
+               column.ScanType = reflect.TypeOf("")
+
+       case "BOOLEAN":
+               column.ScanType = reflect.TypeOf(false)
+
+       case "TIME", "DATE", "TIMESTAMP", "TIMESTAMP WITH LOCAL TIME ZONE", 
"TIMESTAMP WITH TIME ZONE":
+               column.ScanType = reflect.TypeOf(time.Time{})
+
+       case "BINARY", "VARBINARY", "BINARY VARYING":
+               column.ScanType = reflect.TypeOf([]byte{})
+
+       default:
+               panic(fmt.Sprintf("scantype for %s is not implemented", 
col.Type.Name))
+       }
+
+       // Handle rep type special cases for decimals, floats, date, time and 
timestamp
+       switch col.Type.Name {
+       case "DECIMAL", "NUMERIC":
+               column.Rep = message.Rep_BIG_DECIMAL
+       case "FLOAT", "REAL":
+               column.Rep = message.Rep_FLOAT
+       case "TIME":
+               column.Rep = message.Rep_JAVA_SQL_TIME
+       case "DATE":
+               column.Rep = message.Rep_JAVA_SQL_DATE
+       case "TIMESTAMP", "TIMESTAMP WITH LOCAL TIME ZONE", "TIMESTAMP WITH 
TIME ZONE":
+               column.Rep = message.Rep_JAVA_SQL_TIMESTAMP
+       default:
+               column.Rep = col.Type.Rep
+       }
+
+       return column
+}
+
+func (a Adapter) ErrorResponseToResponseError(message *message.ErrorResponse) 
errors.ResponseError {
+
+       return errors.ResponseError{
+               Exceptions:   message.Exceptions,
+               ErrorMessage: message.ErrorMessage,
+               Severity:     int8(message.Severity),
+               ErrorCode:    errors.ErrorCode(message.ErrorCode),
+               SqlState:     errors.SQLState(message.SqlState),
+               Metadata: &errors.RPCMetadata{
+                       ServerAddress: message.GetMetadata().ServerAddress,
+               },
+       }
+}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/hsqldb/hsqldb.go
----------------------------------------------------------------------
diff --git a/hsqldb/hsqldb.go b/hsqldb/hsqldb.go
new file mode 100644
index 0000000..808449f
--- /dev/null
+++ b/hsqldb/hsqldb.go
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package hsqldb
+
+import (
+       "fmt"
+       "math"
+       "reflect"
+       "time"
+
+       "github.com/apache/calcite-avatica-go/errors"
+       "github.com/apache/calcite-avatica-go/internal"
+       "github.com/apache/calcite-avatica-go/message"
+)
+
+type Adapter struct {
+}
+
+func (a Adapter) GetPingStatement() string {
+       return "SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS"
+}
+
+func (a Adapter) GetColumnTypeDefinition(col *message.ColumnMetaData) 
*internal.Column {
+
+       column := &internal.Column{
+               Name:     col.ColumnName,
+               TypeName: col.Type.Name,
+               Nullable: col.Nullable != 0,
+       }
+
+       // Handle precision and length
+       switch col.Type.Name {
+       case "DECIMAL", "NUMERIC":
+
+               precision := int64(col.Precision)
+
+               if precision == 0 {
+                       precision = math.MaxInt64
+               }
+
+               scale := int64(col.Scale)
+
+               if scale == 0 {
+                       scale = math.MaxInt64
+               }
+
+               column.PrecisionScale = &internal.PrecisionScale{
+                       Precision: precision,
+                       Scale:     scale,
+               }
+       case "VARCHAR", "CHAR", "CHARACTER", "BINARY", "VARBINARY", "BIT", 
"BITVARYING":
+               column.Length = int64(col.Precision)
+       }
+
+       // Handle scan types
+       switch col.Type.Name {
+       case "INTEGER", "BIGINT", "TINYINT", "SMALLINT":
+               column.ScanType = reflect.TypeOf(int64(0))
+
+       case "FLOAT", "DOUBLE":
+               column.ScanType = reflect.TypeOf(float64(0))
+
+       case "DECIMAL", "NUMERIC", "VARCHAR", "CHAR", "CHARACTER":
+               column.ScanType = reflect.TypeOf("")
+
+       case "BOOLEAN":
+               column.ScanType = reflect.TypeOf(false)
+
+       case "TIME", "DATE", "TIMESTAMP":
+               column.ScanType = reflect.TypeOf(time.Time{})
+
+       case "BINARY", "VARBINARY":
+               column.ScanType = reflect.TypeOf([]byte{})
+
+       default:
+               panic(fmt.Sprintf("scantype for %s is not implemented", 
col.Type.Name))
+       }
+
+       // Handle rep type special cases for decimals, floats, date, time and 
timestamp
+       switch col.Type.Name {
+       case "DECIMAL", "NUMERIC":
+               column.Rep = message.Rep_BIG_DECIMAL
+       case "FLOAT":
+               column.Rep = message.Rep_FLOAT
+       case "TIME":
+               column.Rep = message.Rep_JAVA_SQL_TIME
+       case "DATE":
+               column.Rep = message.Rep_JAVA_SQL_DATE
+       case "TIMESTAMP":
+               column.Rep = message.Rep_JAVA_SQL_TIMESTAMP
+       default:
+               column.Rep = col.Type.Rep
+       }
+
+       return column
+}
+
+func (a Adapter) ErrorResponseToResponseError(message *message.ErrorResponse) 
errors.ResponseError {
+
+       return errors.ResponseError{
+               Exceptions:   message.Exceptions,
+               ErrorMessage: message.ErrorMessage,
+               Severity:     int8(message.Severity),
+               ErrorCode:    errors.ErrorCode(message.ErrorCode),
+               SqlState:     errors.SQLState(message.SqlState),
+               Metadata: &errors.RPCMetadata{
+                       ServerAddress: message.GetMetadata().ServerAddress,
+               },
+       }
+}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/http_client.go
----------------------------------------------------------------------
diff --git a/http_client.go b/http_client.go
index dff7a02..b58a62a 100644
--- a/http_client.go
+++ b/http_client.go
@@ -55,12 +55,18 @@ type httpClientAuthConfig struct {
 
 // httpClient wraps the default http.Client to communicate with the Avatica 
server.
 type httpClient struct {
-       host       string
-       authConfig httpClientAuthConfig
+       host           string
+       authConfig     httpClientAuthConfig
+       httpClient     *http.Client
+       kerberosClient client.Client
+}
 
-       httpClient *http.Client
+type avaticaError struct {
+       message *avaticaMessage.ErrorResponse
+}
 
-       kerberosClient client.Client
+func (e avaticaError) Error() string {
+       return fmt.Sprintf("avatica encountered an error: %s", 
e.message.ErrorMessage)
 }
 
 // NewHTTPClient creates a new httpClient from a host.
@@ -202,7 +208,7 @@ func (c *httpClient) post(ctx context.Context, message 
proto.Message) (proto.Mes
                        }
                }
 
-               return nil, errorResponseToResponseError(v)
+               return nil, avaticaError{v}
        }
 
        return inner, nil

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/internal/column.go
----------------------------------------------------------------------
diff --git a/internal/column.go b/internal/column.go
new file mode 100644
index 0000000..81fee3f
--- /dev/null
+++ b/internal/column.go
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package internal
+
+import (
+       "reflect"
+
+       "github.com/apache/calcite-avatica-go/message"
+)
+
+type Column struct {
+       Name           string
+       TypeName       string
+       Rep            message.Rep
+       Length         int64
+       Nullable       bool
+       PrecisionScale *PrecisionScale
+       ScanType       reflect.Type
+}
+
+type PrecisionScale struct {
+       Precision int64
+       Scale     int64
+}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/moby.yml
----------------------------------------------------------------------
diff --git a/moby.yml b/moby.yml
index 07cc28a..d1ceefc 100644
--- a/moby.yml
+++ b/moby.yml
@@ -16,13 +16,18 @@
 services:
   - id: phoenix
     image: boostport/hbase-phoenix-all-in-one:1.3-4.13
+
+  - id: hsqldb
+    image: f21global/calcite-avatica:1.11.0-hypersql
+    command: -u jdbc:hsqldb:mem:public
     ports:
       - "8765"
 
 dev:
   image: golang:1.10-alpine
   env:
-    AVATICA_HOST: http://phoenix:8765
+    PHOENIX_HOST: http://phoenix:8765
+    HSQLDB_HOST: http://hsqldb:8765
   steps:
     - type: script
       name: Set up workspace
@@ -34,4 +39,4 @@ dev:
       name: Run tests
       cwd: $GOPATH/src/github.com/apache/calcite-avatica-go
       options:
-        command: go test -v $(go list ./... | grep -v /vendor/)
\ No newline at end of file
+        command: export AVATICA_FLAVOR=HSQLDB && go test -v ./... && export 
AVATICA_FLAVOR=PHOENIX && go test -v ./...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/phoenix/phoenix.go
----------------------------------------------------------------------
diff --git a/phoenix/phoenix.go b/phoenix/phoenix.go
new file mode 100644
index 0000000..08ad4f9
--- /dev/null
+++ b/phoenix/phoenix.go
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package phoenix
+
+import (
+       "fmt"
+       "math"
+       "reflect"
+       "regexp"
+       "strconv"
+       "time"
+
+       "github.com/apache/calcite-avatica-go/errors"
+       "github.com/apache/calcite-avatica-go/internal"
+       "github.com/apache/calcite-avatica-go/message"
+)
+
+type Adapter struct {
+}
+
+func (a Adapter) GetPingStatement() string {
+       return "SELECT 1"
+}
+
+func (a Adapter) GetColumnTypeDefinition(col *message.ColumnMetaData) 
*internal.Column {
+
+       column := &internal.Column{
+               Name:     col.ColumnName,
+               TypeName: col.Type.Name,
+               Nullable: col.Nullable != 0,
+       }
+
+       // Handle precision and length
+       switch col.Type.Name {
+       case "DECIMAL":
+
+               precision := int64(col.Precision)
+
+               if precision == 0 {
+                       precision = math.MaxInt64
+               }
+
+               scale := int64(col.Scale)
+
+               if scale == 0 {
+                       scale = math.MaxInt64
+               }
+
+               column.PrecisionScale = &internal.PrecisionScale{
+                       Precision: precision,
+                       Scale:     scale,
+               }
+       case "VARCHAR", "CHAR", "BINARY":
+               column.Length = int64(col.Precision)
+       case "VARBINARY":
+               column.Length = math.MaxInt64
+       }
+
+       // Handle scan types
+       switch col.Type.Name {
+       case "INTEGER", "UNSIGNED_INT", "BIGINT", "UNSIGNED_LONG", "TINYINT", 
"UNSIGNED_TINYINT", "SMALLINT", "UNSIGNED_SMALLINT":
+               column.ScanType = reflect.TypeOf(int64(0))
+
+       case "FLOAT", "UNSIGNED_FLOAT", "DOUBLE", "UNSIGNED_DOUBLE":
+               column.ScanType = reflect.TypeOf(float64(0))
+
+       case "DECIMAL", "VARCHAR", "CHAR":
+               column.ScanType = reflect.TypeOf("")
+
+       case "BOOLEAN":
+               column.ScanType = reflect.TypeOf(false)
+
+       case "TIME", "DATE", "TIMESTAMP", "UNSIGNED_TIME", "UNSIGNED_DATE", 
"UNSIGNED_TIMESTAMP":
+               column.ScanType = reflect.TypeOf(time.Time{})
+
+       case "BINARY", "VARBINARY":
+               column.ScanType = reflect.TypeOf([]byte{})
+
+       default:
+               panic(fmt.Sprintf("scantype for %s is not implemented", 
col.Type.Name))
+       }
+
+       // Handle rep type special cases for decimals, floats, date, time and 
timestamp
+       switch col.Type.Name {
+       case "DECIMAL":
+               column.Rep = message.Rep_BIG_DECIMAL
+       case "FLOAT":
+               column.Rep = message.Rep_FLOAT
+       case "UNSIGNED_FLOAT":
+               column.Rep = message.Rep_FLOAT
+       case "TIME", "UNSIGNED_TIME":
+               column.Rep = message.Rep_JAVA_SQL_TIME
+       case "DATE", "UNSIGNED_DATE":
+               column.Rep = message.Rep_JAVA_SQL_DATE
+       case "TIMESTAMP", "UNSIGNED_TIMESTAMP":
+               column.Rep = message.Rep_JAVA_SQL_TIMESTAMP
+       default:
+               column.Rep = col.Type.Rep
+       }
+
+       return column
+}
+
+func (a Adapter) ErrorResponseToResponseError(message *message.ErrorResponse) 
errors.ResponseError {
+       var (
+               errorCode int
+               sqlState  string
+       )
+
+       re := regexp.MustCompile(`ERROR (\d+) \(([0-9a-zA-Z]+)\)`)
+       codes := re.FindStringSubmatch(message.ErrorMessage)
+
+       if len(codes) > 1 {
+               errorCode, _ = strconv.Atoi(codes[1])
+       }
+
+       if len(codes) > 2 {
+               sqlState = codes[2]
+       }
+
+       err := errors.ResponseError{
+               Exceptions:   message.Exceptions,
+               ErrorMessage: message.ErrorMessage,
+               Severity:     int8(message.Severity),
+               ErrorCode:    errors.ErrorCode(errorCode),
+               SqlState:     errors.SQLState(sqlState),
+               Metadata: &errors.RPCMetadata{
+                       ServerAddress: message.GetMetadata().ServerAddress,
+               },
+               Name: errorCodeNames[uint32(errorCode)],
+       }
+
+       return err
+}
+
+var errorCodeNames = map[uint32]string{
+       // Connection exceptions (errorcode 01, sqlstate 08)
+       101: "io_exception",
+       102: "malformed_connection_url",
+       103: "cannot_establish_connection",
+
+       // Data exceptions (errorcode 02, sqlstate 22)
+       201: "illegal_data",
+       202: "divide_by_zero",
+       203: "type_mismatch",
+       204: "value_in_upsert_not_constant",
+       205: "malformed_url",
+       206: "data_exceeds_max_capacity",
+       207: "missing_max_length",
+       208: "nonpositive_max_length",
+       209: "decimal_precision_out_of_range",
+       212: "server_arithmetic_error",
+       213: "value_outside_range",
+       214: "value_in_list_not_constant",
+       215: "single_row_subquery_returns_multiple_rows",
+       216: "subquery_returns_different_number_of_fields",
+       217: "ambiguous_join_condition",
+       218: "constraint_violation",
+
+       301: "concurrent_table_mutation",
+       302: "cannot_index_column_on_type",
+
+       // Invalid cursor state (errorcode 04, sqlstate 24)
+       401: "cursor_before_first_row",
+       402: "cursor_past_last_row",
+
+       // Syntax error or access rule violation (errorcode 05, sqlstate 42)
+       501: "ambiguous_table",
+       502: "ambiguous_column",
+       503: "index_missing_pk_columns",
+       504: "column_not_found",
+       505: "read_only_table",
+       506: "cannot_drop_pk",
+       509: "primary_key_missing",
+       510: "primary_key_already_exists",
+       511: "order_by_not_in_select_distinct",
+       512: "invalid_primary_key_constraint",
+       513: "array_not_allowed_in_primary_key",
+       514: "column_exist_in_def",
+       515: "order_by_array_not_supported",
+       516: "non_equality_array_comparison",
+       517: "invalid_not_null_constraint",
+
+       // Invalid transaction state (errorcode 05, sqlstate 25)
+       518: "read_only_connection",
+       519: "varbinary_array_not_supported",
+
+       // Expression index exceptions
+       520: "aggregate_expression_not_allowed_in_index",
+       521: "non_deterministic_expression_not_allowed_in_index",
+       522: "stateless_expression_not_allowed_in_index",
+
+       // Transaction exceptions
+       523: "transaction_conflict_exception",
+       524: "transaction_exception",
+
+       // Union all related errors
+       525: "select_column_num_in_unionall_diffs",
+       526: "select_column_type_in_unionall_diffs",
+
+       // Row timestamp column related errors
+       527: "rowtimestamp_one_pk_col_only",
+       528: "rowtimestamp_pk_col_only",
+       529: "rowtimestamp_create_only",
+       530: "rowtimestamp_col_invalid_type",
+       531: "rowtimestamp_not_allowed_on_view",
+       532: "invalid_scn",
+
+       // Column family related exceptions
+       1000: "single_pk_may_not_be_null",
+       1001: "column_family_not_found",
+       1002: "properties_for_family",
+       1003: "primary_key_with_family_name",
+       1004: "primary_key_out_of_order",
+       1005: "varbinary_in_row_key",
+       1006: "not_nullable_column_in_row_key",
+       1015: "varbinary_last_pk",
+       1023: "nullable_fixed_width_last_pk",
+       1036: "cannot_modify_view_pk",
+       1037: "base_table_column",
+
+       // Key/value column related errors
+       1007: "key_value_not_null",
+
+       // View related errors
+       1008: "view_with_table_config",
+       1009: "view_with_properties",
+
+       // Table related errors that are not in standard code
+       1010: "cannot_mutate_table",
+       1011: "unexpected_mutation_code",
+       1012: "table_undefined",
+       1013: "table_already_exist",
+
+       // Syntax error
+       1014: "type_not_supported_for_operator",
+       1016: "aggregate_in_group_by",
+       1017: "aggregate_in_where",
+       1018: "aggregate_with_not_group_by_column",
+       1019: "only_aggregate_in_having_clause",
+       1020: "upsert_column_numbers_mismatch",
+
+       // Table properties exception
+       1021: "invalid_bucket_num",
+       1022: "no_splits_on_salted_table",
+       1024: "salt_only_on_create_table",
+       1025: "set_unsupported_prop_on_alter_table",
+       1038: "cannot_add_not_nullable_column",
+       1026: "no_mutable_indexes",
+       1028: "invalid_index_state_transition",
+       1029: "invalid_mutable_index_config",
+       1030: "cannot_create_tenant_specific_table",
+       1034: "default_column_family_only_on_create_table",
+       1040: "insufficient_multi_tenant_columns",
+       1041: "tenantid_is_of_wrong_type",
+       1045: "view_where_is_constant",
+       1046: "cannot_update_view_column",
+       1047: "too_many_indexes",
+       1048: "no_local_index_on_table_with_immutable_rows",
+       1049: "column_family_not_allowed_table_property",
+       1050: "column_family_not_allowed_for_ttl",
+       1051: "cannot_alter_property",
+       1052: "cannot_set_property_for_column_not_added",
+       1053: "cannot_set_table_property_add_column",
+       1054: "no_local_indexes",
+       1055: "unallowed_local_indexes",
+       1056: "desc_varbinary_not_supported",
+       1057: "no_table_specified_for_wildcard_select",
+       1058: "unsupported_group_by_expressions",
+       1069: "default_column_family_on_shared_table",
+       1070: "only_table_may_be_declared_transactional",
+       1071: "tx_may_not_switch_to_non_tx",
+       1072: "store_nulls_must_be_true_for_transactional",
+       1073: "cannot_start_transaction_with_scn_set",
+       1074: "tx_max_versions_must_be_greater_than_one",
+       1075: "cannot_specify_scn_for_txn_table",
+       1076: "null_transaction_context",
+       1077: "transaction_failed",
+       1078: "cannot_create_txn_table_if_txns_disabled",
+       1079: "cannot_alter_to_be_txn_if_txns_disabled",
+       1080: "cannot_create_txn_table_with_row_timestamp",
+       1081: "cannot_alter_to_be_txn_with_row_timestamp",
+       1082: "tx_must_be_enabled_to_set_tx_context",
+       1083: "tx_must_be_enabled_to_set_auto_flush",
+       1084: "tx_must_be_enabled_to_set_isolation_level",
+       1085: "tx_unable_to_get_write_fence",
+       1086: "sequence_not_castable_to_auto_partition_id_column",
+       1087: "cannot_coerce_auto_partition_id",
+
+       // Sequence related
+       1200: "sequence_already_exist",
+       1201: "sequence_undefined",
+       1202: "start_with_must_be_constant",
+       1203: "increment_by_must_be_constant",
+       1204: "cache_must_be_non_negative_constant",
+       1205: "invalid_use_of_next_value_for",
+       1206: "cannot_call_current_before_next_value",
+       1207: "empty_sequence_cache",
+       1208: "minvalue_must_be_constant",
+       1209: "maxvalue_must_be_constant",
+       1210: "minvalue_must_be_less_than_or_equal_to_maxvalue",
+       1211: "starts_with_must_be_between_min_max_value",
+       1212: "sequence_val_reached_max_value",
+       1213: "sequence_val_reached_min_value",
+       1214: "increment_by_must_not_be_zero",
+       1215: "num_seq_to_allocate_must_be_constant",
+       1216: "num_seq_to_allocate_not_supported",
+       1217: "auto_partition_sequence_undefined",
+
+       // Parser error. (errorcode 06, sqlstate 42p)
+       601: "parser_error",
+       602: "missing_token",
+       603: "unwanted_token",
+       604: "mismatched_token",
+       605: "unknown_function",
+
+       // Implementation defined class. execution exceptions (errorcode 11, 
sqlstate xcl)
+       1101: "resultset_closed",
+       1102: "get_table_regions_fail",
+       1103: "execute_query_not_applicable",
+       1104: "execute_update_not_applicable",
+       1105: "split_point_not_constant",
+       1106: "batch_exception",
+       1107: "execute_update_with_non_empty_batch",
+       1108: "stale_region_boundary_cache",
+       1109: "cannot_split_local_index",
+       1110: "cannot_salt_local_index",
+       1120: "index_failure_block_write",
+       1130: "update_cache_frequency_invalid",
+       1131: "cannot_drop_col_append_only_schema",
+       1132: "view_append_only_schema",
+
+       // Implementation defined class. phoenix internal error. (errorcode 20, 
sqlstate int)
+       2001: "cannot_call_method_on_type",
+       2002: "class_not_unwrappable",
+       2003: "param_index_out_of_bound",
+       2004: "param_value_unbound",
+       2005: "interrupted_exception",
+       2006: "incompatible_client_server_jar",
+       2007: "outdated_jars",
+       2008: "index_metadata_not_found",
+       2009: "unknown_error_code",
+       6000: "operation_timed_out",
+       6001: "function_undefined",
+       6002: "function_already_exist",
+       6003: "unallowed_user_defined_functions",
+       721:  "schema_already_exists",
+       722:  "schema_not_found",
+       723:  "cannot_mutate_schema",
+}

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/rows.go
----------------------------------------------------------------------
diff --git a/rows.go b/rows.go
index b8fd54c..e205e19 100644
--- a/rows.go
+++ b/rows.go
@@ -19,33 +19,16 @@ package avatica
 
 import (
        "database/sql/driver"
-       "fmt"
        "io"
-       "math"
-       "reflect"
        "time"
 
+       "github.com/apache/calcite-avatica-go/internal"
        "github.com/apache/calcite-avatica-go/message"
        "golang.org/x/net/context"
 )
 
-type precisionScale struct {
-       precision int64
-       scale     int64
-}
-
-type column struct {
-       name           string
-       typeName       string
-       rep            message.Rep
-       length         int64
-       nullable       bool
-       precisionScale *precisionScale
-       scanType       reflect.Type
-}
-
 type resultSet struct {
-       columns    []*column
+       columns    []*internal.Column
        done       bool
        offset     uint64
        data       [][]*message.TypedValue
@@ -68,7 +51,7 @@ func (r *rows) Columns() []string {
        var cols []string
 
        for _, column := range r.resultSets[r.currentResultSet].columns {
-               cols = append(cols, column.name)
+               cols = append(cols, column.Name)
        }
 
        return cols
@@ -110,7 +93,7 @@ func (r *rows) Next(dest []driver.Value) error {
                })
 
                if err != nil {
-                       return err
+                       return r.conn.avaticaErrorToResponseErrorOrError(err)
                }
 
                frame := res.(*message.FetchResponse).Frame
@@ -140,7 +123,7 @@ func (r *rows) Next(dest []driver.Value) error {
        }
 
        for i, val := range resultSet.data[resultSet.currentRow] {
-               dest[i] = typedValueToNative(resultSet.columns[i].rep, val, 
r.conn.config)
+               dest[i] = typedValueToNative(resultSet.columns[i].Rep, val, 
r.conn.config)
        }
 
        resultSet.currentRow++
@@ -158,84 +141,10 @@ func newRows(conn *conn, statementID uint32, resultSets 
[]*message.ResultSetResp
                        break
                }
 
-               var columns []*column
+               var columns []*internal.Column
 
                for _, col := range result.Signature.Columns {
-
-                       column := &column{
-                               name:     col.ColumnName,
-                               typeName: col.Type.Name,
-                               nullable: col.Nullable != 0,
-                       }
-
-                       // Handle precision and length
-                       switch col.Type.Name {
-                       case "DECIMAL":
-
-                               precision := int64(col.Precision)
-
-                               if precision == 0 {
-                                       precision = math.MaxInt64
-                               }
-
-                               scale := int64(col.Scale)
-
-                               if scale == 0 {
-                                       scale = math.MaxInt64
-                               }
-
-                               column.precisionScale = &precisionScale{
-                                       precision: precision,
-                                       scale:     scale,
-                               }
-                       case "VARCHAR", "CHAR", "BINARY":
-                               column.length = int64(col.Precision)
-                       case "VARBINARY":
-                               column.length = math.MaxInt64
-                       }
-
-                       // Handle scan types
-                       switch col.Type.Name {
-                       case "INTEGER", "UNSIGNED_INT", "BIGINT", 
"UNSIGNED_LONG", "TINYINT", "UNSIGNED_TINYINT", "SMALLINT", "UNSIGNED_SMALLINT":
-                               column.scanType = reflect.TypeOf(int64(0))
-
-                       case "FLOAT", "UNSIGNED_FLOAT", "DOUBLE", 
"UNSIGNED_DOUBLE":
-                               column.scanType = reflect.TypeOf(float64(0))
-
-                       case "DECIMAL", "VARCHAR", "CHAR":
-                               column.scanType = reflect.TypeOf("")
-
-                       case "BOOLEAN":
-                               column.scanType = reflect.TypeOf(false)
-
-                       case "TIME", "DATE", "TIMESTAMP", "UNSIGNED_TIME", 
"UNSIGNED_DATE", "UNSIGNED_TIMESTAMP":
-                               column.scanType = reflect.TypeOf(time.Time{})
-
-                       case "BINARY", "VARBINARY":
-                               column.scanType = reflect.TypeOf([]byte{})
-
-                       default:
-                               panic(fmt.Sprintf("scantype for %s is not 
implemented", col.Type.Name))
-                       }
-
-                       // Handle rep type special cases for decimals, floats, 
date, time and timestamp
-                       switch col.Type.Name {
-                       case "DECIMAL":
-                               column.rep = message.Rep_BIG_DECIMAL
-                       case "FLOAT":
-                               column.rep = message.Rep_FLOAT
-                       case "UNSIGNED_FLOAT":
-                               column.rep = message.Rep_FLOAT
-                       case "TIME", "UNSIGNED_TIME":
-                               column.rep = message.Rep_JAVA_SQL_TIME
-                       case "DATE", "UNSIGNED_DATE":
-                               column.rep = message.Rep_JAVA_SQL_DATE
-                       case "TIMESTAMP", "UNSIGNED_TIMESTAMP":
-                               column.rep = message.Rep_JAVA_SQL_TIMESTAMP
-                       default:
-                               column.rep = col.Type.Rep
-                       }
-
+                       column := conn.adapter.GetColumnTypeDefinition(col)
                        columns = append(columns, column)
                }
 
@@ -271,7 +180,6 @@ func newRows(conn *conn, statementID uint32, resultSets 
[]*message.ResultSetResp
 
 // typedValueToNative converts values from avatica's types to Go's native types
 func typedValueToNative(rep message.Rep, v *message.TypedValue, config 
*Config) interface{} {
-
        switch rep {
        case message.Rep_BOOLEAN, message.Rep_PRIMITIVE_BOOLEAN:
                return v.BoolValue

http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/2968def4/rows_go18.go
----------------------------------------------------------------------
diff --git a/rows_go18.go b/rows_go18.go
index 3dcf95c..792c211 100644
--- a/rows_go18.go
+++ b/rows_go18.go
@@ -44,11 +44,11 @@ func (r *rows) NextResultSet() error {
 
 func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
 
-       return r.resultSets[r.currentResultSet].columns[index].typeName
+       return r.resultSets[r.currentResultSet].columns[index].TypeName
 }
 
 func (r *rows) ColumnTypeLength(index int) (length int64, ok bool) {
-       l := r.resultSets[r.currentResultSet].columns[index].length
+       l := r.resultSets[r.currentResultSet].columns[index].Length
 
        if l == 0 {
                return 0, false
@@ -58,20 +58,20 @@ func (r *rows) ColumnTypeLength(index int) (length int64, 
ok bool) {
 }
 
 func (r *rows) ColumnTypeNullable(index int) (nullable, ok bool) {
-       return r.resultSets[r.currentResultSet].columns[index].nullable, true
+       return r.resultSets[r.currentResultSet].columns[index].Nullable, true
 }
 
 func (r *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok 
bool) {
 
-       ps := r.resultSets[r.currentResultSet].columns[index].precisionScale
+       ps := r.resultSets[r.currentResultSet].columns[index].PrecisionScale
 
        if ps != nil {
-               return ps.precision, ps.scale, true
+               return ps.Precision, ps.Scale, true
        }
 
        return 0, 0, false
 }
 
 func (r *rows) ColumnTypeScanType(index int) reflect.Type {
-       return r.resultSets[r.currentResultSet].columns[index].scanType
+       return r.resultSets[r.currentResultSet].columns[index].ScanType
 }

Reply via email to