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.FlexConsts;
019import org.apache.ibatis.mapping.BoundSql;
020import org.apache.ibatis.mapping.MappedStatement;
021import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
022
023import java.sql.PreparedStatement;
024import java.sql.SQLException;
025import java.util.Date;
026import java.util.Map;
027
028public class SqlArgsParameterHandler extends DefaultParameterHandler {
029
030    private final Map parameterObject;
031
032
033    public SqlArgsParameterHandler(MappedStatement mappedStatement, Map parameterObject, BoundSql boundSql) {
034        super(mappedStatement, parameterObject, boundSql);
035        this.parameterObject = parameterObject;
036    }
037
038
039    @Override
040    public void setParameters(PreparedStatement ps) {
041        try {
042            doSetParameters(ps);
043        } catch (SQLException e) {
044            throw new RuntimeException(e);
045        }
046    }
047
048
049    private void doSetParameters(PreparedStatement ps) throws SQLException {
050        Object[] sqlArgs = (Object[]) ((Map<?, ?>) parameterObject).get(FlexConsts.SQL_ARGS);
051        if (sqlArgs != null && sqlArgs.length > 0) {
052            int index = 1;
053            for (Object value : sqlArgs) {
054                //通过配置的 TypeHandler 去设置内容
055                if (value instanceof TypeHandlerObject) {
056                    ((TypeHandlerObject) value).setParameter(ps, index++);
057                }
058                //在 Oracle、SqlServer 中 TIMESTAMP、DATE 类型的数据是支持 java.util.Date 给值的
059                else if (value instanceof java.util.Date) {
060                    setDateParameter(ps, (Date) value, index++);
061                } else if (value instanceof byte[]) {
062                    ps.setBytes(index++, (byte[]) value);
063                } else {
064                    /** 在 MySql,Oracle 等驱动中,通过 PreparedStatement.setObject 后,驱动会自动根据 value 内容进行转换
065                     * 源码可参考: {{@link com.mysql.jdbc.PreparedStatement#setObject(int, Object)}
066                     **/
067                    ps.setObject(index++, value);
068                }
069            }
070        } else {
071            super.setParameters(ps);
072        }
073    }
074
075    /**
076     * Oracle、SqlServer 需要主动设置下 date 类型
077     * MySql 通过 setObject 后会自动转换,具体查看 MySql 驱动源码
078     *
079     * @param ps    PreparedStatement
080     * @param value date value
081     * @param index set to index
082     * @throws SQLException
083     */
084    private void setDateParameter(PreparedStatement ps, Date value, int index) throws SQLException {
085        if (value instanceof java.sql.Date) {
086            ps.setDate(index, (java.sql.Date) value);
087        } else if (value instanceof java.sql.Timestamp) {
088            ps.setTimestamp(index, (java.sql.Timestamp) value);
089        } else {
090            ps.setTimestamp(index, new java.sql.Timestamp(value.getTime()));
091        }
092    }
093
094}