You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by pa...@apache.org on 2021/05/25 23:16:53 UTC

[shardingsphere] branch master updated: Support Savepoint for Proxy (#10468)

This is an automated email from the ASF dual-hosted git repository.

panjuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 156fa6a  Support Savepoint for Proxy (#10468)
156fa6a is described below

commit 156fa6a89d32571ffc467e76f74e71eb632aa56e
Author: 吴伟杰 <wu...@apache.org>
AuthorDate: Wed May 26 07:16:09 2021 +0800

    Support Savepoint for Proxy (#10468)
    
    * Support Savepoint for Proxy
    
    * Fix code style and license
    
    * Complete testcases for BackendTransactionManager
---
 .../transaction/BackendTransactionManager.java     |  35 ++++++-
 .../transaction/ConnectionSavepointManager.java    | 102 +++++++++++++++++++++
 .../jdbc/transaction/LocalTransactionManager.java  |  41 +++++++++
 .../jdbc/transaction/TransactionManager.java       |  24 +++++
 .../transaction/TransactionBackendHandler.java     |  12 +++
 .../TransactionBackendHandlerFactory.java          |  12 +++
 .../transaction/BackendTransactionManagerTest.java |  49 ++++++++++
 .../sql/parser/autogen/PostgreSQLStatement.g4      |   2 +
 .../impl/PostgreSQLTCLStatementSQLVisitor.java     |  25 ++++-
 .../sql/parser/core/visitor/SQLVisitorRule.java    |   6 +-
 ...atement.java => ReleaseSavepointStatement.java} |  10 +-
 ...ment.java => RollbackToSavepointStatement.java} |  10 +-
 .../common/statement/tcl/SavepointStatement.java   |   6 ++
 .../tcl/PostgreSQLReleaseSavepointStatement.java}  |   9 +-
 .../PostgreSQLRollbackToSavepointStatement.java}   |   9 +-
 .../transaction/core/TransactionOperationType.java |   2 +-
 16 files changed, 338 insertions(+), 16 deletions(-)

diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManager.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManager.java
index f78e966..d1b2a11 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManager.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManager.java
@@ -17,10 +17,10 @@
 
 package org.apache.shardingsphere.proxy.backend.communication.jdbc.transaction;
 
+import org.apache.shardingsphere.infra.transaction.TransactionHolder;
 import org.apache.shardingsphere.proxy.backend.communication.jdbc.connection.BackendConnection;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.transaction.ShardingTransactionManagerEngine;
-import org.apache.shardingsphere.infra.transaction.TransactionHolder;
 import org.apache.shardingsphere.transaction.core.TransactionType;
 import org.apache.shardingsphere.transaction.spi.ShardingTransactionManager;
 
@@ -92,4 +92,37 @@ public final class BackendTransactionManager implements TransactionManager {
             }
         }
     }
+    
+    @Override
+    public void setSavepoint(final String savepointName) throws SQLException {
+        if (!connection.getTransactionStatus().isInTransaction()) {
+            return;
+        }
+        if (TransactionType.LOCAL == transactionType || null == shardingTransactionManager) {
+            localTransactionManager.setSavepoint(savepointName);
+        }
+        // TODO Non-local transaction manager
+    }
+    
+    @Override
+    public void rollbackTo(final String savepointName) throws SQLException {
+        if (!connection.getTransactionStatus().isInTransaction()) {
+            return;
+        }
+        if (TransactionType.LOCAL == transactionType || null == shardingTransactionManager) {
+            localTransactionManager.rollbackTo(savepointName);
+        }
+        // TODO Non-local transaction manager
+    }
+    
+    @Override
+    public void releaseSavepoint(final String savepointName) throws SQLException {
+        if (!connection.getTransactionStatus().isInTransaction()) {
+            return;
+        }
+        if (TransactionType.LOCAL == transactionType || null == shardingTransactionManager) {
+            localTransactionManager.releaseSavepoint(savepointName);
+        }
+        // TODO Non-local transaction manager
+    }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/ConnectionSavepointManager.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/ConnectionSavepointManager.java
new file mode 100644
index 0000000..1c880e8
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/ConnectionSavepointManager.java
@@ -0,0 +1,102 @@
+/*
+ * 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 org.apache.shardingsphere.proxy.backend.communication.jdbc.transaction;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Savepoint;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Connection savepoint manager for local transaction.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ConnectionSavepointManager {
+    
+    private static final ConnectionSavepointManager INSTANCE = new ConnectionSavepointManager();
+    
+    private static final Map<Connection, Map<String, Savepoint>> CONNECTION_SAVEPOINT_MAP = new ConcurrentHashMap<>(128);
+    
+    /**
+     * Get instance of connection savepoint manager.
+     *
+     * @return instance of connection savepoint manager
+     */
+    public static ConnectionSavepointManager getInstance() {
+        return INSTANCE;
+    }
+    
+    /**
+     * Set savepoint.
+     *
+     * @param connection connection
+     * @param savepointName savepoint name
+     * @throws SQLException SQL Exception
+     */
+    public void setSavepoint(final Connection connection, final String savepointName) throws SQLException {
+        Savepoint result = connection.setSavepoint(savepointName);
+        CONNECTION_SAVEPOINT_MAP.computeIfAbsent(connection, unused -> new LinkedHashMap<>()).put(savepointName, result);
+    }
+    
+    /**
+     * Rollback to savepoint.
+     *
+     * @param connection connection
+     * @param savepointName savepoint name
+     * @throws SQLException SQL Exception
+     */
+    public void rollbackToSavepoint(final Connection connection, final String savepointName) throws SQLException {
+        Optional<Savepoint> result = lookupSavepoint(connection, savepointName);
+        if (result.isPresent()) {
+            connection.rollback(result.get());
+        }
+    }
+    
+    /**
+     * Release savepoint.
+     *
+     * @param connection connection
+     * @param savepointName savepoint name
+     * @throws SQLException SQL Exception
+     */
+    public void releaseSavepoint(final Connection connection, final String savepointName) throws SQLException {
+        Optional<Savepoint> result = lookupSavepoint(connection, savepointName);
+        if (result.isPresent()) {
+            connection.releaseSavepoint(result.get());
+        }
+    }
+    
+    private Optional<Savepoint> lookupSavepoint(final Connection connection, final String savepointName) {
+        return Optional.ofNullable(CONNECTION_SAVEPOINT_MAP.get(connection)).map(savepointMap -> savepointMap.get(savepointName));
+    }
+    
+    /**
+     * Transaction finished.
+     *
+     * @param connection connection
+     */
+    public void transactionFinished(final Connection connection) {
+        CONNECTION_SAVEPOINT_MAP.remove(connection);
+    }
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/LocalTransactionManager.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/LocalTransactionManager.java
index 1011256..c015221 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/LocalTransactionManager.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/LocalTransactionManager.java
@@ -67,6 +67,8 @@ public final class LocalTransactionManager implements TransactionManager {
                 each.commit();
             } catch (final SQLException ex) {
                 result.add(ex);
+            } finally {
+                ConnectionSavepointManager.getInstance().transactionFinished(each);
             }
         }
         return result;
@@ -79,6 +81,8 @@ public final class LocalTransactionManager implements TransactionManager {
                 each.rollback();
             } catch (final SQLException ex) {
                 result.add(ex);
+            } finally {
+                ConnectionSavepointManager.getInstance().transactionFinished(each);
             }
         }
         return result;
@@ -94,4 +98,41 @@ public final class LocalTransactionManager implements TransactionManager {
         }
         throw ex;
     }
