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,
 		},
 	})