001/*
002 *  Copyright (c) 2022-2025, 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 com.mybatisflex.core.exception.FlexExceptions;
020import com.mybatisflex.core.util.EnumWrapper;
021import org.apache.ibatis.mapping.BoundSql;
022import org.apache.ibatis.mapping.MappedStatement;
023import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
024import org.apache.ibatis.type.TypeHandler;
025import org.apache.ibatis.type.TypeHandlerRegistry;
026
027import java.sql.PreparedStatement;
028import java.sql.SQLException;
029import java.util.Map;
030
031/**
032 * 向 {@link PreparedStatement} 中的占位符设置值。
033 *
034 * @author michael
035 * @author 王帅
036 */
037public class SqlArgsParameterHandler extends DefaultParameterHandler {
038
039    private final TypeHandlerRegistry typeHandlerRegistry;
040
041    public SqlArgsParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
042        super(mappedStatement, parameterObject, boundSql);
043        this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
044    }
045
046    @Override
047    public void setParameters(PreparedStatement ps) {
048        try {
049            doSetParameters(ps);
050        } catch (SQLException e) {
051            throw FlexExceptions.wrap(e);
052        }
053    }
054
055    @SuppressWarnings({"rawtypes", "unchecked"})
056    private void doSetParameters(PreparedStatement ps) throws SQLException {
057        Object[] sqlArgs;
058        Map parameters = (Map) getParameterObject();
059        if (parameters.containsKey(FlexConsts.RAW_ARGS)
060            || (sqlArgs = (Object[]) parameters.get(FlexConsts.SQL_ARGS)) == null
061            || sqlArgs.length == 0) {
062            super.setParameters(ps);
063            return;
064        }
065
066        int index = 1;
067        for (Object value : sqlArgs) {
068            // 设置 NULL 值
069            if (value == null) {
070                // ps.setNull(index++, Types.NULL);
071                // 此处不应该使用 setNull(index++, Types.NULL),通过 setObject 传入 null 值,有 jdbc 驱动自行验证类型即可
072                // 使用 setNull 在 db2 等数据库下,Types.NULL 并非其需要类型
073                ps.setObject(index++, null);
074                continue;
075            }
076
077            // 通过配置的 TypeHandler 去设置值
078            if (value instanceof TypeHandlerObject) {
079                ((TypeHandlerObject) value).setParameter(ps, index++);
080                continue;
081            }
082
083            TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(value.getClass());
084            if (typeHandler == null) {
085                typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
086            }
087
088            // 此处的 jdbcType 可以为 null 的,原因是 value 不为 null,
089            // 只有 value 为 null 时, jdbcType 不允许为 null
090            typeHandler.setParameter(ps, index++, value, null);
091        }
092    }
093
094}