+    
+    @Override
+    public void setSavepoint(final String savepointName) throws SQLException {
+        if (!connection.getTransactionStatus().isInTransaction()) {
+            return;
+        }
+        for (Connection each : connection.getCachedConnections().values()) {
+            ConnectionSavepointManager.getInstance().setSavepoint(each, savepointName);
+        }
+        connection.getConnectionPostProcessors().add(target -> {
+            try {
+                ConnectionSavepointManager.getInstance().setSavepoint(target, savepointName);
+            } catch (final SQLException ex) {
+                throw new RuntimeException(ex);
+            }
+        });
+    }
+    
+    @Override
+    public void rollbackTo(final String savepointName) throws SQLException {
+        if (!connection.getTransactionStatus().isInTransaction()) {
+            return;
+        }
+        for (Connection each : connection.getCachedConnections().values()) {
+            ConnectionSavepointManager.getInstance().rollbackToSavepoint(each, savepointName);
+        }
+    }
+    
+    @Override
+    public void releaseSavepoint(final String savepointName) throws SQLException {
+        if (!connection.getTransactionStatus().isInTransaction()) {
+            return;
+        }
+        for (Connection each : connection.getCachedConnections().values()) {
+            ConnectionSavepointManager.getInstance().releaseSavepoint(each, savepointName);
+        }
+    }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/TransactionManager.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/TransactionManager.java
index b8b8219..e21eb44 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/TransactionManager.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/TransactionManager.java
@@ -44,4 +44,28 @@ public interface TransactionManager {
      * @throws SQLException SQL Exception
      */
     void rollback() throws SQLException;
+    
+    /**
+     * Set savepoint.
+     *
+     * @param savepointName savepoint name
+     * @throws SQLException SQL Exception
+     */
+    void setSavepoint(String savepointName) throws SQLException;
+    
+    /**
+     * Rollback to savepoint.
+     *
+     * @param savepointName savepoint name
+     * @throws SQLException SQL Exception
+     */
+    void rollbackTo(String savepointName) throws SQLException;
+    
+    /**
+     * Release savepoint.
+     *
+     * @param savepointName savepoint name
+     * @throws SQLException SQL Exception
+     */
+    void releaseSavepoint(String savepointName) throws SQLException;
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandler.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandler.java
index a3bc117..2507117 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandler.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandler.java
@@ -22,6 +22,9 @@ import org.apache.shardingsphere.proxy.backend.communication.jdbc.transaction.Ba
 import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
 import org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
 import org.apache.shardingsphere.proxy.backend.text.TextProtocolBackendHandler;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.ReleaseSavepointStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.RollbackToSavepointStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.SavepointStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.TCLStatement;
 import org.apache.shardingsphere.transaction.core.TransactionOperationType;
 
@@ -51,6 +54,15 @@ public final class TransactionBackendHandler implements TextProtocolBackendHandl
             case BEGIN:
                 backendTransactionManager.begin();
                 break;
+            case SAVEPOINT:
+                backendTransactionManager.setSavepoint(((SavepointStatement) tclStatement).getSavepointName());
+                break;
+            case ROLLBACK_TO_SAVEPOINT:
+                backendTransactionManager.rollbackTo(((RollbackToSavepointStatement) tclStatement).getSavepointName());
+                break;
+            case RELEASE_SAVEPOINT:
+                backendTransactionManager.releaseSavepoint(((ReleaseSavepointStatement) tclStatement).getSavepointName());
+                break;
             case COMMIT:
                 backendTransactionManager.commit();
                 break;
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandlerFactory.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandlerFactory.java
index e5d5d8a..a5e2330 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandlerFactory.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/transaction/TransactionBackendHandlerFactory.java
@@ -25,7 +25,10 @@ import org.apache.shardingsphere.proxy.backend.text.data.impl.BroadcastDatabaseB
 import org.apache.shardingsphere.proxy.backend.text.skip.SkipBackendHandler;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.BeginTransactionStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.CommitStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.ReleaseSavepointStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.RollbackStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.RollbackToSavepointStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.SavepointStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.SetAutoCommitStatement;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.TCLStatement;
 import org.apache.shardingsphere.transaction.core.TransactionOperationType;
@@ -55,6 +58,15 @@ public final class TransactionBackendHandlerFactory {
             }
             return new TransactionBackendHandler(tclStatement, TransactionOperationType.BEGIN, backendConnection);
         }
