All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sagacity.sqltoy.utils.SqlUtil Maven / Gradle / Ivy

There is a newer version: 5.6.31.jre8
Show newest version
package org.sagacity.sqltoy.utils;

import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import org.sagacity.sqltoy.SqlExecuteStat;
import org.sagacity.sqltoy.SqlToyConstants;
import org.sagacity.sqltoy.SqlToyContext;
import org.sagacity.sqltoy.callback.CallableStatementResultHandler;
import org.sagacity.sqltoy.callback.DecryptHandler;
import org.sagacity.sqltoy.callback.InsertRowCallbackHandler;
import org.sagacity.sqltoy.callback.PreparedStatementResultHandler;
import org.sagacity.sqltoy.callback.RowCallbackHandler;
import org.sagacity.sqltoy.config.SqlConfigParseUtils;
import org.sagacity.sqltoy.config.model.DataType;
import org.sagacity.sqltoy.config.model.EntityMeta;
import org.sagacity.sqltoy.config.model.FieldMeta;
import org.sagacity.sqltoy.config.model.SqlWithAnalysis;
import org.sagacity.sqltoy.exception.DataAccessException;
import org.sagacity.sqltoy.model.IgnoreCaseSet;
import org.sagacity.sqltoy.model.TreeTableModel;
import org.sagacity.sqltoy.plugins.TypeHandler;
import org.sagacity.sqltoy.utils.DataSourceUtils.DBType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zhongxuchen
 * @version v1.3, Date:Apr 14, 2009 11:52:31 PM
 * @project sagacity-sqltoy
 * @description 数据库sql相关的处理工具
 * @modify Date:2011-8-18
 *         {移植BaseDaoSupport中分页移植到SqlUtil中,将数据库表、外键、主键等库和表信息移植到DBUtil中 }
 * @modify Date:2011-8-22 {修复getJdbcRecordCount中因group分组查询导致的错误, 如select
 *         name,count(*) from table group by name}
 * @modify Date:2012-11-21
 *         {完善分页查询语句中存在union的处理机制,框架自动判断是否存在union,有union则自动实现外层包裹}
 * @modify Date:2017-6-5 {剔除注释时用空白填补,防止出现类似原本:select xxx from 变成select xxxfrom }
 * @modify Date:2017-6-14 {修复针对阿里的druid数据库datasource针对clob类型处理的错误}
 * @modify Date:2019-7-5 剔除对druid clob bug的支持(druid 1.1.10 已经修复)
 * @modify Date:2020-06-18 用BeanUtil代替BeanInfo中getWriteMethod,完成对象属性赋值
 * @modify Date:2024-07-12 优化sql注释剔除的处理,兼容sql中存在/* 但没有对应收尾--*\/符号的场景
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class SqlUtil {
	/**
	 * 定义日志
	 */
	private final static Logger logger = LoggerFactory.getLogger(SqlUtil.class);

	/**
	 * sql中的单行注释
	 */
	public final static Pattern maskPattern = Pattern.compile("\\/\\*[^+!]");

	public static final Pattern ORDER_BY_PATTERN = Pattern.compile("(?i)\\Worder\\s+by\\W");

	public static final Pattern UPCASE_ORDER_PATTERN = Pattern.compile("\\WORder\\s+");

	public static final Pattern ONE_QUOTA = Pattern.compile("\'");
	public static final Pattern DOUBLE_QUOTA = Pattern.compile("\"");

	// 判断sql是否是merge into 开头
	public static final Pattern MERGE_INTO_PATTERN = Pattern.compile("^merge\\s+into\\s+");

	public static final Pattern SQLINJECT_PATTERN = Pattern.compile(
			"(?i)\\W((delete\\s+from)|update|(truncate\\s+table)|(alter\\s+table)|modify|(insert\\s+into)|select|set|create|drop|(merge\\s+into))\\s+");

	/**
	 * 查询select 匹配
	 */
	public static final String SELECT_REGEX = "\\Wselect\\s+";

	/**
	 * 查询from 匹配
	 */
	public static final String FROM_REGEX = "\\s+from[\\(\\s+]";

	// union 匹配模式
	public static final Pattern UNION_PATTERN = Pattern.compile("(?i)\\W+union\\W+");
	public final static String BLANK = " ";

	/**
	 * 存放转换后的sql
	 */
	private static ConcurrentHashMap convertSqlMap = new ConcurrentHashMap();

	// sql 注释过滤器
	private static HashMap sqlCommentfilters = new HashMap();

	static {
		// 排除表字段说明(注释)中的";"符号
		sqlCommentfilters.put("'", "'");
		sqlCommentfilters.put("(", ")");
		sqlCommentfilters.put("{", "}");
	}

	private SqlUtil() {
	}

	/**
	 * @param conditions :数据库in条件的数据集合,可以是POJO List或Object[]
	 * @param colIndex   :二维数组对应列编号
	 * @param property   :POJO property
	 * @param isChar     :in 是否要加单引号
	 * @todo 合成数据库in 查询的条件(不建议使用)
	 * @return:example:1,2,3或'1','2','3'
	 */
	public static String combineQueryInStr(Object conditions, Integer colIndex, String property, boolean isChar) {
		StringBuilder conditons = new StringBuilder(64);
		String flag = "";
		// 是否是字符类型
		if (isChar) {
			flag = "'";
		}
		// 判断数据集合维度
		int dimen = CollectionUtil.judgeObjectDimen(conditions);
		switch (dimen) {
		// 单个数据
		case 0: {
			conditons.append(flag).append(conditions.toString()).append(flag);
			break;
		}
		// 一维数组
		case 1: {
			Object[] array;
			if (conditions instanceof Collection) {
				array = ((Collection) conditions).toArray();
			} else if (conditions.getClass().isArray()) {
				array = CollectionUtil.convertArray(conditions);
			} else {
				array = ((Map) conditions).values().toArray();
			}
			for (int i = 0; i < array.length; i++) {
				if (i != 0) {
					conditons.append(",");
				}
				conditons.append(flag);
				if (null == property) {
					conditons.append(array[i]);
				} else {
					conditons.append(BeanUtil.getProperty(array[i], property));
				}
				conditons.append(flag);
			}
			break;
		}
		// 二维数据
		case 2: {
			Object[][] array;
			if (conditions instanceof Collection) {
				array = CollectionUtil.twoDimenlistToArray((Collection) conditions);
			} else if (conditions instanceof Object[][]) {
				array = (Object[][]) conditions;
			} else {
				array = CollectionUtil.twoDimenlistToArray(((Map) conditions).values());
			}
			for (int i = 0; i < array.length; i++) {
				if (i != 0) {
					conditons.append(",");
				}
				conditons.append(flag);
				if (null == property) {
					conditons.append(array[i][colIndex.intValue()]);
				} else {
					conditons.append(BeanUtil.getProperty(array[i][colIndex.intValue()], property));
				}
				conditons.append(flag);
			}
			break;
		}
		}
		return conditons.toString();
	}

	/**
	 * @param typeHandler
	 * @param conn
	 * @param dbType
	 * @param pst
	 * @param params
	 * @param paramsType
	 * @param fromIndex
	 * @throws SQLException
	 * @throws IOException
	 * @todo 自动进行类型转换, 设置sql中的参数条件的值
	 */
	public static void setParamsValue(TypeHandler typeHandler, Connection conn, final Integer dbType,
			PreparedStatement pst, Object[] params, Integer[] paramsType, int fromIndex)
			throws SQLException, IOException {
		// fromIndex 针对存储过程调用存在从1开始,如:{?=call xxStore()}
		// 一般情况fromIndex 都是0
		if (null != params && params.length > 0) {
			int n = params.length;
			int startIndex = fromIndex + 1;
			if (null == paramsType || paramsType.length == 0) {
				// paramsType=-1 表示按照参数值来判断类型
				for (int i = 0; i < n; i++) {
					setParamValue(typeHandler, conn, dbType, pst, params[i], -1, startIndex + i);
				}
			} else {
				for (int i = 0; i < n; i++) {
					setParamValue(typeHandler, conn, dbType, pst, params[i], paramsType[i], startIndex + i);
				}
			}
		}
	}

	/**
	 * @param typeHandler
	 * @param conn
	 * @param dbType
	 * @param pst
	 * @param params
	 * @param paramsType
	 * @param fromIndex
	 * @throws SQLException
	 * @throws IOException
	 * @TODO 针对sqlserver提供特殊处理(避免干扰其他代码)
	 */
	private static void setSqlServerParamsValue(TypeHandler typeHandler, Connection conn, final Integer dbType,
			PreparedStatement pst, Object[] params, Integer[] paramsType, int fromIndex)
			throws SQLException, IOException {
		// fromIndex 针对存储过程调用存在从1开始,如:{?=call xxStore()}
		// 一般情况fromIndex 都是0
		if (null != params && params.length > 0) {
			int n = params.length;
			int startIndex = fromIndex + 1;
			if (null == paramsType || paramsType.length == 0) {
				// paramsType=-1 表示按照参数值来判断类型
				for (int i = 0; i < n; i++) {
					setParamValue(typeHandler, conn, dbType, pst, params[i], -1, startIndex + i);
				}
			} else {
				int meter = 0;
				for (int i = 0; i < n; i++) {
					if (paramsType[i] != java.sql.Types.TIMESTAMP) {
						setParamValue(typeHandler, conn, dbType, pst, params[i], paramsType[i], startIndex + meter);
						meter++;
					}
				}
			}
		}
	}

	/**
	 * @param typeHandler
	 * @param conn
	 * @param dbType
	 * @param pst
	 * @param paramValue
	 * @param jdbcType
	 * @param paramIndex
	 * @throws SQLException
	 * @throws IOException
	 * @todo 设置sql中的参数条件的值
	 */
	public static void setParamValue(TypeHandler typeHandler, Connection conn, final Integer dbType,
			PreparedStatement pst, Object paramValue, int jdbcType, int paramIndex) throws SQLException, IOException {
		// jdbc部分数据库赋null值时必须要指定数据类型
		if (null == paramValue) {
			if (jdbcType != java.sql.Types.NULL) {
				if (typeHandler != null && typeHandler.setNull(dbType, pst, paramIndex, jdbcType)) {
					return;
				}
				// postgresql bytea类型需要统一处理成BINARY
				if (jdbcType == java.sql.Types.BLOB) {
					if (dbType == DBType.POSTGRESQL || dbType == DBType.POSTGRESQL15) {
						pst.setNull(paramIndex, java.sql.Types.BINARY);
					} else {
						pst.setNull(paramIndex, jdbcType);
					}
				} else if (jdbcType == java.sql.Types.CLOB) {
					if (DBType.ORACLE == dbType || DBType.DB2 == dbType || DBType.OCEANBASE == dbType
							|| DBType.ORACLE11 == dbType || DBType.DM == dbType) {
						pst.setNull(paramIndex, jdbcType);
					} else {
						pst.setNull(paramIndex, java.sql.Types.VARCHAR);
					}
				} else if (jdbcType == java.sql.Types.NCLOB) {
					if (DBType.ORACLE == dbType || DBType.DB2 == dbType || DBType.OCEANBASE == dbType
							|| DBType.ORACLE11 == dbType || DBType.DM == dbType) {
						pst.setNull(paramIndex, jdbcType);
					} else {
						pst.setNull(paramIndex, java.sql.Types.NVARCHAR);
					}
				} else {
					pst.setNull(paramIndex, jdbcType);
				}
			} else {
				pst.setNull(paramIndex, java.sql.Types.NULL);
			}
			return;
		}
		// 自定义类型处理器,完成setValue处理
		if (typeHandler != null && typeHandler.setValue(dbType, pst, paramIndex, jdbcType, paramValue)) {
			return;
		}
		String tmpStr;
		if (paramValue instanceof java.lang.String) {
			tmpStr = (String) paramValue;
			// clob 类型只有oracle、db2、dm、oceanBase等数据库支持
			if (jdbcType == java.sql.Types.CLOB) {
				if (DBType.ORACLE == dbType || DBType.DB2 == dbType || DBType.OCEANBASE == dbType
						|| DBType.ORACLE11 == dbType || DBType.DM == dbType || DBType.KINGBASE == dbType) {
					Clob clob = conn.createClob();
					clob.setString(1, tmpStr);
					pst.setClob(paramIndex, clob);
				} else {
					pst.setString(paramIndex, tmpStr);
				}
			} else if (jdbcType == java.sql.Types.NCLOB) {
				if (DBType.ORACLE == dbType || DBType.DB2 == dbType || DBType.OCEANBASE == dbType
						|| DBType.ORACLE11 == dbType || DBType.DM == dbType || DBType.KINGBASE == dbType) {
					NClob nclob = conn.createNClob();
					nclob.setString(1, tmpStr);
					pst.setNClob(paramIndex, nclob);
				} else {
					pst.setString(paramIndex, tmpStr);
				}
			} else {
				pst.setString(paramIndex, tmpStr);
			}
		} else if (paramValue instanceof java.lang.Integer) {
			// update 2023-6-2 兼容前端int对应数据库是boolean场景
			Integer paramInt = (Integer) paramValue;
			if (jdbcType == java.sql.Types.BOOLEAN) {
				if (paramInt == 1) {
					pst.setBoolean(paramIndex, true);
				} else {
					pst.setBoolean(paramIndex, false);
				}
			} else {
				pst.setInt(paramIndex, paramInt);
			}
		} else if (paramValue instanceof java.time.LocalDateTime) {
			pst.setTimestamp(paramIndex, Timestamp.valueOf((LocalDateTime) paramValue));
		} else if (paramValue instanceof BigDecimal) {
			pst.setBigDecimal(paramIndex, (BigDecimal) paramValue);
		} else if (paramValue instanceof java.time.LocalDate) {
			pst.setDate(paramIndex, java.sql.Date.valueOf((LocalDate) paramValue));
		} else if (paramValue instanceof java.sql.Timestamp) {
			pst.setTimestamp(paramIndex, (java.sql.Timestamp) paramValue);
		} else if (paramValue instanceof java.util.Date) {
			if (dbType == DBType.CLICKHOUSE) {
				pst.setDate(paramIndex, new java.sql.Date(((java.util.Date) paramValue).getTime()));
			} else {
				pst.setTimestamp(paramIndex, new Timestamp(((java.util.Date) paramValue).getTime()));
			}
		} else if (paramValue instanceof java.math.BigInteger) {
			pst.setBigDecimal(paramIndex, new BigDecimal(((BigInteger) paramValue)));
		} else if (paramValue instanceof java.lang.Double) {
			pst.setDouble(paramIndex, ((Double) paramValue));
		} else if (paramValue instanceof java.lang.Long) {
			pst.setLong(paramIndex, ((Long) paramValue));
		} else if (paramValue instanceof java.sql.Clob) {
			tmpStr = clobToString((java.sql.Clob) paramValue);
			pst.setString(paramIndex, tmpStr);
		} else if (paramValue instanceof byte[]) {
			if (jdbcType == java.sql.Types.BLOB) {
				if (dbType == DBType.MOGDB || dbType == DBType.VASTBASE || dbType == DBType.OPENGAUSS
						|| dbType == DBType.STARDB) {
					pst.setBlob(paramIndex, new ByteArrayInputStream((byte[]) paramValue));
				} else {
					Blob blob = null;
					try {
						blob = conn.createBlob();
						OutputStream out = blob.setBinaryStream(1);
						out.write((byte[]) paramValue);
						out.flush();
						out.close();
						pst.setBlob(paramIndex, blob);
					} catch (Exception e) {
						pst.setBytes(paramIndex, (byte[]) paramValue);
					}
				}
			} else {
				pst.setBytes(paramIndex, (byte[]) paramValue);
			}
		} else if (paramValue instanceof java.lang.Float) {
			pst.setFloat(paramIndex, ((Float) paramValue));
		} else if (paramValue instanceof java.sql.Blob) {
			Blob tmp = (java.sql.Blob) paramValue;
			pst.setBytes(paramIndex, tmp.getBytes(0, Long.valueOf(tmp.length()).intValue()));
		} else if (paramValue instanceof java.sql.Date) {
			pst.setDate(paramIndex, (java.sql.Date) paramValue);
		} else if (paramValue instanceof java.lang.Boolean) {
			// update 2023-10-16 增强特殊情况下的兼容
			if (jdbcType == java.sql.Types.VARCHAR || jdbcType == java.sql.Types.CHAR) {
				pst.setString(paramIndex, ((Boolean) paramValue) ? "1" : "0");
			} else if (jdbcType == java.sql.Types.INTEGER || jdbcType == java.sql.Types.SMALLINT
					|| jdbcType == java.sql.Types.TINYINT) {
				pst.setInt(paramIndex, ((Boolean) paramValue) ? 1 : 0);
			} else {
				pst.setBoolean(paramIndex, (Boolean) paramValue);
			}
		} else if (paramValue instanceof java.time.LocalTime) {
			pst.setTime(paramIndex, java.sql.Time.valueOf((LocalTime) paramValue));
		} else if (paramValue instanceof java.sql.Time) {
			pst.setTime(paramIndex, (java.sql.Time) paramValue);
		} else if (paramValue instanceof java.lang.Character) {
			tmpStr = ((Character) paramValue).toString();
			pst.setString(paramIndex, tmpStr);
		} else if (paramValue instanceof java.lang.Short) {
			pst.setShort(paramIndex, (java.lang.Short) paramValue);
		} else if (paramValue instanceof java.lang.Byte) {
			pst.setByte(paramIndex, (Byte) paramValue);
		} else if (paramValue instanceof Object[]) {
			setArray(dbType, conn, pst, paramIndex, paramValue);
		} // update 2023-08-02 增加默认的枚举类型处理
		else if (paramValue instanceof Enum) {
			pst.setObject(paramIndex, BeanUtil.getEnumValue(paramValue));
		}
		// update 2023-5-26 增加集合类型场景支持(对应数据库Array)
		else if (paramValue instanceof Collection) {
			Object[] values = ((Collection) paramValue).toArray();
			// 集合为空,无法判断具体类型,设置为null
			if (values.length == 0) {
				pst.setNull(paramIndex, java.sql.Types.ARRAY);
			} else {
				String type = null;
				for (Object val : values) {
					if (val != null) {
						type = val.getClass().getName().concat("[]");
						break;
					}
				}
				// 将Object[] 转为具体类型的数组(否则会抛异常)
				if (type != null) {
					setArray(dbType, conn, pst, paramIndex, BeanUtil.convertArray(values, type));
				} else {
					pst.setNull(paramIndex, java.sql.Types.ARRAY);
				}
			}
		} else {
			if (jdbcType != java.sql.Types.NULL) {
				pst.setObject(paramIndex, paramValue, jdbcType);
			} else {
				pst.setObject(paramIndex, paramValue);
			}
		}
	}

	/**
	 * @param dbType
	 * @param conn
	 * @param pst
	 * @param paramIndex
	 * @param paramValue
	 * @throws SQLException
	 * @TODO setArray gaussdb 必须要通过conn构造Array
	 */
	private static void setArray(Integer dbType, Connection conn, PreparedStatement pst, int paramIndex,
			Object paramValue) throws SQLException {
		// 目前只支持Integer 和 String两种类型
		if (dbType == DBType.GAUSSDB || dbType == DBType.MOGDB || dbType == DBType.OPENGAUSS
				|| dbType == DBType.VASTBASE || dbType == DBType.STARDB || dbType == DBType.OSCAR) {
			if (paramValue instanceof Integer[]) {
				Array array = conn.createArrayOf("INTEGER", (Integer[]) paramValue);
				pst.setArray(paramIndex, array);
			} else if (paramValue instanceof String[]) {
				Array array = conn.createArrayOf("VARCHAR", (String[]) paramValue);
				pst.setArray(paramIndex, array);
			} else if (paramValue instanceof BigDecimal[]) {
				Array array = conn.createArrayOf("NUMBER", (BigDecimal[]) paramValue);
				pst.setArray(paramIndex, array);
			} else if (paramValue instanceof BigInteger[]) {
				Array array = conn.createArrayOf("BIGINT", (BigInteger[]) paramValue);
				pst.setArray(paramIndex, array);
			} else if (paramValue instanceof Float[]) {
				Array array = conn.createArrayOf("FLOAT", (Float[]) paramValue);
				pst.setArray(paramIndex, array);
			} else if (paramValue instanceof Long[]) {
				Array array = conn.createArrayOf("INTEGER", (Long[]) paramValue);
				pst.setArray(paramIndex, array);
			} else {
				pst.setObject(paramIndex, paramValue, java.sql.Types.ARRAY);
			}
		} else {
			pst.setObject(paramIndex, paramValue, java.sql.Types.ARRAY);
		}
	}

	/**
	 * @param typeHandler
	 * @param rs
	 * @param voClass
	 * @param ignoreAllEmptySet
	 * @param columnFieldMap
	 * @return
	 * @throws Exception
	 * @todo 提供数据查询结果集转java对象的反射处理,以java VO集合形式返回
	 */
	private static List reflectResultToVO(TypeHandler typeHandler, DecryptHandler decryptHandler, ResultSet rs,
			Class voClass, boolean ignoreAllEmptySet, HashMap columnFieldMap) throws Exception {
		List resultList = new ArrayList();
		// 提取数据预警阈值
		int warnThresholds = SqlToyConstants.getWarnThresholds();
		// 是否超出阈值
		boolean warnLimit = false;
		// 最大阀值
		long maxThresholds = SqlToyConstants.getMaxThresholds();
		boolean maxLimit = false;
		// 最大值要大于等于警告阀值
		if (maxThresholds > 1 && maxThresholds <= warnThresholds) {
			maxThresholds = warnThresholds;
		}
		// rs 中的列名称
		String[] columnNames = getColumnLabels(rs.getMetaData());
		// 组织vo中对应的属性
		String[] fields = new String[columnNames.length];
		// update 2020-12-24 增加映射对象时属性映射关系提取
		boolean hasMap = (columnFieldMap == null || columnFieldMap.isEmpty()) ? false : true;
		// 剔除下划线
		for (int i = 0; i < fields.length; i++) {
			fields[i] = columnNames[i].toLowerCase();
			// 存在pojo中属性跟数据库字段名称有对照映射关系的
			if (hasMap) {
				if (columnFieldMap.containsKey(fields[i])) {
					fields[i] = columnFieldMap.get(fields[i]);
				} else {
					fields[i] = fields[i].replace("_", "");
				}
			} else {
				fields[i] = fields[i].replace("_", "");
			}
		}
		// 匹配对应的set方法
		Method[] setMethods = BeanUtil.matchSetMethods(voClass, fields);
		// set方法对应参数的类型,并全部转为小写
		String[] propTypes = new String[setMethods.length];
		int[] propTypeValues = new int[setMethods.length];
		Class[] genericTypes = new Class[setMethods.length];
		Type[] types;
		Class methodType;
		for (int i = 0; i < propTypes.length; i++) {
			if (setMethods[i] != null) {
				methodType = setMethods[i].getParameterTypes()[0];
				propTypes[i] = methodType.getTypeName();
				propTypeValues[i] = DataType.getType(methodType);
				types = setMethods[i].getGenericParameterTypes();
				if (types.length > 0 && (types[0] instanceof ParameterizedType)) {
					genericTypes[i] = (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[0];
				}
			}
		}
		int index = 0;
		// 循环通过java reflection将rs中的值映射到VO中
		Object rowData;
		while (rs.next()) {
			rowData = reflectResultRowToVOClass(typeHandler, decryptHandler, rs, columnNames, setMethods,
					propTypeValues, propTypes, genericTypes, voClass, ignoreAllEmptySet);
			if (rowData != null) {
				resultList.add(rowData);
			}
			index++;
			// 存在超出25000条数据的查询
			if (index == warnThresholds) {
				warnLimit = true;
			}
			// 超出最大提取数据阀值,直接终止数据提取
			if (index == maxThresholds) {
				maxLimit = true;
				break;
			}
		}
		// 提醒实际提取数量
		if (warnLimit) {
			logger.warn("Large Result:class={},total:{}>={}" + index, voClass.getName(), index, warnThresholds);
		}
		// 提醒实际提取数量
		if (maxLimit) {
			logger.warn("Large Result:class={},total:{}>={}" + index, voClass.getName(), index, maxThresholds);
		}
		return resultList;
	}

	/**
	 * @param typeHandler
	 * @param decryptHandler    解密
	 * @param rs
	 * @param columnLabels
	 * @param setMethods
	 * @param propTypeValues    对应类型int值
	 * @param propTypes         没有做大小写处理
	 * @param genericTypes
	 * @param voClass
	 * @param ignoreAllEmptySet
	 * @return
	 * @throws Exception
	 * @todo 提供数据查询结果集转java对象的反射处理,以java VO集合形式返回
	 */
	private static Object reflectResultRowToVOClass(TypeHandler typeHandler, DecryptHandler decryptHandler,
			ResultSet rs, String[] columnLabels, Method[] setMethods, int[] propTypeValues, String[] propTypes,
			Class[] genericTypes, Class voClass, boolean ignoreAllEmptySet) throws Exception {
		// 根据匹配的字段通过java reflection将rs中的值映射到VO中
		Object bean = voClass.getDeclaredConstructor().newInstance();
		Object fieldValue;
		boolean allNull = true;
		Method method;
		// 已经小写
		String typeName;
		String label;
		int typeValue;
		for (int i = 0, n = columnLabels.length; i < n; i++) {
			label = columnLabels[i];
			method = setMethods[i];
			typeName = propTypes[i];
			typeValue = propTypeValues[i];
			if (method != null) {
				fieldValue = rs.getObject(label);
				if (null != fieldValue) {
					if (decryptHandler != null) {
						fieldValue = decryptHandler.decrypt(label, fieldValue);
					}
					allNull = false;
					method.invoke(bean,
							BeanUtil.convertType(typeHandler, fieldValue, typeValue, typeName, genericTypes[i]));
				}
			}
		}
		if (allNull && ignoreAllEmptySet) {
			return null;
		}
		return bean;
	}

	/**
	 * @param rsmd
	 * @return
	 * @throws SQLException
	 * @TODO 获取ResultSet 里面的列名称
	 */
	private static String[] getColumnLabels(ResultSetMetaData rsmd) throws SQLException {
		int fieldCnt = rsmd.getColumnCount();
		String[] columnNames = new String[fieldCnt];
		for (int i = 1; i < fieldCnt + 1; i++) {
			columnNames[i - 1] = rsmd.getColumnLabel(i);
		}
		return columnNames;
	}

	/**
	 * @param userData
	 * @param pst
	 * @param rs
	 * @param preparedStatementResultHandler
	 * @return
	 * @throws Exception
	 * @todo 提供统一的ResultSet, PreparedStatemenet 关闭功能
	 */
	public static Object preparedStatementProcess(Object userData, PreparedStatement pst, ResultSet rs,
			PreparedStatementResultHandler preparedStatementResultHandler) throws Exception {
		try {
			preparedStatementResultHandler.execute(userData, pst, rs);
		} catch (Exception se) {
			se.printStackTrace();
			logger.error(se.getMessage(), se);
			throw se;
		} finally {
			try {
				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pst != null) {
					pst.close();
					pst = null;
				}
			} catch (SQLException se) {
				se.printStackTrace();
			}
		}
		return preparedStatementResultHandler.getResult();
	}

	/**
	 * @param userData
	 * @param pst
	 * @param rs
	 * @param callableStatementResultHandler
	 * @return
	 * @throws Exception
	 * @todo 提供统一的ResultSet, callableStatement 关闭功能
	 */
	public static Object callableStatementProcess(Object userData, CallableStatement pst, ResultSet rs,
			CallableStatementResultHandler callableStatementResultHandler) throws Exception {
		try {
			callableStatementResultHandler.execute(userData, pst, rs);
		} catch (Exception se) {
			se.printStackTrace();
			logger.error(se.getMessage(), se);
			throw se;
		} finally {
			try {
				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pst != null) {
					pst.close();
					pst = null;
				}
			} catch (SQLException se) {
				se.printStackTrace();
			}
		}
		return callableStatementResultHandler.getResult();
	}

	/**
	 * @param sql
	 * @return
	 * @todo 剔除sql中的注释(提供三种形态的注释剔除)
	 */
	public static String clearMark(String sql) {
		if (StringUtil.isBlank(sql)) {
			return sql;
		}
		int endMarkIndex;
		// 剔除形式的多行注释
		int markIndex = sql.indexOf("", markIndex);
			// update 2024-7-8 兼容sql中存在收尾的情况
			if (endMarkIndex == -1) {
				break;
			} else if (endMarkIndex == sql.length() - 3) {
				sql = sql.substring(0, markIndex);
				break;
			} else {
				sql = sql.substring(0, markIndex).concat(BLANK).concat(sql.substring(endMarkIndex + 3));
			}
			markIndex = sql.indexOf(" 这类冲突
		if (sql.contains("--")) {
			String[] sqlAry = sql.split("\n");
			StringBuilder sqlBuffer = new StringBuilder();
			int startMask;
			int lineMaskIndex;
			String lineStr;
			int meter = 0;
			for (String line : sqlAry) {
				lineStr = line.trim();
				// 排除掉-- 开头和空行
				if (!"".equals(lineStr) && !lineStr.startsWith("--")) {
					// 不包含-- 直接拼接
					lineMaskIndex = line.indexOf("--");
					if (meter > 0) {
						sqlBuffer.append("\n");
					}
					// 增加一个空白
					sqlBuffer.append(BLANK);
					if (lineMaskIndex == -1) {
						sqlBuffer.append(line);
					} else {
						// 找到-- 单行注释开始位置(排除在'',""中间的场景)
						startMask = findStartLineMask(line, lineMaskIndex);
						if (startMask > 0) {
							sqlBuffer.append(line.substring(0, startMask));
						} else {
							sqlBuffer.append(line);
						}
					}
					meter++;
				}
			}
			sql = sqlBuffer.toString();
		}
		// 剔除sql末尾的分号逗号(开发过程中容易忽视)
		if (sql.endsWith(";") || sql.endsWith(",")) {
			sql = sql.substring(0, sql.length() - 1);
		}
		// 剔除全角(update 2023-10-24 框架不做干涉)
		// sql = sql.replaceAll("\\:", ":").replaceAll("\\=", "=").replaceAll("\\.",
		// ".");
		return sql;
	}

	/**
	 * @param sql
	 * @param lineMaskIndex
	 * @return
	 * @TODO 找到行注释的开始位置
	 */
	private static int findStartLineMask(String sql, int lineMaskIndex) {
		// 单引号、双引号、hint注释结尾 的最后位置
		int lastIndex = StringUtil.matchLastIndex(sql, "\'|\"|\\*\\/");
		// 行注释的位置在单引号等最后位置后面,直接返回
		if (lineMaskIndex > lastIndex) {
			return lineMaskIndex;
		}
		// 单引号之间
		int start = StringUtil.matchIndex(sql, "\'");
		int symMarkEnd;
		while (start != -1) {
			symMarkEnd = StringUtil.getSymMarkIndex("'", "'", sql, start);
			if (symMarkEnd != -1) {
				sql = sql.substring(0, start).concat(loopBlank(symMarkEnd - start + 1))
						.concat(sql.substring(symMarkEnd + 1));
				start = StringUtil.matchIndex(sql, "\'");
			} else {
				break;
			}
		}
		// 双引号之间
		start = StringUtil.matchIndex(sql, "\"");
		while (start != -1) {
			symMarkEnd = StringUtil.getSymMarkIndex("\"", "\"", sql, start);
			if (symMarkEnd != -1) {
				sql = sql.substring(0, start).concat(loopBlank(symMarkEnd - start + 1))
						.concat(sql.substring(symMarkEnd + 1));
				start = StringUtil.matchIndex(sql, "\"");
			} else {
				break;
			}
		}
		// hint /*+ all */ 或 /*! all*/ 注释
		start = sql.indexOf("/*");
		while (start != -1) {
			symMarkEnd = StringUtil.getSymMarkIndex("/*", "*/", sql, start);
			if (symMarkEnd != -1) {
				sql = sql.substring(0, start).concat(loopBlank(symMarkEnd - start + 2))
						.concat(sql.substring(symMarkEnd + 2));
				start = sql.indexOf("/*");
			} else {
				break;
			}
		}
		return sql.indexOf("--");
	}

	private static String loopBlank(int size) {
		if (size == 0) {
			return "";
		}
		StringBuilder result = new StringBuilder();
		for (int i = 0; i < size; i++) {
			result.append(BLANK);
		}
		return result.toString();
	}

	/**
	 * @param typeHandler
	 * @param queryStr
	 * @param params
	 * @param voClass
	 * @param rowCallbackHandler
	 * @param conn
	 * @param dbType
	 * @param ignoreAllEmptySet
	 * @param colFieldMap
	 * @return
	 * @throws Exception
	 * @todo 获取单条记录
	 */
	public static Object loadByJdbcQuery(TypeHandler typeHandler, final String queryStr, final Object[] params,
			final Class voClass, final RowCallbackHandler rowCallbackHandler, final Connection conn,
			final Integer dbType, final boolean ignoreAllEmptySet, final HashMap colFieldMap)
			throws Exception {
		List result = findByJdbcQuery(typeHandler, queryStr, params, voClass, rowCallbackHandler, null, conn, dbType,
				ignoreAllEmptySet, colFieldMap, -1, -1);
		if (result != null && !result.isEmpty()) {
			if (result.size() > 1) {
				throw new IllegalAccessException("查询结果不唯一,loadByJdbcQuery 方法只针对单条结果的数据查询!");
			}
			return result.get(0);
		}
		return null;
	}

	/**
	 * @param conn
	 * @param sequence
	 * @param dbType
	 * @return
	 * @throws DataAccessException
	 * @TODO 提供独立的获取sequence下一个值的方法
	 */
	public static Object getSequenceValue(Connection conn, String sequence, Integer dbType) throws DataAccessException {
		String sql = "";
		if (dbType == DBType.POSTGRESQL || dbType == DBType.POSTGRESQL15 || dbType == DBType.KINGBASE
				|| dbType == DBType.H2) {
			sql = "select nextval('" + sequence + "')";
		} else if (dbType == DBType.SQLSERVER) {
			sql = "select NEXT VALUE FOR " + sequence;
		} else if (dbType == DBType.GAUSSDB || dbType == DBType.MOGDB || dbType == DBType.OPENGAUSS
				|| dbType == DBType.VASTBASE || dbType == DBType.OCEANBASE || dbType == DBType.ORACLE
				|| dbType == DBType.ORACLE11 || dbType == DBType.DM || dbType == DBType.STARDB
				|| dbType == DBType.OSCAR) {
			sql = "select " + sequence + ".nextval";
		} else {
			sql = "select NEXTVAL FOR " + sequence;
		}
		PreparedStatement pst = null;
		ResultSet rs = null;
		Object id = null;
		try {
			SqlExecuteStat.showSql("获取sequence下一个值", sql, null);
			pst = conn.prepareStatement(sql);
			rs = pst.executeQuery();
			while (rs.next()) {
				id = rs.getObject(1);
				break;
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new DataAccessException("获取sequence={} 值失败!错误信息:{}", sequence, e.getMessage());
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e) {

				}
				rs = null;
			}
			if (pst != null) {
				try {
					pst.close();
				} catch (Exception e) {

				}
				pst = null;
			}
		}
		return id;
	}

	/**
	 * @param typeHandler
	 * @param queryStr
	 * @param params
	 * @param voClass
	 * @param rowCallbackHandler
	 * @param decryptHandler
	 * @param conn
	 * @param dbType
	 * @param ignoreAllEmptySet
	 * @param colFieldMap
	 * @param fetchSize
	 * @param maxRows
	 * @return
	 * @throws Exception
	 * @todo sql 查询并返回List集合结果
	 */
	public static List findByJdbcQuery(TypeHandler typeHandler, final String queryStr, final Object[] params,
			final Class voClass, final RowCallbackHandler rowCallbackHandler, final DecryptHandler decryptHandler,
			final Connection conn, final Integer dbType, final boolean ignoreAllEmptySet,
			final HashMap colFieldMap, final int fetchSize, final int maxRows) throws Exception {
		ResultSet rs = null;
		PreparedStatement pst = conn.prepareStatement(queryStr, ResultSet.TYPE_FORWARD_ONLY,
				ResultSet.CONCUR_READ_ONLY);
		if (fetchSize > 0) {
			pst.setFetchSize(fetchSize);
		}
		if (maxRows > 0) {
			pst.setMaxRows(maxRows);
		}
		List result = (List) preparedStatementProcess(null, pst, rs, new PreparedStatementResultHandler() {
			@Override
			public void execute(Object obj, PreparedStatement pst, ResultSet rs) throws Exception {
				try {
					setParamsValue(typeHandler, conn, dbType, pst, params, null, 0);
					rs = pst.executeQuery();
					this.setResult(processResultSet(typeHandler, rs, voClass, rowCallbackHandler, decryptHandler, 0,
							ignoreAllEmptySet, colFieldMap));
				} catch (Exception e) {
					throw e;
				} finally {
					if (rs != null) {
						rs.close();
						rs = null;
					}
				}
			}
		});
		// 为null返回一个空集合
		if (result == null) {
			result = new ArrayList();
		}
		return result;
	}

	/**
	 * @param typeHandler
	 * @param rs
	 * @param voClass
	 * @param rowCallbackHandler
	 * @param decryptHandler
	 * @param startColIndex
	 * @param ignoreAllEmptySet
	 * @param colFieldMap
	 * @return
	 * @throws Exception
	 * @todo 处理sql查询时的结果集, 当没有反调或voClass反射处理时以数组方式返回resultSet的数据
	 */
	public static List processResultSet(TypeHandler typeHandler, ResultSet rs, Class voClass,
			RowCallbackHandler rowCallbackHandler, final DecryptHandler decryptHandler, int startColIndex,
			boolean ignoreAllEmptySet, final HashMap colFieldMap) throws Exception {
		// 记录行记数器
		int index = 0;
		// 提取数据预警阈值
		int warnThresholds = SqlToyConstants.getWarnThresholds();
		// 是否超出阈值
		boolean warnLimit = false;
		// 最大阀值
		long maxThresholds = SqlToyConstants.getMaxThresholds();
		boolean maxLimit = false;
		// 最大值要大于等于警告阀值
		if (maxThresholds > 1 && maxThresholds <= warnThresholds) {
			maxThresholds = warnThresholds;
		}
		List result;
		if (voClass != null) {
			result = reflectResultToVO(typeHandler, decryptHandler, rs, voClass, ignoreAllEmptySet, colFieldMap);
		} else if (rowCallbackHandler != null) {
			while (rs.next()) {
				rowCallbackHandler.processRow(rs, index);
				index++;
				// 超出预警阀值
				if (index == warnThresholds) {
					warnLimit = true;
				}
				// 提取数据超过上限(-1表示不限制)
				if (index == maxThresholds) {
					maxLimit = true;
					break;
				}
			}
			result = rowCallbackHandler.getResult();
		} else {
			// 取得字段列数,在没有rowCallbackHandler用数组返回
			int rowCnt = rs.getMetaData().getColumnCount();
			List items = new ArrayList();
			Object fieldValue = null;
			boolean allNull = true;
			while (rs.next()) {
				allNull = true;
				List rowData = new ArrayList();
				for (int i = startColIndex; i < rowCnt; i++) {
					// 处理clob
					fieldValue = rs.getObject(i + 1);
					if (fieldValue != null) {
						allNull = false;
						if (fieldValue instanceof java.sql.Clob) {
							fieldValue = clobToString((java.sql.Clob) fieldValue);
						}
					}
					rowData.add(fieldValue);
				}
				if (!(allNull && ignoreAllEmptySet)) {
					items.add(rowData);
				}
				index++;
				// 超出预警阀值
				if (index == warnThresholds) {
					warnLimit = true;
				}
				// 超出最大提取数据阀值,直接终止数据提取
				if (index == maxThresholds) {
					maxLimit = true;
					break;
				}
			}
			result = items;
		}
		// 提醒实际提取数据量
		if (warnLimit) {
			logger.warn("Large Result:total={}>={}", index, warnThresholds);
		}
		// 超过最大提取数据阀值
		if (maxLimit) {
			logger.error("Max Large Result:total={}>={}", index, maxThresholds);
		}
		return result;
	}

	/**
	 * @param typeHandler
	 * @param updateSql
	 * @param rowDatas
	 * @param batchSize
	 * @param insertCallhandler
	 * @param updateTypes
	 * @param autoCommit
	 * @param conn
	 * @param dbType
	 * @return
	 * @throws Exception
	 * @todo 通过jdbc方式批量插入数据,一般提供给数据采集时或插入临时表使用,一般采用hibernate 方式插入
	 */
	public static Long batchUpdateByJdbc(TypeHandler typeHandler, final String updateSql, final Collection rowDatas,
			final int batchSize, final InsertRowCallbackHandler insertCallhandler, final Integer[] updateTypes,
			final Boolean autoCommit, final Connection conn, final Integer dbType) throws Exception {
		if (rowDatas == null || rowDatas.isEmpty()) {
			logger.error("执行batchUpdateByJdbc 数据为空,sql={}", updateSql);
			return 0L;
		}
		// sql中?参数数量
		int argsCnt = StringUtil.matchCnt(SqlConfigParseUtils.clearDblQuestMark(updateSql),
				SqlConfigParseUtils.ARG_REGEX);
		PreparedStatement pst = null;
		long updateCount = 0;
		try {
			boolean hasSetAutoCommit = false;
			boolean useCallHandler = true;
			// 是否使用反调方式
			if (insertCallhandler == null) {
				useCallHandler = false;
			}
			// 是否自动提交
			if (autoCommit != null && autoCommit.booleanValue() != conn.getAutoCommit()) {
				conn.setAutoCommit(autoCommit.booleanValue());
				hasSetAutoCommit = true;
			}
			pst = conn.prepareStatement(updateSql);
			int totalRows = rowDatas.size();
			boolean useBatch = (totalRows > 1) ? true : false;
			Object rowData;
			int index = 0;
			// 批处理计数器
			int meter = 0;
			int paramCnt;
			for (Iterator iter = rowDatas.iterator(); iter.hasNext();) {
				rowData = iter.next();
				index++;
				if (rowData != null) {
					// 使用反调
					if (useCallHandler) {
						insertCallhandler.process(pst, index, rowData);
					} else {
						// 使用对象properties方式传值
						if (rowData.getClass().isArray()) {
							Object[] tmp = CollectionUtil.convertArray(rowData);
							paramCnt = tmp.length;
							// 第一次做长度校验
							if (meter == 0 && argsCnt != paramCnt) {
								throw new IllegalArgumentException(
										"batchUpdate sql中的?参数数量:" + argsCnt + " 跟实际传参数量:" + paramCnt + " 不等,请检查!");
							}
							for (int i = 0; i < paramCnt; i++) {
								setParamValue(typeHandler, conn, dbType, pst, tmp[i],
										updateTypes == null ? -1 : updateTypes[i], i + 1);
							}
						} else if (rowData instanceof Collection) {
							Collection tmp = (Collection) rowData;
							paramCnt = tmp.size();
							// 第一次做长度校验
							if (meter == 0 && argsCnt != paramCnt) {
								throw new IllegalArgumentException(
										"batchUpdate sql中的?参数数量:" + argsCnt + " 跟实际传参数量:" + paramCnt + " 不等,请检查!");
							}
							int tmpIndex = 0;
							for (Iterator tmpIter = tmp.iterator(); tmpIter.hasNext();) {
								setParamValue(typeHandler, conn, dbType, pst, tmpIter.next(),
										updateTypes == null ? -1 : updateTypes[tmpIndex], tmpIndex + 1);
								tmpIndex++;
							}
						}
					}
					meter++;
					// 批量执行
					if (useBatch) {
						pst.addBatch();
						if ((meter % batchSize) == 0 || index == totalRows) {
							int[] updateRows = pst.executeBatch();
							for (int t : updateRows) {
								updateCount = updateCount + ((t > 0) ? t : 0);
							}
							pst.clearBatch();
						}
					} // 单条执行
					else {
						updateCount = pst.executeUpdate();
					}
				}
			}
			if (hasSetAutoCommit) {
				conn.setAutoCommit(!autoCommit);
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			throw e;
		} finally {
			try {
				if (pst != null) {
					pst.close();
					pst = null;
				}
			} catch (SQLException se) {
				logger.error(se.getMessage(), se);
			}
		}
		return updateCount;
	}

	/**
	 * @param typeHandler
	 * @param treeTableModel
	 * @param conn
	 * @param dbType
	 * @return
	 * @throws Exception
	 * @todo 计算树形结构表中的:节点层级、节点对应所有上级节点的路径、是否叶子节点
	 */
	public static boolean wrapTreeTableRoute(TypeHandler typeHandler, final TreeTableModel treeTableModel,
			Connection conn, final Integer dbType) throws Exception {
		if (StringUtil.isBlank(treeTableModel.getTableName()) || StringUtil.isBlank(treeTableModel.getIdField())
				|| StringUtil.isBlank(treeTableModel.getPidField())
				|| StringUtil.isBlank(treeTableModel.getPidValue())) {
			logger.error("请设置树形表的table名称、id字段名称、pid字段名称、pidValue值!");
			throw new IllegalArgumentException("没有对应的table名称、id字段名称、pid字段名称、pidValue值");
		}
		String flag = "";
		// 判断是否字符串类型
		if (treeTableModel.isChar()) {
			flag = "'";
		}
		String nodeRouteField = ReservedWordsUtil.convertWord(treeTableModel.getNodeRouteField(), dbType);
		String nodeLevelField = ReservedWordsUtil.convertWord(treeTableModel.getNodeLevelField(), dbType);
		String idField = ReservedWordsUtil.convertWord(treeTableModel.getIdField(), dbType);
		String pidField = ReservedWordsUtil.convertWord(treeTableModel.getPidField(), dbType);
		String tableName = ReservedWordsUtil.convertSimpleSql(treeTableModel.getTableName(), dbType);
		String conditions = ReservedWordsUtil.convertWord(treeTableModel.getConditions(), dbType);
		String leafField = ReservedWordsUtil.convertWord(treeTableModel.getLeafField(), dbType);
		// 修改nodeRoute和nodeLevel
		if (StringUtil.isNotBlank(nodeRouteField) && StringUtil.isNotBlank(nodeLevelField)) {
			StringBuilder nextNodeQueryStr = new StringBuilder("select ").append(idField).append(",")
					.append(nodeRouteField).append(",").append(pidField).append(" from ").append(tableName)
					.append(" where ").append(pidField).append(" in (${inStr})");
			String idInfoSql = "select ".concat(nodeLevelField).concat(",").concat(nodeRouteField).concat(" from ")
					.concat(tableName).concat(" where ").concat(idField).concat("=").concat(flag)
					.concat(treeTableModel.getPidValue().toString()).concat(flag);
			// 附加条件(如一张表里面分账套,将多家企业的部门信息放于一张表中,附加条件就可以是账套)
			if (StringUtil.isNotBlank(conditions)) {
				idInfoSql = idInfoSql.concat(" and ").concat(conditions);
			}
			// 获取层次等级
			List idInfo = findByJdbcQuery(typeHandler, idInfoSql, null, null, null, null, conn, dbType, false, null,
					SqlToyConstants.FETCH_SIZE, -1);
			// 设置第一层level
			int nodeLevel = 0;
			String nodeRoute = "";
			if (idInfo != null && !idInfo.isEmpty()) {
				if (((List) idInfo.get(0)).get(0) == null) {
					throw new DataAccessException("表中id=" + treeTableModel.getPidValue() + "对应的节点等级字段:" + nodeLevelField
							+ "值为null,不要越层调用wrapTreeTableRoute!");
				}
				if (((List) idInfo.get(0)).get(1) == null) {
					throw new DataAccessException("表中id=" + treeTableModel.getPidValue() + "对应的节点路径字段:" + nodeRouteField
							+ "值为null,不要越层调用wrapTreeTableRoute!");
				}
				nodeLevel = Integer.parseInt(((List) idInfo.get(0)).get(0).toString());
				nodeRoute = ((List) idInfo.get(0)).get(1).toString();
			}
			StringBuilder updateLevelAndRoute = new StringBuilder("update ").append(tableName).append(" set ")
					.append(nodeLevelField).append("=?,").append(nodeRouteField).append("=? ").append(" where ")
					.append(idField).append("=?");
			// 附加条件
			if (StringUtil.isNotBlank(conditions)) {
				nextNodeQueryStr.append(" and ").append(conditions);
				updateLevelAndRoute.append(" and ").append(conditions);
			}
			// 模拟指定节点的信息
			HashMap pidsMap = new HashMap();
			pidsMap.put(treeTableModel.getPidValue().toString(), nodeRoute);
			// 下级节点
			List ids;
			if (StringUtil.isNotBlank(treeTableModel.getIdValue())) {
				StringBuilder firstNextNodeQuery = new StringBuilder("select ").append(idField).append(",")
						.append(nodeRouteField).append(",").append(pidField).append(" from ").append(tableName)
						.append(" where ").append(idField).append("=?");
				if (StringUtil.isNotBlank(conditions)) {
					firstNextNodeQuery.append(" and ").append(conditions);
				}
				ids = findByJdbcQuery(typeHandler, firstNextNodeQuery.toString(),
						new Object[] { treeTableModel.getIdValue() }, null, null, null, conn, dbType, false, null,
						SqlToyConstants.FETCH_SIZE, -1);
			} else {
				ids = findByJdbcQuery(typeHandler,
						nextNodeQueryStr.toString().replaceFirst("\\$\\{inStr\\}",
								flag + treeTableModel.getPidValue() + flag),
						null, null, null, null, conn, dbType, false, null, SqlToyConstants.FETCH_SIZE, -1);
			}
			if (ids != null && !ids.isEmpty()) {
				processNextLevel(typeHandler, updateLevelAndRoute.toString(), nextNodeQueryStr.toString(),
						treeTableModel, pidsMap, ids, nodeLevel + 1, conn, dbType);
			}
		}
		// 设置节点是否为叶子节点,(mysql不支持update table where in 机制)
		if (StringUtil.isNotBlank(leafField)) {
			// 将所有记录先全部设置为叶子节点(isLeaf=1)
			StringBuilder updateLeafSql = new StringBuilder();
			updateLeafSql.append("update ").append(tableName);
			updateLeafSql.append(" set ").append(leafField).append("=1");
			// 附加条件(保留)
			if (StringUtil.isNotBlank(conditions)) {
				updateLeafSql.append(" where ").append(conditions);
			}
			// 先将所有节点设置为叶子
			executeSql(typeHandler, updateLeafSql.toString(), null, null, conn, dbType, null, true);
			// 再设置父节点的记录为非叶子节点(isLeaf=0)
			StringBuilder updateTrunkLeafSql = new StringBuilder();
			updateTrunkLeafSql.append("update ").append(tableName);
			// 支持mysql8 update 2018-5-11
			if (dbType == DataSourceUtils.DBType.MYSQL || dbType == DataSourceUtils.DBType.MYSQL57) {
				// update sys_organ_info a inner join (select t.organ_pid from
				// sys_organ_info t) b
				// on a.organ_id=b.organ_pid set IS_LEAF=0
				// set field=value
				updateTrunkLeafSql.append(" inner join (select ");
				updateTrunkLeafSql.append(pidField);
				updateTrunkLeafSql.append(" from ").append(tableName);
				if (StringUtil.isNotBlank(conditions)) {
					updateTrunkLeafSql.append(" where ").append(conditions);
				}
				updateTrunkLeafSql.append(") as t_wrapLeaf ");
				updateTrunkLeafSql.append(" on ");
				updateTrunkLeafSql.append(idField).append("=t_wrapLeaf.").append(pidField);
				updateTrunkLeafSql.append(" set ");
				updateTrunkLeafSql.append(leafField).append("=0");
				if (StringUtil.isNotBlank(conditions)) {
					updateTrunkLeafSql.append(" where ").append(conditions);
				}
			} else {
				// update organ_info set IS_LEAF=0
				// where organ_id in (select organ_pid from organ_info)
				updateTrunkLeafSql.append(" set ");
				updateTrunkLeafSql.append(leafField).append("=0");
				updateTrunkLeafSql.append(" where ").append(idField);
				updateTrunkLeafSql.append(" in (select ").append(pidField);
				updateTrunkLeafSql.append(" from ").append(tableName);
				if (StringUtil.isNotBlank(conditions)) {
					updateTrunkLeafSql.append(" where ").append(conditions);
				}
				updateTrunkLeafSql.append(") ");
				if (StringUtil.isNotBlank(conditions)) {
					updateTrunkLeafSql.append(" and ").append(conditions);
				}
			}
			executeSql(typeHandler, updateTrunkLeafSql.toString(), null, null, conn, dbType, null, false);
		}
		return true;
	}

	/**
	 * @param typeHandler
	 * @param updateLevelAndRoute
	 * @param nextNodeQueryStr
	 * @param treeTableModel
	 * @param pidsMap
	 * @param ids
	 * @param nodeLevel
	 * @param conn
	 * @param dbType
	 * @throws Exception
	 * @todo TreeTableRoute中处理下一层级的递归方法,逐层计算下一级节点的节点层次和路径
	 */
	private static void processNextLevel(TypeHandler typeHandler, final String updateLevelAndRoute,
			final String nextNodeQueryStr, final TreeTableModel treeTableModel, final HashMap pidsMap, List ids,
			final int nodeLevel, Connection conn, final int dbType) throws Exception {
		// 修改节点level和节点路径
		batchUpdateByJdbc(typeHandler, updateLevelAndRoute, ids, 500, new InsertRowCallbackHandler() {
			@Override
			public void process(PreparedStatement pst, int index, Object rowData) throws SQLException {
				String id = ((List) rowData).get(0).toString();
				// 获得父节点id和父节点路径
				String pid = ((List) rowData).get(2).toString();
				String nodeRoute = (String) pidsMap.get(pid);
				int size = treeTableModel.getIdLength();
				if (nodeRoute == null || "".equals(nodeRoute.trim())) {
					nodeRoute = "";
					if (!treeTableModel.isChar() || treeTableModel.isAppendZero()) {
						// 负数
						if (NumberUtil.isInteger(pid) && pid.indexOf("-") == 0) {
							nodeRoute = nodeRoute.concat("-")
									.concat(StringUtil.addLeftZero2Len(pid.substring(1), size - 1));
						} else {
							nodeRoute = nodeRoute.concat(StringUtil.addLeftZero2Len(pid, size));
						}
					} else {
						nodeRoute = nodeRoute.concat(StringUtil.addRightBlank2Len(pid, size));
					}
				} else {
					nodeRoute = nodeRoute.trim();
				}
				// update 2018-1-9 增加判断是否以逗号结尾,解决修改过程中出现双逗号问题
				if (!nodeRoute.endsWith(treeTableModel.getSplitSign())) {
					nodeRoute = nodeRoute.concat(treeTableModel.getSplitSign());
				}
				// 回置节点的nodeRoute值
				if (!treeTableModel.isChar() || treeTableModel.isAppendZero()) {
					nodeRoute = nodeRoute.concat(StringUtil.addLeftZero2Len(id, size));
				} else {
					nodeRoute = nodeRoute.concat(StringUtil.addRightBlank2Len(id, size));
				}
				((List) rowData).set(1, nodeRoute);
				// 节点等级
				pst.setInt(1, nodeLevel);
				// 节点路径(当节点路径长度不做补充统一长度操作,则末尾自动加上一个分割符)
				pst.setString(2, nodeRoute + ((size < 2) ? treeTableModel.getSplitSign() : ""));
				if (treeTableModel.isChar()) {
					pst.setString(3, id);
				} else {
					pst.setLong(3, Long.parseLong(id));
				}
			}
		}, null, null, conn, dbType);
		// 处理节点的下一层次
		int size = ids.size();
		int fromIndex = 0;
		int toIndex = -1;
		// 避免in()中的参数过多,每次500个
		String inStrs;
		List subIds = null;
		List nextIds = null;
		boolean exist = false;
		while (toIndex < size) {
			fromIndex = toIndex + 1;
			toIndex += 500;
			if (toIndex >= size - 1) {
				toIndex = size - 1;
				exist = true;
			}
			if (fromIndex >= toIndex) {
				subIds = new ArrayList();
				subIds.add(ids.get(toIndex));
			} else {
				subIds = ids.subList(fromIndex, toIndex + 1);
			}
			inStrs = combineQueryInStr(subIds, 0, null, treeTableModel.isChar());
			// 获取下一层节点
			nextIds = findByJdbcQuery(typeHandler, nextNodeQueryStr.replaceFirst("\\$\\{inStr\\}", inStrs), null, null,
					null, null, conn, dbType, false, null, SqlToyConstants.FETCH_SIZE, -1);
			// 递归处理下一层
			if (nextIds != null && !nextIds.isEmpty()) {
				processNextLevel(typeHandler, updateLevelAndRoute, nextNodeQueryStr, treeTableModel,
						CollectionUtil.hashList(subIds, 0, 1, true), nextIds, nodeLevel + 1, conn, dbType);
			}
			if (exist) {
				break;
			}
		}
	}

	/**
	 * @param conn
	 * @param sqlContent
	 * @param batchSize
	 * @param autoCommit
	 * @throws Exception
	 * @todo sql文件自动创建到数据库
	 */
	public static void executeBatchSql(Connection conn, String sqlContent, Integer batchSize, Boolean autoCommit)
			throws Exception {
		String splitSign = DataSourceUtils.getDatabaseSqlSplitSign(conn);
		// 剔除sql中的注释
		sqlContent = SqlUtil.clearMark(sqlContent);
		if (splitSign.indexOf("go") != -1) {
			sqlContent = clearMistyChars(sqlContent, BLANK);
		}
		// 分割成多个子语句
		String[] statments = StringUtil.splitExcludeSymMark(sqlContent, splitSign, sqlCommentfilters);
		boolean hasSetAutoCommit = false;
		// 是否自动提交
		if (autoCommit != null && autoCommit.booleanValue() != conn.getAutoCommit()) {
			conn.setAutoCommit(autoCommit.booleanValue());
			hasSetAutoCommit = true;
		}
		Statement stat = null;
		try {
			stat = conn.createStatement();
			int meter = 0;
			int realBatch = (batchSize == null || batchSize.intValue() > 1) ? batchSize.intValue() : 100;
			int totalRows = statments.length;
			int i = 0;
			for (String sql : statments) {
				if (StringUtil.isNotBlank(sql)) {
					meter++;
					logger.debug("正在批量执行的sql:{}", sql);
					stat.addBatch(sql);
				}
				if ((meter % realBatch) == 0 || i + 1 == totalRows) {
					stat.executeBatch();
					stat.clearBatch();
				}
				i++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw e;
		} finally {
			if (stat != null) {
				stat.close();
				stat = null;
			}
		}
		// 恢复conn原始autoCommit默认值
		if (hasSetAutoCommit) {
			conn.setAutoCommit(!autoCommit);
		}
	}

	/**
	 * @param sql
	 * @param judgeUpcase
	 * @return
	 * @todo 判断sql语句中是否有order by排序
	 */
	public static boolean hasOrderBy(String sql, boolean judgeUpcase) {
		// 最后的收括号位置
		int lastBracketIndex = sql.lastIndexOf(")");
		boolean result = false;
		int orderByIndex = StringUtil.matchLastIndex(sql, ORDER_BY_PATTERN, 1);
		// 存在order by
		if (orderByIndex > lastBracketIndex) {
			result = true;
		}
		// 特殊处理 order by,通过ORder这种非常规写法代表分页时是否进行外层包裹(建议废弃使用)
		if (judgeUpcase) {
			int upcaseOrderBy = StringUtil.matchLastIndex(sql, UPCASE_ORDER_PATTERN, 1);
			if (upcaseOrderBy > lastBracketIndex) {
				result = false;
			}
		}
		return result;
	}

	/**
	 * @param clob
	 * @return
	 * @todo clob转换成字符串
	 */
	public static String clobToString(Clob clob) {
		if (clob == null) {
			return null;
		}
		StringBuffer sb = new StringBuffer(1024 * 8);// 8K
		Reader clobStream = null;
		try {
			clobStream = clob.getCharacterStream();
			char[] b = new char[1024];// 每次获取1K
			int i = 0;
			while ((i = clobStream.read(b)) != -1) {
				sb.append(b, 0, i);
			}
		} catch (Exception ex) {
			sb = null;
		} finally {
			closeQuietly(clobStream);
		}
		if (sb == null) {
			return null;
		}
		return sb.toString();
	}

	/**
	 * @param typeHandler
	 * @param executeSql
	 * @param params
	 * @param paramsType
	 * @param conn
	 * @param dbType
	 * @param autoCommit
	 * @param processWord
	 * @return
	 * @throws Exception
	 * @todo 执行Sql语句完成修改操作
	 */
	public static Long executeSql(TypeHandler typeHandler, final String executeSql, final Object[] params,
			final Integer[] paramsType, final Connection conn, final Integer dbType, final Boolean autoCommit,
			boolean processWord) throws Exception {
		// 对sql进行关键词符号替换
		String realSql = processWord ? ReservedWordsUtil.convertSql(executeSql, dbType) : executeSql;
		SqlExecuteStat.showSql("execute sql=", realSql, params);
		boolean hasSetAutoCommit = false;
		Long updateCounts = null;
		if (autoCommit != null) {
			if (!autoCommit == conn.getAutoCommit()) {
				conn.setAutoCommit(autoCommit);
				hasSetAutoCommit = true;
			}
		}
		PreparedStatement pst = conn.prepareStatement(realSql);
		Object result = preparedStatementProcess(null, pst, null, new PreparedStatementResultHandler() {
			@Override
			public void execute(Object obj, PreparedStatement pst, ResultSet rs) throws SQLException, IOException {
				// sqlserver 存在timestamp不能赋值问题,通过对象完成的修改、插入忽视掉timestamp列
				if (dbType == DBType.SQLSERVER && paramsType != null) {
					setSqlServerParamsValue(typeHandler, conn, dbType, pst, params, paramsType, 0);
				} else {
					setParamsValue(typeHandler, conn, dbType, pst, params, paramsType, 0);
				}
				pst.executeUpdate();
				// 返回update的记录数量
				this.setResult(Long.valueOf(pst.getUpdateCount()));
			}
		});
		if (result != null) {
			updateCounts = (Long) result;
		}
		if (hasSetAutoCommit && autoCommit != null) {
			conn.setAutoCommit(!autoCommit);
		}
		return updateCounts;
	}

	/**
	 * @param idValue
	 * @param idType
	 * @return
	 * @todo 转换主键数据类型(主键生成只支持数字和字符串类型)
	 */
	public static Object convertIdValueType(Object idValue, String idType) {
		if (idValue == null) {
			return null;
		}
		if (StringUtil.isBlank(idType)) {
			return idValue;
		}
		// 按照优先顺序对比
		if ("java.lang.string".equals(idType)) {
			return idValue.toString();
		}
		if ("java.lang.integer".equals(idType)) {
			return Integer.valueOf(idValue.toString());
		}
		if ("java.lang.long".equals(idType)) {
			return Long.valueOf(idValue.toString());
		}
		if ("java.math.biginteger".equals(idType)) {
			return new BigInteger(idValue.toString());
		}
		if ("java.math.bigdecimal".equals(idType)) {
			return new BigDecimal(idValue.toString());
		}
		if ("long".equals(idType)) {
			return Long.valueOf(idValue.toString()).longValue();
		}
		if ("int".equals(idType)) {
			return Integer.valueOf(idValue.toString()).intValue();
		}
		if ("java.lang.short".equals(idType)) {
			return Short.valueOf(idValue.toString());
		}
		if ("short".equals(idType)) {
			return Short.valueOf(idValue.toString()).shortValue();
		}
		return idValue;
	}

	/**
	 * @param closeables 可关闭的流对象列表
	 * @throws IOException
	 * @todo 关闭一个或多个流对象
	 */
	public static void close(Closeable... closeables) throws IOException {
		if (closeables != null) {
			for (Closeable closeable : closeables) {
				if (closeable != null) {
					closeable.close();
				}
			}
		}
	}

	/**
	 * @param closeables 可关闭的流对象列表
	 * @todo 关闭一个或多个流对象
	 */
	public static void closeQuietly(Closeable... closeables) {
		try {
			close(closeables);
		} catch (IOException e) {
			// do nothing
		}
	}

	/**
	 * @param sql
	 * @param clearMistyChar
	 * @return
	 * @todo 判断是否内包含union 查询,即是否是select * from (select * from t union select * from
	 *       t2 ) 形式的查询,将所有()剔除后判定是否有union 存在
	 */
	public static boolean hasUnion(String sql, boolean clearMistyChar) {
		if (!StringUtil.matches(sql, UNION_PATTERN)) {
			return false;
		}
		// 存在with as ,先剔除
		if (StringUtil.matches(BLANK + sql, SqlToyConstants.withPattern)) {
			SqlWithAnalysis sqlWith = new SqlWithAnalysis(sql);
			sql = sqlWith.getRejectWithSql();
		}
		String tmpSql = BLANK + (clearMistyChar ? clearMistyChars(sql, BLANK) : sql);
		StringBuilder lastSql = new StringBuilder(tmpSql);
		// 找到第一个select 所对称的from位置,排查掉子查询中的内容
		int fromIndex = StringUtil.getSymMarkMatchIndex(SELECT_REGEX, FROM_REGEX, tmpSql.toLowerCase(), 0);
		if (fromIndex != -1) {
			lastSql.delete(0, fromIndex);
		}
		// 删除所有对称的括号中的内容
		int start = lastSql.indexOf("(");
		int symMarkEnd;
		while (start != -1) {
			symMarkEnd = StringUtil.getSymMarkIndex("(", ")", lastSql.toString(), start);
			if (symMarkEnd != -1) {
				lastSql.delete(start, symMarkEnd + 1);
				start = lastSql.indexOf("(");
			} else {
				break;
			}
		}
		if (StringUtil.matches(lastSql.toString(), UNION_PATTERN)) {
			return true;
		}
		return false;
	}

	/**
	 * @param entityMeta
	 * @param sql
	 * @return
	 * @TODO 转化对象字段名称为数据库字段名称
	 */
	public static String convertFieldsToColumns(EntityMeta entityMeta, String sql) {
		if (StringUtil.isBlank(sql)) {
			return sql;
		}
		String key = entityMeta.getTableName() + "_" + sql;
		// 从缓存中直接获取,避免每次都处理提升效率
		if (convertSqlMap.containsKey(key)) {
			return convertSqlMap.get(key);
		}
		String[] fields = entityMeta.getFieldsArray();
		StringBuilder sqlBuff = new StringBuilder();
		// 末尾补齐一位空白,便于后续取index时避免越界
		String realSql = sql.concat(BLANK);
		int start = 0;
		int index;
		String preSql;
		String columnName;
		char preChar, tailChar;
		String varSql;
		boolean isBlank;
		// 转换sql中的对应 vo属性为具体表字段
		for (String field : fields) {
			columnName = entityMeta.getColumnName(field);
			// 对象属性和(表字段一致且非关键词),无需处理
			if (columnName != null
					&& (!columnName.equalsIgnoreCase(field) || ReservedWordsUtil.isKeyWord(columnName))) {
				start = 0;
				// 定位匹配到field,判断匹配的前一位和后一位字符,前一位是:的属于条件,且都不能是字符和数字以及下划线
				index = StringUtil.indexOfIgnoreCase(realSql, field, start);
				while (index != -1) {
					preSql = realSql.substring(start, index);
					isBlank = false;
					if (StringUtil.matches(preSql, "\\s$")) {
						isBlank = true;
					}
					varSql = preSql.trim();
					// 首位字符不是数字(48~57)、(A-Z|a-z)字母(65~90,97~122)、下划线(95)、冒号(58)
					if (!"".equals(varSql)) {
						preChar = varSql.charAt(varSql.length() - 1);
					} else {
						preChar = ' ';
					}
					tailChar = realSql.charAt(index + field.length());
					// 非条件参数(58为冒号),结尾字符不能是数字、字母和(
					if (((isBlank && preChar != 58) || (preChar > 58 && preChar < 65)
							|| (preChar > 90 && preChar < 97 && preChar != 95) || preChar < 48 || preChar > 122)
							&& ((tailChar > 58 && tailChar < 65) || (tailChar > 90 && tailChar < 97 && tailChar != 95)
									|| (tailChar < 48 && tailChar != 40) || tailChar > 122)) {
						// 含关键词处理
						if (preSql.endsWith("[") || preSql.endsWith("`") || preSql.endsWith("\"")) {
							sqlBuff.append(preSql).append(columnName);
						} else {
							sqlBuff.append(preSql).append(ReservedWordsUtil.convertWord(columnName, null));
						}
						start = index + field.length();
					}
					index = StringUtil.indexOfIgnoreCase(realSql, field, index + field.length());
				}
				if (start > 0) {
					sqlBuff.append(realSql.substring(start));
					realSql = sqlBuff.toString();
					sqlBuff.delete(0, sqlBuff.length());
				}
			}
		}
		// 放入缓存
		convertSqlMap.put(key, realSql);
		return realSql;
	}

	/**
	 * @param entityMeta
	 * @return
	 * @TODO 组合动态条件
	 */
	public static String wrapWhere(EntityMeta entityMeta) {
		String[] fields = entityMeta.getFieldsArray();
		StringBuilder sqlBuff = new StringBuilder(" 1=1 ");
		String columnName;
		for (String field : fields) {
			columnName = ReservedWordsUtil.convertWord(entityMeta.getColumnName(field), null);
			sqlBuff.append("#[and ").append(columnName).append("=:").append(field).append("]");
		}
		return sqlBuff.toString();
	}

	/**
	 * @param sqlToyContext
	 * @param entityClass
	 * @param sql
	 * @return
	 * @TODO 针对对象查询补全sql中的select * from table 部分,适度让代码中的sql简短一些(并不推荐)
	 */
	public static String completionSql(SqlToyContext sqlToyContext, Class entityClass, String sql) {
		if (null == entityClass || SqlConfigParseUtils.isNamedQuery(sql)) {
			return sql;
		}
		String sqlLow = sql.toLowerCase().trim();
		// 包含了select 或with as、show、desc 模式开头直接返回
		if (StringUtil.matches(sqlLow, "^(select|with|show|desc)\\W")) {
			return sql;
		}
		// 存储过程模式直接返回
		if (StringUtil.matches(sqlLow, "^\\{?\\W*call\\W+")) {
			return sql;
		}
		// 非entity实体类型
		if (!sqlToyContext.isEntity(entityClass)) {
			// from 开头补齐select *
			if (StringUtil.matches(sqlLow, "^from\\W")) {
				return "select * ".concat(sql);
			}
			return sql;
		}
		EntityMeta entityMeta = sqlToyContext.getEntityMeta(entityClass);
		// from 开头补齐select col1,col2,...
		if (StringUtil.matches(sqlLow, "^from\\W")) {
			return "select ".concat(entityMeta.getAllColumnNames()).concat(BLANK).concat(sql);
		}
		// 没有where和from(排除 select * from table),补齐select * from table where
		if (!StringUtil.matches(BLANK.concat(sqlLow), "\\W(from|where)\\W")) {
			if (StringUtil.matches(sqlLow, "^(and|or)\\W")) {
				return "select ".concat(entityMeta.getAllColumnNames()).concat(" from ")
						.concat(entityMeta.getSchemaTable(null, null)).concat(" where 1=1 ").concat(sql);
			}
			return "select ".concat(entityMeta.getAllColumnNames()).concat(" from ")
					.concat(entityMeta.getSchemaTable(null, null)).concat(" where ").concat(sql);
		}
		// where开头 补齐select * from
		if (StringUtil.matches(sqlLow, "^where\\W")) {
			return "select ".concat(entityMeta.getAllColumnNames()).concat(" from ")
					.concat(entityMeta.getSchemaTable(null, null)).concat(BLANK).concat(sql);
		}
		return sql;
	}

	/**
	 * @param sql
	 * @param dbType
	 * @return
	 * @todo 判断sql中是否存在lock锁
	 */
	public static boolean hasLock(String sql, Integer dbType) {
		if (sql == null) {
			return false;
		}
		if (StringUtil.matches(sql, "(?i)\\s+for\\s+update")) {
			return true;
		}
		// sqlserver
		if (dbType != null && dbType.intValue() == DBType.SQLSERVER) {
			if (StringUtil.matches(sql,
					"(?i)with\\s*\\(\\s*(rowlock|xlock|updlock|holdlock|nolock|readpast)?\\,?\\s*(rowlock|xlock|updlock|holdlock|nolock|readpast)\\s*\\)")) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @param defaultValue
	 * @return
	 * @todo 处理sqlserver default值为((value))问题
	 */
	public static String clearDefaultValue(String defaultValue) {
		if (defaultValue == null) {
			return null;
		}
		if ("".equals(defaultValue.trim())) {
			return defaultValue;
		}
		String result = defaultValue;
		// 针对postgresql
		if (result.indexOf("(") != -1 && result.indexOf(")") != -1 && result.indexOf("::") != -1) {
			result = result.substring(result.indexOf("(") + 1, result.indexOf("::"));
		}
		// postgresql
		if (result.indexOf("'") != -1 && result.indexOf("::") != -1) {
			result = result.substring(0, result.indexOf("::"));
		}
		if (result.startsWith("((") && result.endsWith("))")) {
			result = result.substring(2, result.length() - 2);
		}
		if (result.startsWith("(") && result.endsWith(")")) {
			result = result.substring(1, result.length() - 1);
		}
		if (result.startsWith("'") && result.endsWith("'")) {
			result = result.substring(1, result.length() - 1);
		}
		if (result.startsWith("\"") && result.endsWith("\"")) {
			result = result.substring(1, result.length() - 1);
		}
		return result.trim();
	}

	/**
	 * @param source
	 * @param target
	 * @return
	 * @todo 替换换行、回车、tab符号;\r 换行、\t tab符合、\n 回车
	 */
	public static String clearMistyChars(String source, String target) {
		if (source == null) {
			return null;
		}
		// 回车换行前后的空白也剔除
		return source.replaceAll("\\s*(\r|\n)\\s*", target).replaceAll("\t", target);
	}

	/**
	 * @param dbType
	 * @param fieldMeta
	 * @param createSqlTimeFields
	 * @return
	 * @TODO 获取数据库时间字符串
	 */
	public static String getDBTime(Integer dbType, FieldMeta fieldMeta, IgnoreCaseSet createSqlTimeFields) {
		if (fieldMeta == null || createSqlTimeFields == null || createSqlTimeFields.isEmpty()) {
			return null;
		}
		int fieldType = fieldMeta.getType();
		// 统一需要处理的字段、且是日期、时间类型
		if (createSqlTimeFields.contains(fieldMeta.getFieldName()) && (fieldType == java.sql.Types.DATE
				|| fieldType == java.sql.Types.TIME || fieldType == java.sql.Types.TIME_WITH_TIMEZONE
				|| fieldType == java.sql.Types.TIMESTAMP || fieldType == java.sql.Types.TIMESTAMP_WITH_TIMEZONE)) {
			// 只支持now
			if (dbType == DBType.CLICKHOUSE) {
				return "now()";
			}
			// time
			if (fieldType == java.sql.Types.TIME || fieldType == java.sql.Types.TIME_WITH_TIMEZONE
					|| "java.time.localtime".equals(fieldMeta.getFieldType())
					|| "java.sql.time".equals(fieldMeta.getFieldType())) {
				if (dbType == DBType.MYSQL || dbType == DBType.MYSQL57 || dbType == DBType.TIDB
						|| dbType == DBType.SQLITE || dbType == DBType.H2 || dbType == DBType.POSTGRESQL
						|| dbType == DBType.POSTGRESQL15 || dbType == DBType.KINGBASE || dbType == DBType.DB2
						|| dbType == DBType.OCEANBASE) {
					return "current_time";
				} else if (dbType == DBType.GAUSSDB || dbType == DBType.OPENGAUSS || dbType == DBType.MOGDB
						|| dbType == DBType.VASTBASE || dbType == DBType.STARDB || dbType == DBType.OSCAR) {
					return "now()";
				} else if (dbType == DBType.SQLSERVER) {
					return "getdate()";
				} else {
					return "current_timestamp";
				}
			} // timestamp
			else if ("java.time.localdate".equals(fieldMeta.getFieldType())) {
				if (dbType == DBType.SQLSERVER) {
					return "getdate()";
				}
				return "current_date";
			} else {
				return "current_timestamp";
			}
		}
		return null;
	}

	/**
	 * @param argValue
	 * @return
	 * @TODO 验证sql in的参数,要么是''形式的字符,要么是数字
	 */
	public static boolean validateInArg(String argValue) {
		// 判断是否有关键词
		boolean hasSqlKeyWord = StringUtil.matches(BLANK + argValue, SQLINJECT_PATTERN);
		String argTrim = argValue.replaceAll("\\s+", "");
		String[] args = null;
		// 判断是否有逗号分割
		if (argTrim.indexOf(",") != -1) {
			// 以逗号开始或结束不符合in的写法
			if (argTrim.startsWith(",") || argTrim.endsWith(",")) {
				return false;
			}
			// 分割成数组进行检查
			args = argTrim.split("\\,");
		} else {
			// 单个字符串组成单一数组,形成统一的检查格式
			args = new String[] { argTrim };
		}
		// 1:char;2:string;3:数字
		int argType = 3;
		if (args[0].startsWith("'") && args[0].endsWith("'")) {
			argType = 1;
		} else if (args[0].startsWith("\"") && args[0].endsWith("\"")) {
			argType = 2;
		}
		// 无逗号分隔符,且是数子 不能直接in (123) 输出,返回false,依旧以pst.setString(index,"123")设置条件值
		if (argType == 3 && args.length == 1) {
			return false;
		}
		for (String item : args) {
			if (argType == 1) {
				if (!item.startsWith("'") || !item.endsWith("'")) {
					return false;
				}
				// 有关键词时,校验是否多个单引号,避免:''+(select field from table)+''模式
				if (hasSqlKeyWord && StringUtil.matchCnt(item, ONE_QUOTA, 0) > 2) {
					return false;
				}
			} else if (argType == 2) {
				if (!item.startsWith("\"") || !item.endsWith("\"")) {
					return false;
				}
				// 有关键词时,校验是否多个双引号,避免:""+(select field from table)+""模式
				if (hasSqlKeyWord && StringUtil.matchCnt(item, DOUBLE_QUOTA, 0) > 2) {
					return false;
				}
			} else if (!NumberUtil.isNumber(item)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * @param sqlArgValue
	 * @param addSingleQuotation 是否加单引号
	 * @return
	 * @TODO 将参数值转成字符传
	 */
	public static String toSqlString(Object sqlArgValue, boolean addSingleQuotation) {
		if (sqlArgValue == null) {
			return "null";
		}
		// 参数前面是否是条件比较符号,如果是比较符号针对日期、字符串加单引号
		String sign = addSingleQuotation ? "'" : "";
		String valueStr;
		int nanoValue;
		String timeStr;
		Object paramValue;
		if (sqlArgValue instanceof Enum) {
			paramValue = BeanUtil.getEnumValue(sqlArgValue);
		} else {
			paramValue = sqlArgValue;
		}
		if (paramValue instanceof CharSequence) {
			valueStr = sign + paramValue + sign;
		} else if (paramValue instanceof Timestamp) {
			valueStr = sign + DateUtil.formatDate(paramValue, "yyyy-MM-dd HH:mm:ss.SSS") + sign;
		} else if (paramValue instanceof LocalDateTime) {
			nanoValue = ((LocalDateTime) paramValue).getNano();
			if (nanoValue > 0) {
				if (SqlToyConstants.localDateTimeFormat != null
						&& !SqlToyConstants.localDateTimeFormat.equals("auto")) {
					timeStr = DateUtil.formatDate(paramValue, SqlToyConstants.localDateTimeFormat);
				} else {
					timeStr = DateUtil.formatDate(paramValue, "yyyy-MM-dd HH:mm:ss") + DateUtil.processNano(nanoValue);
				}
			} else {
				timeStr = DateUtil.formatDate(paramValue, "yyyy-MM-dd HH:mm:ss");
			}
			valueStr = sign + timeStr + sign;
		} else if (paramValue instanceof LocalDate) {
			valueStr = sign + DateUtil.formatDate(paramValue, "yyyy-MM-dd") + sign;
		} else if (paramValue instanceof LocalTime) {
			nanoValue = ((LocalTime) paramValue).getNano();
			if (nanoValue > 0) {
				if (SqlToyConstants.localTimeFormat != null && !SqlToyConstants.localTimeFormat.equals("auto")) {
					timeStr = DateUtil.formatDate(paramValue, SqlToyConstants.localTimeFormat);
				} else {
					timeStr = DateUtil.formatDate(paramValue, "HH:mm:ss") + DateUtil.processNano(nanoValue);
				}
			} else {
				timeStr = DateUtil.formatDate(paramValue, "HH:mm:ss");
			}
			valueStr = sign + timeStr + sign;
		} else if (paramValue instanceof Time) {
			valueStr = sign + DateUtil.formatDate(paramValue, "HH:mm:ss") + sign;
		} else if (paramValue instanceof Date) {
			valueStr = sign + DateUtil.formatDate(paramValue, "yyyy-MM-dd HH:mm:ss") + sign;
		} else if (paramValue instanceof Object[]) {
			valueStr = combineArray((Object[]) paramValue);
		} else if (paramValue instanceof Collection) {
			valueStr = combineArray(((Collection) paramValue).toArray());
		} else {
			valueStr = "" + paramValue;
		}
		return valueStr;
	}

	/**
	 * @param array
	 * @return
	 * @TODO 组合in参数
	 */
	public static String combineArray(Object[] array) {
		if (array == null || array.length == 0) {
			return "null";
		}
		StringBuilder result = new StringBuilder();
		Object value;
		int nanoValue;
		String timeStr;
		for (int i = 0; i < array.length; i++) {
			if (i > 0) {
				result.append(",");
			}
			value = array[i];
			if (value == null) {
				result.append("null");
			} else {
				// 支持枚举类型
				if (value instanceof Enum) {
					value = BeanUtil.getEnumValue(value);
				}
				if (value instanceof CharSequence) {
					result.append("'" + value + "'");
				} else if (value instanceof Timestamp) {
					result.append("'" + DateUtil.formatDate(value, "yyyy-MM-dd HH:mm:ss.SSS") + "'");
				} else if (value instanceof LocalDateTime) {
					nanoValue = ((LocalDateTime) value).getNano();
					if (nanoValue > 0) {
						if (SqlToyConstants.localDateTimeFormat != null
								&& !SqlToyConstants.localDateTimeFormat.equals("auto")) {
							timeStr = DateUtil.formatDate(value, SqlToyConstants.localDateTimeFormat);
						} else {
							timeStr = DateUtil.formatDate(value, "yyyy-MM-dd HH:mm:ss")
									+ DateUtil.processNano(nanoValue);
						}
					} else {
						timeStr = DateUtil.formatDate(value, "yyyy-MM-dd HH:mm:ss");
					}
					result.append("'" + timeStr + "'");
				} else if (value instanceof LocalDate) {
					result.append("'" + DateUtil.formatDate(value, "yyyy-MM-dd") + "'");
				} else if (value instanceof LocalTime) {
					nanoValue = ((LocalTime) value).getNano();
					if (nanoValue > 0) {
						if (SqlToyConstants.localTimeFormat != null
								&& !SqlToyConstants.localTimeFormat.equals("auto")) {
							timeStr = DateUtil.formatDate(value, SqlToyConstants.localTimeFormat);
						} else {
							timeStr = DateUtil.formatDate(value, "HH:mm:ss") + DateUtil.processNano(nanoValue);
						}
					} else {
						timeStr = DateUtil.formatDate(value, "HH:mm:ss");
					}
					result.append("'" + timeStr + "'");
				} else if (value instanceof Time) {
					result.append("'" + DateUtil.formatDate(value, "HH:mm:ss") + "'");
				} else if (value instanceof Date) {
					result.append("'" + DateUtil.formatDate(value, "yyyy-MM-dd HH:mm:ss") + "'");
				} else {
					result.append("" + value);
				}
			}
		}
		return result.toString();
	}

	/**
	 * merge into sql特定数据库下需要补充;符号(sql加工成SqlToyConfig 时统一清理掉了分号)
	 * 
	 * @param sql
	 * @param dbType
	 * @return
	 */
	public static String adjustMergeIntoSql(String sql, Integer dbType) {
		String sqlTrimLow = sql.toLowerCase().trim();
		// 非merge into 不做任何处理
		if (!StringUtil.matches(sqlTrimLow, MERGE_INTO_PATTERN)) {
			return sql;
		}
		boolean isBranchEnd = sqlTrimLow.endsWith(";");
		// sqlserver merge into 要以;结尾
		if (dbType == DBType.SQLSERVER && !isBranchEnd) {
			return sql.concat(";");
		}
		// 其他数据库merge into 以;结尾则需要剔除分号
		if (isBranchEnd && dbType != DBType.SQLSERVER) {
			return sql.substring(0, sql.lastIndexOf(";"));
		}
		return sql;
	}

	/**
	 * 

* 主要用于分页场景(极端特殊情况自定义count-sql): *

  • 1、获取select 对称的from位置;
  • *
  • 2、判断是否复杂查询(分页是否select count(1) from (sql)),获取from 对称的where的位置
  • *
  • 非分页:sqlserver 锁查询,提取from位置,此场景sql简单,不会产生问题
  • *

    * * @param sql * @param startRegex * @param endRegex * @param startIndex * @return */ public static int getSymMarkIndexExcludeKeyWords(String sql, String startRegex, String endRegex, int startIndex) { Pattern endPattern = Pattern.compile(endRegex); String sqlLow = sql.toLowerCase(); int startRegexIndex = StringUtil.matchIndex(sqlLow, startRegex, startIndex)[0]; int endRegIndex = StringUtil.getSymMarkMatchIndex(startRegex, endRegex, sqlLow, startIndex); // 就一个endPattern直接返回 if (endRegIndex > 0 && StringUtil.matchCnt(startIndex == 0 ? sqlLow : sqlLow.substring(startIndex), endPattern) == 1) { return endRegIndex; } // 如果有select concat(a,'(') from 判断就可能有问题 String startMark = "(", endMark = ")"; int startBreaket = sqlLow.indexOf(startMark, startRegexIndex); // 在select 和from之间有()符号,要排除select (day from()) from 场景 if (startBreaket < endRegIndex && startBreaket > 0) { // 删除所有对称的括号中的内容 int start = startBreaket; int symMarkEnd; String tail; while (start != -1) { symMarkEnd = StringUtil.getSymMarkIndex(startMark, endMark, sqlLow, start); if (symMarkEnd != -1) { tail = sqlLow.substring(symMarkEnd); // 替换掉对称()中的select、from、where为等长字符,避免找select 对称的from位置形成干扰 sqlLow = sqlLow.substring(0, start) + sqlLow.substring(start, symMarkEnd).replace("from", "AAAA") .replace("select", "AAAAAA").replace("where", "AAAAA") + tail; // 后续sql中没有endPattern则停止处理 if (!StringUtil.matches(tail, endPattern)) { break; } start = sqlLow.indexOf(startMark, symMarkEnd); } else { break; } } int lastEndRegIndex = StringUtil.getSymMarkMatchIndex(startRegex, endRegex, sqlLow, startIndex); if (lastEndRegIndex == -1) { return endRegIndex; } return lastEndRegIndex; } return endRegIndex; } }




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy