001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.mybatis;
017
018import com.mybatisflex.core.transaction.TransactionContext;
019import org.apache.ibatis.cursor.Cursor;
020import org.apache.ibatis.cursor.defaults.DefaultCursor;
021import org.apache.ibatis.executor.Executor;
022import org.apache.ibatis.executor.parameter.ParameterHandler;
023import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
024import org.apache.ibatis.mapping.BoundSql;
025import org.apache.ibatis.mapping.MappedStatement;
026import org.apache.ibatis.session.ResultHandler;
027import org.apache.ibatis.session.RowBounds;
028
029import java.sql.SQLException;
030import java.sql.Statement;
031import java.util.Iterator;
032
033public class FlexResultSetHandler extends DefaultResultSetHandler {
034
035    public FlexResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) {
036        super(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
037    }
038
039    @Override
040    public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
041        return new FlexCursor<>(super.handleCursorResultSets(stmt));
042    }
043
044    static class FlexCursor<T> extends DefaultCursor<T> {
045
046        private Cursor originalCursor;
047
048        public FlexCursor(Cursor cursor) {
049            super(null, null, null, null);
050            this.originalCursor = cursor;
051            TransactionContext.holdCursor(cursor);
052        }
053
054        @Override
055        public void close() {
056            //非事务场景下,通过 releaseCursor 对 cursor 进行 close
057            if (TransactionContext.getXID() == null) {
058                TransactionContext.releaseCursor();
059            }
060            //else 在事务的场景下,由事务主动关闭
061        }
062
063        @Override
064        public boolean isOpen() {
065            return originalCursor.isOpen();
066        }
067
068        @Override
069        public boolean isConsumed() {
070            return originalCursor.isConsumed();
071        }
072
073        @Override
074        public int getCurrentIndex() {
075            return originalCursor.getCurrentIndex();
076        }
077
078        @Override
079        public Iterator<T> iterator() {
080            try {
081                return originalCursor.iterator();
082            } catch (IllegalStateException e) {
083                if (TransactionContext.getXID() == null) {
084                    throw new IllegalStateException(e.getMessage() + " Cursor must use in transaction.");
085                }
086                throw e;
087            }
088        }
089    }
090}