You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2017/08/11 01:50:11 UTC
[14/50] calcite-avatica-go git commit: Add support for configuring
the transaction isolation level using the DSN.
Add support for configuring the transaction isolation level using the DSN.
Project: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/commit/88a23514
Tree: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/tree/88a23514
Diff: http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/diff/88a23514
Branch: refs/heads/master
Commit: 88a23514205a4d88d8ef2e2c801f8ced1d199367
Parents: 6eed044
Author: Francis Chuang <fr...@boostport.com>
Authored: Thu Sep 29 16:36:03 2016 +1000
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Aug 10 18:47:09 2017 -0700
----------------------------------------------------------------------
README.md | 18 ++++++++++++++++++
connection.go | 2 +-
driver_test.go | 18 ++++++++++++------
dsn.go | 33 +++++++++++++++++++++++++--------
dsn_test.go | 39 ++++++++++++++++++++++++++++++++++++++-
transaction.go | 2 +-
6 files changed, 95 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/88a23514/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index f8bfe30..17c0992 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,24 @@ additional frames are then fetched on a as-needed basis. `frameMaxSize` allows y
in each frame to suit your application's performance profile. By default this is set to `-1`, so that there is no limit
on the number of rows in a frame.
+#### transactionIsolation
+
+Setting `transactionIsolation` allows you to set the isolation level for transactions using the connection. The value
+should be a positive integer analogous to the transaction levels defined by the JDBC specification. The default value
+is `0`, which means transactions are not supported. This is to deal with the fact that Calcite/Avatica works with
+many types of backends, with some backends having no transaction support. If you are using Apache Phoenix 4.7 onwards,
+we recommend setting it to `4`, which is the maximum isolation level supported.
+
+The supported values for `transactionIsolation` are:
+
+| Value | JDBC Constant | Description |
+| ----- | ------------------------------ | -------------------------------------------------------------------------------- |
+| 0 | none | Transactions are not supported |
+| 1 | `TRANSACTION_READ_UNCOMMITTED` | Dirty reads, non-repeatable reads and phantom reads may occur. |
+| 2 | `TRANSACTION_READ_COMMITTED` | Dirty reads are prevented, but non-repeatable reads and phantom reads may occur. |
+| 4 | `TRANSACTION_REPEATABLE_READ` | Dirty reads and non-repeatable reads are prevented, but phantom reads may occur. |
+| 8 | `TRANSACTION_SERIALIZABLE` | Dirty reads, non-repeatable reads, and phantom reads are all prevented. |
+
### time.Time support
The following Phoenix/Avatica datatypes are automatically converted to and from `time.Time`:
http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/88a23514/connection.go
----------------------------------------------------------------------
diff --git a/connection.go b/connection.go
index 24cad3b..1a3c9df 100644
--- a/connection.go
+++ b/connection.go
@@ -74,7 +74,7 @@ func (c *conn) Begin() (driver.Tx, error) {
ConnProps: &message.ConnectionProperties{
AutoCommit: false,
HasAutoCommit: true,
- TransactionIsolation: 4,
+ TransactionIsolation: c.config.transactionIsolation,
},
})
http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/88a23514/driver_test.go
----------------------------------------------------------------------
diff --git a/driver_test.go b/driver_test.go
index b69e747..928b610 100644
--- a/driver_test.go
+++ b/driver_test.go
@@ -501,7 +501,9 @@ func TestStoreAndRetrieveBinaryData(t *testing.T) {
func TestCommittingTransactions(t *testing.T) {
- runTests(t, dsn, func(dbt *DBTest) {
+ query := "?transactionIsolation=4"
+
+ runTests(t, dsn+query, func(dbt *DBTest) {
// Create and seed table
dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
@@ -567,7 +569,9 @@ func TestCommittingTransactions(t *testing.T) {
func TestRollingBackTransactions(t *testing.T) {
- runTests(t, dsn, func(dbt *DBTest) {
+ query := "?transactionIsolation=4"
+
+ runTests(t, dsn+query, func(dbt *DBTest) {
// Create and seed table
dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
@@ -638,7 +642,7 @@ func TestPreparedStatements(t *testing.T) {
// Create and seed table
dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
int INTEGER PRIMARY KEY
- ) TRANSACTIONAL=true`)
+ ) TRANSACTIONAL=false`)
stmt, err := dbt.db.Prepare(`UPSERT INTO ` + dbt.tableName + ` VALUES(?)`)
@@ -788,7 +792,9 @@ func TestQueryShortcut(t *testing.T) {
func TestOptimisticConcurrency(t *testing.T) {
- runTests(t, dsn, func(dbt *DBTest) {
+ query := "?transactionIsolation=4"
+
+ runTests(t, dsn+query, func(dbt *DBTest) {
// Create and seed table
dbt.mustExec(`CREATE TABLE ` + dbt.tableName + ` (
@@ -873,7 +879,7 @@ func TestLastInsertIDShouldReturnError(t *testing.T) {
id INTEGER PRIMARY KEY,
msg VARCHAR,
version INTEGER
- ) TRANSACTIONAL=true`)
+ ) TRANSACTIONAL=false`)
dbt.mustExec(`CREATE SEQUENCE test_sequence`)
@@ -900,7 +906,7 @@ func TestConnectionToInvalidServerShouldReturnError(t *testing.T) {
_, err := dbt.db.Exec(`CREATE TABLE ` + dbt.tableName + ` (
id INTEGER PRIMARY KEY,
msg VARCHAR,
- ) TRANSACTIONAL=true`)
+ ) TRANSACTIONAL=false`)
if err == nil {
dbt.Fatal("Expected an error due to connection to invalid server, but got nothing.")
http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/88a23514/dsn.go
----------------------------------------------------------------------
diff --git a/dsn.go b/dsn.go
index eb8270e..2292bf3 100644
--- a/dsn.go
+++ b/dsn.go
@@ -9,20 +9,22 @@ import (
// Config is a configuration parsed from a DSN string
type Config struct {
- endpoint string
- maxRowsTotal int64
- frameMaxSize int32
- location *time.Location
- schema string
+ endpoint string
+ maxRowsTotal int64
+ frameMaxSize int32
+ location *time.Location
+ schema string
+ transactionIsolation uint32
}
// ParseDSN parses a DSN string to a Config
func ParseDSN(dsn string) (*Config, error) {
conf := &Config{
- maxRowsTotal: -1,
- frameMaxSize: -1,
- location: time.UTC,
+ maxRowsTotal: -1,
+ frameMaxSize: -1,
+ location: time.UTC,
+ transactionIsolation: 0,
}
parsed, err := url.ParseRequestURI(dsn)
@@ -70,6 +72,21 @@ func ParseDSN(dsn string) (*Config, error) {
conf.schema = v
}
+ if v := queries.Get("transactionIsolation"); v != "" {
+
+ isolation, err := strconv.Atoi(v)
+
+ if err != nil {
+ return nil, fmt.Errorf("Invalid value for transactionIsolation: %s", err)
+ }
+
+ if isolation < 0 || isolation > 8 || isolation&(isolation-1) != 0 {
+ return nil, fmt.Errorf("transactionIsolation must be 0, 1, 2, 4 or 8, %d given", isolation)
+ }
+
+ conf.transactionIsolation = uint32(isolation)
+ }
+
parsed.RawQuery = ""
parsed.Fragment = ""
http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/88a23514/dsn_test.go
----------------------------------------------------------------------
diff --git a/dsn_test.go b/dsn_test.go
index 74a35b6..7c43786 100644
--- a/dsn_test.go
+++ b/dsn_test.go
@@ -1,13 +1,14 @@
package avatica
import (
+ "strconv"
"testing"
"time"
)
func TestParseDSN(t *testing.T) {
- config, err := ParseDSN("http://localhost:8765?maxRowsTotal=1&frameMaxSize=1&location=Australia/Melbourne&schema=myschema")
+ config, err := ParseDSN("http://localhost:8765?maxRowsTotal=1&frameMaxSize=1&location=Australia/Melbourne&schema=myschema&transactionIsolation=8")
if err != nil {
t.Fatalf("Unexpected error: %s", err)
@@ -32,6 +33,10 @@ func TestParseDSN(t *testing.T) {
if config.schema != "myschema" {
t.Errorf("Expected schema to be %s, got %s", "myschema", config.schema)
}
+
+ if config.transactionIsolation != 8 {
+ t.Errorf("Expected transactionIsolation to be %d, got %d", 8, config.transactionIsolation)
+ }
}
func TestParseEmptyDSN(t *testing.T) {
@@ -66,6 +71,10 @@ func TestDSNDefaults(t *testing.T) {
if config.schema != "" {
t.Errorf("Unexpected schema set: %s", config.schema)
}
+
+ if config.transactionIsolation != 0 {
+ t.Errorf("Default transaction level should be %d, got %d.", 0, config.transactionIsolation)
+ }
}
func TestLocallocation(t *testing.T) {
@@ -101,3 +110,31 @@ func TestBadInput(t *testing.T) {
t.Fatal("Expected error due to invalid frameMaxSize, but did not receive any.")
}
}
+
+func TestInvalidTransactionIsolation(t *testing.T) {
+
+ badIsolationLevels := []int{-1, 3, 5, 6, 7, 9, 10, 11, 100}
+
+ for _, isolationLevel := range badIsolationLevels {
+
+ _, err := ParseDSN("http://localhost:8765?transactionIsolation=" + strconv.Itoa(isolationLevel))
+
+ if err == nil {
+ t.Fatal("Expected error due to invalid transactionIsolation, but did not receive any.")
+ }
+ }
+}
+
+func TestValidTransactionIsolation(t *testing.T) {
+
+ validIsolationLevels := []int{0, 1, 2, 4, 8}
+
+ for _, isolationLevel := range validIsolationLevels {
+
+ _, err := ParseDSN("http://localhost:8765?transactionIsolation=" + strconv.Itoa(isolationLevel))
+
+ if err != nil {
+ t.Fatalf("Unexpected error when %d is set as the isolation level: %s", isolationLevel, err)
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/calcite-avatica-go/blob/88a23514/transaction.go
----------------------------------------------------------------------
diff --git a/transaction.go b/transaction.go
index ca968ec..e1a012e 100644
--- a/transaction.go
+++ b/transaction.go
@@ -41,7 +41,7 @@ func (t *tx) enableAutoCommit() error {
ConnProps: &message.ConnectionProperties{
AutoCommit: true,
HasAutoCommit: true,
- TransactionIsolation: 4,
+ TransactionIsolation: t.conn.config.transactionIsolation,
},
})