+        if (tclStatement instanceof SavepointStatement) {
+            return new TransactionBackendHandler(tclStatement, TransactionOperationType.SAVEPOINT, backendConnection);
+        }
+        if (tclStatement instanceof ReleaseSavepointStatement) {
+            return new TransactionBackendHandler(tclStatement, TransactionOperationType.RELEASE_SAVEPOINT, backendConnection);
+        }
+        if (tclStatement instanceof RollbackToSavepointStatement) {
+            return new TransactionBackendHandler(tclStatement, TransactionOperationType.ROLLBACK_TO_SAVEPOINT, backendConnection);
+        }
         if (tclStatement instanceof CommitStatement) {
             return new TransactionBackendHandler(tclStatement, TransactionOperationType.COMMIT, backendConnection);
         }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManagerTest.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManagerTest.java
index 5d3e627..67a8893 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManagerTest.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/transaction/BackendTransactionManagerTest.java
@@ -34,6 +34,7 @@ import org.mockito.junit.MockitoJUnitRunner;
 
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -145,6 +146,54 @@ public final class BackendTransactionManagerTest {
         verify(shardingTransactionManager, times(0)).rollback();
     }
     
+    @Test
+    public void assertSetSavepointForLocalTransaction() throws SQLException {
+        newBackendTransactionManager(TransactionType.LOCAL, true);
+        String savepointName = "JDBC_SAVEPOINT_0";
+        backendTransactionManager.setSavepoint(savepointName);
+        verify(localTransactionManager).setSavepoint(savepointName);
+    }
+    
+    @Test
+    public void assertSetSavepointWithoutTransaction() throws SQLException {
+        newBackendTransactionManager(TransactionType.LOCAL, false);
+        String savepointName = "JDBC_SAVEPOINT_0";
+        backendTransactionManager.setSavepoint(savepointName);
+        verify(localTransactionManager, never()).setSavepoint(savepointName);
+    }
+    
+    @Test
+    public void assertRollbackToSavepointForLocalTransaction() throws SQLException {
+        newBackendTransactionManager(TransactionType.LOCAL, true);
+        String savepointName = "JDBC_SAVEPOINT_0";
+        backendTransactionManager.rollbackTo(savepointName);
+        verify(localTransactionManager).rollbackTo(savepointName);
+    }
+    
+    @Test
+    public void assertRollbackToSavepointWithoutTransaction() throws SQLException {
+        newBackendTransactionManager(TransactionType.LOCAL, false);
+        String savepointName = "JDBC_SAVEPOINT_0";
+        backendTransactionManager.rollbackTo(savepointName);
+        verify(localTransactionManager, never()).rollbackTo(savepointName);
+    }
+    
+    @Test
+    public void assertReleaseSavepointForLocalTransaction() throws SQLException {
+        newBackendTransactionManager(TransactionType.LOCAL, true);
+        String savepointName = "JDBC_SAVEPOINT_0";
+        backendTransactionManager.releaseSavepoint(savepointName);
+        verify(localTransactionManager).releaseSavepoint(savepointName);
+    }
+    
+    @Test
+    public void assertReleaseSavepointWithoutTransaction() throws SQLException {
+        newBackendTransactionManager(TransactionType.LOCAL, false);
+        String savepointName = "JDBC_SAVEPOINT_0";
+        backendTransactionManager.releaseSavepoint(savepointName);
+        verify(localTransactionManager, never()).releaseSavepoint(savepointName);
+    }
+    
     private void newBackendTransactionManager(final TransactionType transactionType, final boolean inTransaction) {
         when(backendConnection.getTransactionStatus().getTransactionType()).thenReturn(transactionType);
         when(transactionStatus.isInTransaction()).thenReturn(inTransaction);
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/org/apache/shardingsphere/sql/parser/autogen/PostgreSQLStatement.g4 b/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/org/apache/shardingsphere/sql/parser/autogen/PostgreSQLStatement.g4
index 8858efd..ea988c3 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/org/apache/shardingsphere/sql/parser/autogen/PostgreSQLStatement.g4
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/antlr4/org/apache/shardingsphere/sql/parser/autogen/PostgreSQLStatement.g4
@@ -38,6 +38,8 @@ execute
     | commit
     | rollback
     | savepoint
+    | releaseSavepoint
+    | rollbackToSavepoint
     | grant
     | revoke
     | createUser
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLTCLStatementSQLVisitor.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLTCLStatementSQLVisitor.java
index b54ee2e..021991b 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLTCLStatementSQLVisitor.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-dialect/shardingsphere-sql-parser-postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLTCLStatementSQLVisitor.java
@@ -24,13 +24,17 @@ import org.apache.shardingsphere.sql.parser.api.visitor.type.TCLSQLVisitor;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.BeginTransactionContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.CommitContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.EndContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.ReleaseSavepointContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.RollbackContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.RollbackToSavepointContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.SavepointContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.SetTransactionContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.StartTransactionContext;
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLBeginTransactionStatement;
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLCommitStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLReleaseSavepointStatement;
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLRollbackStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLRollbackToSavepointStatement;
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLSavepointStatement;
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl.PostgreSQLSetTransactionStatement;
 
@@ -68,7 +72,26 @@ public final class PostgreSQLTCLStatementSQLVisitor extends PostgreSQLStatementS
     
     @Override
     public ASTNode visitSavepoint(final SavepointContext ctx) {
-        return new PostgreSQLSavepointStatement();
+        String savepointName = ctx.colId().getText();
+        PostgreSQLSavepointStatement result = new PostgreSQLSavepointStatement();
+        result.setSavepointName(savepointName);
+        return result;
+    }
+    
+    @Override
+    public ASTNode visitRollbackToSavepoint(final RollbackToSavepointContext ctx) {
+        String savepointName = ctx.colId().getText();
+        PostgreSQLRollbackToSavepointStatement result = new PostgreSQLRollbackToSavepointStatement();
+        result.setSavepointName(savepointName);
+        return result;
+    }
+    
+    @Override
+    public ASTNode visitReleaseSavepoint(final ReleaseSavepointContext ctx) {
+        String savepointName = ctx.colId().getText();
+        PostgreSQLReleaseSavepointStatement result = new PostgreSQLReleaseSavepointStatement();
+        result.setSavepointName(savepointName);
+        return result;
     }
     
     @Override
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-engine/src/main/java/org/apache/shardingsphere/sql/parser/core/visitor/SQLVisitorRule.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-engine/src/main/java/org/apache/shardingsphere/sql/parser/core/visitor/SQLVisitorRule.java
index 1b51188..6f8470e 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-engine/src/main/java/org/apache/shardingsphere/sql/parser/core/visitor/SQLVisitorRule.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-engine/src/main/java/org/apache/shardingsphere/sql/parser/core/visitor/SQLVisitorRule.java
@@ -138,7 +138,11 @@ public enum SQLVisitorRule {
     
     ROLLBACK("Rollback", SQLStatementType.TCL),
     
-    SAVE_POINT("Savepoint", SQLStatementType.TCL),
+    SAVEPOINT("Savepoint", SQLStatementType.TCL),
+    
+    RELEASE_SAVEPOINT("ReleaseSavepoint", SQLStatementType.TCL),
+    
+    ROLLBACK_TO_SAVEPOINT("RollbackToSavepoint", SQLStatementType.TCL),
     
     GRANT("Grant", SQLStatementType.DCL),
     
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/ReleaseSavepointStatement.java
similarity index 80%
copy from shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
copy to shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/ReleaseSavepointStatement.java
index e75b64d..87949db 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/ReleaseSavepointStatement.java
@@ -17,10 +17,16 @@
 
 package org.apache.shardingsphere.sql.parser.sql.common.statement.tcl;
 
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
 
 /**
- * Savepoint statement.
+ * Release savepoint statement.
  */
-public abstract class SavepointStatement extends AbstractSQLStatement implements TCLStatement {
+@Getter
+@Setter
+public abstract class ReleaseSavepointStatement extends AbstractSQLStatement implements TCLStatement {
+    
+    private String savepointName;
 }
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/RollbackToSavepointStatement.java
similarity index 80%
copy from shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
copy to shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/RollbackToSavepointStatement.java
index e75b64d..4035a84 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/RollbackToSavepointStatement.java
@@ -17,10 +17,16 @@
 
 package org.apache.shardingsphere.sql.parser.sql.common.statement.tcl;
 
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
 
 /**
- * Savepoint statement.
+ * Rollback to savepoint statement.
  */
-public abstract class SavepointStatement extends AbstractSQLStatement implements TCLStatement {
+@Getter
+@Setter
+public abstract class RollbackToSavepointStatement extends AbstractSQLStatement implements TCLStatement {
+    
+    private String savepointName;
 }
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
index e75b64d..8ff7c39 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
@@ -17,10 +17,16 @@
 
 package org.apache.shardingsphere.sql.parser.sql.common.statement.tcl;
 
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
 
 /**
  * Savepoint statement.
  */
+@Getter
+@Setter
 public abstract class SavepointStatement extends AbstractSQLStatement implements TCLStatement {
+    
+    private String savepointName;
 }
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/postgresql/tcl/PostgreSQLReleaseSavepointStatement.java
similarity index 69%
copy from shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
copy to shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/postgresql/tcl/PostgreSQLReleaseSavepointStatement.java
index e75b64d..6c3dcf8 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/postgresql/tcl/PostgreSQLReleaseSavepointStatement.java
@@ -15,12 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.sql.parser.sql.common.statement.tcl;
+package org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl;
 
-import org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.ReleaseSavepointStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.PostgreSQLStatement;
 
 /**
- * Savepoint statement.
+ * PostgreSQL release savepoint statement.
  */
-public abstract class SavepointStatement extends AbstractSQLStatement implements TCLStatement {
+public final class PostgreSQLReleaseSavepointStatement extends ReleaseSavepointStatement implements PostgreSQLStatement {
 }
diff --git a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/postgresql/tcl/PostgreSQLRollbackToSavepointStatement.java
similarity index 69%
copy from shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
copy to shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/postgresql/tcl/PostgreSQLRollbackToSavepointStatement.java
index e75b64d..3fd16bf 100644
--- a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/statement/tcl/SavepointStatement.java
+++ b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/dialect/statement/postgresql/tcl/PostgreSQLRollbackToSavepointStatement.java
@@ -15,12 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.sql.parser.sql.common.statement.tcl;
+package org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.tcl;
 
-import org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.RollbackToSavepointStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.PostgreSQLStatement;
 
 /**
- * Savepoint statement.
+ * PostgreSQL rollback to savepoint statement.
  */
-public abstract class SavepointStatement extends AbstractSQLStatement implements TCLStatement {
+public final class PostgreSQLRollbackToSavepointStatement extends RollbackToSavepointStatement implements PostgreSQLStatement {
 }
diff --git a/shardingsphere-transaction/shardingsphere-transaction-core/src/main/java/org/apache/shardingsphere/transaction/core/TransactionOperationType.java b/shardingsphere-transaction/shardingsphere-transaction-core/src/main/java/org/apache/shardingsphere/transaction/core/TransactionOperationType.java
index 8b9659e..1761a50 100644
--- a/shardingsphere-transaction/shardingsphere-transaction-core/src/main/java/org/apache/shardingsphere/transaction/core/TransactionOperationType.java
+++ b/shardingsphere-transaction/shardingsphere-transaction-core/src/main/java/org/apache/shardingsphere/transaction/core/TransactionOperationType.java
@@ -22,5 +22,5 @@ package org.apache.shardingsphere.transaction.core;
  */
 public enum TransactionOperationType {
     
-    BEGIN, COMMIT, ROLLBACK
+    BEGIN, COMMIT, ROLLBACK, SAVEPOINT, ROLLBACK_TO_SAVEPOINT, RELEASE_SAVEPOINT
 }