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.util;
017
018import java.time.LocalDateTime;
019import java.util.Date;
020import java.util.regex.Matcher;
021
022public class SqlUtil {
023
024    private SqlUtil() {
025    }
026
027    public static void keepColumnSafely(String column) {
028        if (StringUtil.isBlank(column)) {
029            throw new IllegalArgumentException("Column must not be empty");
030        } else {
031            column = column.trim();
032        }
033
034        int strLen = column.length();
035        for (int i = 0; i < strLen; ++i) {
036            char ch = column.charAt(i);
037            if (Character.isWhitespace(ch)) {
038                throw new IllegalArgumentException("Column must not has space char.");
039            }
040            if (isUnSafeChar(ch)) {
041                throw new IllegalArgumentException("Column has unsafe char: [" + ch + "].");
042            }
043        }
044    }
045
046
047    /**
048     * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
049     */
050    private static String SQL_ORDER_BY_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
051
052    public static void keepOrderBySqlSafely(String value) {
053        if (!value.matches(SQL_ORDER_BY_PATTERN)) {
054            throw new IllegalArgumentException("Order By sql not safe, order by string: " + value);
055        }
056    }
057
058
059    private static final char[] UN_SAFE_CHARS = "'`\"<>&+=#-;".toCharArray();
060
061    private static boolean isUnSafeChar(char ch) {
062        for (char c : UN_SAFE_CHARS) {
063            if (c == ch) {
064                return true;
065            }
066        }
067        return false;
068    }
069
070
071    /**
072     * 根据数据库响应结果判断数据库操作是否成功。
073     *
074     * @param result 数据库操作返回影响条数
075     * @return {@code true} 操作成功,{@code false} 操作失败。
076     */
077    public static boolean toBool(Number result) {
078        return result != null && result.longValue() > 0;
079    }
080
081
082    /**
083     * 替换 sql 中的问号 ?
084     * @param sql sql 内容
085     * @param params 参数
086     * @return 完整的 sql
087     */
088    public static String replaceSqlParams(String sql, Object[] params) {
089        if (params != null && params.length > 0) {
090            for (Object value : params) {
091                // null
092                if (value == null) {
093                    sql = sql.replaceFirst("\\?", "null");
094                }
095                // number
096                else if (value instanceof Number || value instanceof Boolean) {
097                    sql = sql.replaceFirst("\\?", value.toString());
098                }
099                // other
100                else {
101                    StringBuilder sb = new StringBuilder();
102                    sb.append("'");
103                    if (value instanceof Date) {
104                        sb.append(DateUtil.toDateTimeString((Date) value));
105                    } else if (value instanceof LocalDateTime) {
106                        sb.append(DateUtil.toDateTimeString(DateUtil.toDate((LocalDateTime) value)));
107                    } else {
108                        sb.append(value);
109                    }
110                    sb.append("'");
111                    sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(sb.toString()));
112                }
113            }
114        }
115        return sql;
116    }
117
118
119
120}