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

com.gitee.qdbp.jdbc.sql.SqlBuffer Maven / Gradle / Ivy

package com.gitee.qdbp.jdbc.sql;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import com.gitee.qdbp.able.jdbc.model.DbFieldName;
import com.gitee.qdbp.able.jdbc.model.DbRawValue;
import com.gitee.qdbp.jdbc.model.DbType;
import com.gitee.qdbp.jdbc.model.DbVersion;
import com.gitee.qdbp.jdbc.model.OmitStrategy;
import com.gitee.qdbp.jdbc.plugins.DbPluginHelper;
import com.gitee.qdbp.jdbc.plugins.SqlDialect;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.IndentTools;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * SQL容器
 *
 * @author zhaohuihua
 * @version 190601
 */
public class SqlBuffer implements Serializable {

    /** SerialVersionUID **/
    private static final long serialVersionUID = 1L;

    /** 数据库方言 **/
    private final SqlDialect dialect;
    /** 插件容器 **/
    private final DbPluginHelper plugins;

    /** 占位符当前序号 **/
    private int index;
    /** SQL缓存容器 **/
    private final List buffer;
    /** 快捷方式实例 **/
    private SqlBuilder shortcut;

    /** 构造函数 **/
    public SqlBuffer(DbType dbType, DbPluginHelper plugins) {
        this(plugins.buildSqlDialect(dbType), plugins);
    }

    /** 构造函数 **/
    public SqlBuffer(DbVersion version, DbPluginHelper plugins) {
        this(plugins.buildSqlDialect(version), plugins);
    }

    /** 构造函数 **/
    public SqlBuffer(SqlDialect dialect, DbPluginHelper plugins) {
        this.dialect = dialect;
        this.plugins = plugins;
        this.index = 0;
        this.buffer = new ArrayList<>();
    }

    /** 构造函数 **/
    protected SqlBuffer(SqlDialect dialect, DbPluginHelper plugins, SqlBuilder shortcut) {
        this(dialect, plugins);
        this.shortcut = shortcut;
    }

    /** 返回当前实例的快捷方式实例 **/
    public SqlBuilder shortcut() {
        if (this.shortcut == null) {
            this.shortcut = new SqlBuilder(this);
        }
        return this.shortcut;
    }

    /** 数据库方言 **/
    public SqlDialect sqlDialect() {
        return dialect;
    }

    /** 插件容器 **/
    public DbPluginHelper plugins() {
        return plugins;
    }

    /** 清除内容 **/
    public void clear() {
        this.buffer.clear();
    }

    /**
     * 将指定SQL片段追加到SQL后面
     * 
     * @param part SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(String part) {
        StringItem si = getLastStringItem();
        si.append(part);
        return this;
    }

    /**
     * 将指定SQL片段追加到SQL后面
     * 
     * @param part SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(char... part) {
        StringItem si = getLastStringItem();
        si.append(part);
        return this;
    }

    /**
     * 将指定SQL片段追加到SQL后面
     * 
     * @param part SQL片段
     * @param suffix 后缀
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(String part, char suffix) {
        StringItem si = getLastStringItem();
        si.append(part, suffix);
        return this;
    }

    /**
     * 将指定SQL片段追加到SQL后面
     * 
     * @param prefix 前缀
     * @param part SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(char prefix, String part) {
        StringItem si = getLastStringItem();
        si.append(prefix, part);
        return this;
    }

    /**
     * 将指定SQL片段追加到SQL后面
     * 
     * @param prefix 前缀
     * @param part SQL片段
     * @param suffix 后缀
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(char prefix, String part, char suffix) {
        StringItem si = getLastStringItem();
        si.append(prefix, part, suffix);
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param part SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(String part) {
        StringItem si = getFirstStringItem();
        si.prepend(part);
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param part SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(char... part) {
        StringItem si = getFirstStringItem();
        si.prepend(part);
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param part SQL片段
     * @param suffix 后缀
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(String part, char suffix) {
        StringItem si = getFirstStringItem();
        si.prepend(part, suffix);
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param prefix 前缀
     * @param part SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(char prefix, String part) {
        StringItem si = getFirstStringItem();
        si.prepend(prefix, part);
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param prefix 前缀
     * @param part SQL片段
     * @param suffix 后缀
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(char prefix, String part, char suffix) {
        StringItem si = getFirstStringItem();
        si.prepend(prefix, part, suffix);
        return this;
    }

    /**
     * 将指定SQL片段追加到SQL语句后面
     * 
     * @param another SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(SqlBuffer another) {
        if (another != null && !another.isEmpty()) {
            another.copyTo(this);
        }
        return this;
    }

    /**
     * 将指定SQL片段追加到SQL语句后面
     * 
     * @param prefix 前缀
     * @param another SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer append(char prefix, SqlBuffer another) {
        if (another != null && !another.isEmpty()) {
            this.append(prefix);
            another.copyTo(this);
        }
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param another SQL片段
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(SqlBuffer another) {
        if (another != null && !another.isEmpty()) {
            // 复制到临时缓冲区
            SqlBuffer temp = another.copy();
            // 序号递增, 空出前面的位置
            this.raiseIndex(another.index);
            // 增加到SQL语句最前面
            this.buffer.addAll(0, temp.buffer);
        }
        return this;
    }

    /**
     * 将指定SQL片段增加到SQL语句最前面
     * 
     * @param another SQL片段
     * @param suffix 后缀
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer prepend(SqlBuffer another, char suffix) {
        if (another != null && !another.isEmpty()) {
            this.prepend(suffix);
            // 序号递增, 空出前面的位置
            this.raiseIndex(another.index);
            // 增加到SQL语句最前面
            this.buffer.addAll(0, another.buffer);
        }
        return this;
    }

    private StringItem getLastStringItem() {
        Item last = this.buffer.isEmpty() ? null : this.buffer.get(this.buffer.size() - 1);
        if (last instanceof StringItem) {
            return (StringItem) last;
        } else {
            StringItem si = new StringItem();
            this.buffer.add(si);
            return si;
        }
    }

    private StringItem getFirstStringItem() {
        Item first = this.buffer.isEmpty() ? null : this.buffer.get(0);
        if (first instanceof StringItem) {
            return (StringItem) first;
        } else {
            StringItem si = new StringItem();
            this.buffer.add(0, si);
            return si;
        }
    }

    /** 序号递增, 空出前面的位置 **/
    protected void raiseIndex(int offset) {
        if (offset == 0) {
            return;
        }
        this.index += offset;
        for (Item item : this.buffer) {
            if (item instanceof VariableItem) {
                VariableItem variable = ((VariableItem) item);
                variable.index += offset;
            }
        }
    }

    /**
     * 增加变量, 同时将变量以占位符追加到SQL语句中
     * 
     * @param value 变量
     * @return 返回当前SQL容器用于连写
     */
    public SqlBuffer addVariable(Object value) {
        if (value == null) {
            this.buffer.add(new VariableItem(index++, null));
        } else if (value instanceof SqlBuffer) {
            append((SqlBuffer) value);
        } else if (value instanceof SqlBuilder) {
            append(((SqlBuilder) value).out());
        } else if (value instanceof DbRawValue) {
            DbRawValue raw = (DbRawValue) value;
            this.buffer.add(new RawValueItem(raw.toString()));
        } else if (value instanceof Collection) {
            this.addVariables(new ArrayList<>((Collection) value));
        } else if (value.getClass().isArray()) {
            this.addVariables(ConvertTools.parseList(value));
        } else if (value instanceof DbFieldName) {
            // this.append(value.toString());
            // 缺少环境数据, 无法将字段名转换为列名
            throw new IllegalArgumentException("CanNotSupportedVariableType: DbFieldName");
        } else {
            this.buffer.add(new VariableItem(index++, value));
        }
        return this;
    }

    private void addVariables(List values) {
        List items = SqlTools.duplicateRemoval(values);
        OmitStrategy omits = plugins.getOmitStrategyOfInSql();
        for (int i = 0, count = items.size(); i < count; i++) {
            Object value = items.get(i);
            if (i > 0) {
                this.append(',');
            }
            if (omits.getMinSize() > 0 && count > omits.getMinSize()) {
                this.tryOmit(i, count, omits.getKeepSize());
            }
            this.buffer.add(new VariableItem(index++, value));
        }
    }

    /** 删除左右两则的空白字符 **/
    public SqlBuffer trim() {
        trimLeft();
        trimRight();
        return this;
    }

    /** 删除左侧空白 **/
    public SqlBuffer trimLeft() {
        if (buffer.isEmpty()) {
            return this;
        }
        for (int i = 0, last = buffer.size() - 1; i <= last; i++) {
            Item item = buffer.get(i);
            if (item instanceof StringItem) {
                StringItem stringItem = (StringItem) item;
                int size = stringItem.trimLeft();
                if (size == 0) {
                    continue;
                }
            }
            return this;
        }
        return this;
    }

    /** 删除右侧空白 **/
    public SqlBuffer trimRight() {
        if (buffer.isEmpty()) {
            return this;
        }
        for (int i = buffer.size() - 1; i >= 0; i--) {
            Item item = buffer.get(i);
            if (item instanceof StringItem) {
                StringItem stringItem = (StringItem) item;
                int size = stringItem.trimRight();
                if (size == 0) {
                    continue;
                }
            }
            return this;
        }
        return this;
    }

    /**
     * 在第1个非空字符前插入前缀
* 删除prefixOverrides, 插入prefix
* 如果内容全部为空, 将不会做任何处理, 返回false
* 如果prefix为空, 又没有找到prefixOverrides, 也会返回false * * @param prefix 待插入的前缀 * @param prefixOverrides 待替换的前缀, 不区分大小写, 支持以|拆分的多个前缀, 如AND|OR * @return 是否有变更 */ public boolean insertPrefix(String prefix, String prefixOverrides) { if (buffer.isEmpty() || VerifyTools.isAllBlank(prefix, prefixOverrides)) { return false; } for (int i = 0; i < buffer.size(); i++) { Item item = buffer.get(i); if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; boolean changed = stringItem.insertPrefix(prefix, prefixOverrides); if (changed) { return true; } } else if (item instanceof VariableItem || item instanceof RawValueItem) { if (VerifyTools.isBlank(prefix)) { return false; } StringItem element = new StringItem(); element.append(prefix); // 如果前缀的结尾不是符号, 就要加空格; 符号排除了右括号, 因为右括号后面也要加空格 if (!SqlTools.Text.endsWithSqlSymbol(prefix, ')')) { element.append(' '); } buffer.add(i, element); return true; } else if (item instanceof OmitItem) { continue; } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } return false; } /** * 在最后1个非空字符后插入后缀
* 删除suffixOverrides, 插入suffix
* 如果内容全部为空, 将不会做任何处理, 返回false
* 如果suffix为空, 又没有找到suffixOverrides, 也会返回false * * @param suffix 待插入的后缀 * @param suffixOverrides 待替换的后缀, 不区分大小写, 支持以|拆分的多个后缀, 如AND|OR * @return 是否有变更 */ public boolean insertSuffix(String suffix, String suffixOverrides) { if (buffer.isEmpty() || VerifyTools.isAllBlank(suffix, suffixOverrides)) { return false; } for (int i = buffer.size() - 1; i >= 0; i--) { Item item = buffer.get(i); if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; boolean changed = stringItem.insertSuffix(suffix, suffixOverrides); if (changed) { return true; } } else if (item instanceof VariableItem || item instanceof RawValueItem) { if (VerifyTools.isBlank(suffix)) { return false; } StringItem element = new StringItem(); if (!SqlTools.Text.startsWithSqlSymbol(suffix)) { element.append(' '); } element.append(suffix); buffer.add(i + 1, element); return true; } else if (item instanceof OmitItem) { continue; } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } return false; } public boolean isEmpty() { return buffer.isEmpty(); } public boolean isBlank() { if (buffer.isEmpty()) { return true; } for (Item item : buffer) { if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; String stringValue = stringItem.getValue().toString(); if (stringValue.trim().length() > 0) { return false; } } else if (item instanceof RawValueItem) { RawValueItem rawValueItem = (RawValueItem) item; String stringValue = rawValueItem.getValue(); if (stringValue.trim().length() > 0) { return false; } } else if (item instanceof VariableItem) { VariableItem variableItem = (VariableItem) item; if (variableItem.getValue() != null) { return false; } } else if (item instanceof OmitItem) { continue; } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } return true; } /** * 超级长的SQL在输出日志时可以省略掉一部分
* 省略哪一部分, 用startOmit()/endOmit()来标识起止位置 * * @return 返回当前SQL容器用于连写 */ public SqlBuffer startOmit() { this.buffer.add(new OmitItem(true)); return this; } /** * 超级长的SQL在输出日志时可以省略掉一部分
* 省略哪一部分, 用startOmit()/endOmit()来标识起止位置 * * @return 返回当前SQL容器用于连写 */ public SqlBuffer endOmit() { this.buffer.add(new OmitItem(false)); return this; } /** * 传入size和当前index, 自动计算, 插入省略标记
* 日志只取前3行+后3行; 因此在第3行后面开始省略, 在后3行之前结束省略
* 注意: 如果有换行符, 最好放在换行符后面 * * @param index 当前行数 * @param count 总行数 * @return 返回当前SQL容器用于连写 */ public SqlBuffer tryOmit(int index, int count) { return tryOmit(index, count, 3); } /** * 传入size和当前index, 自动计算, 插入省略标记
* 日志只取前3行+后3行; 因此在第3行后面开始省略, 在后3行之前结束省略
* 注意: 如果有换行符, 最好放在换行符后面 * * @param index 当前行数(从0开始) * @param count 总行数 * @param limit 保留多少行(前后各保留limit行) * @return 返回当前SQL容器用于连写 */ public SqlBuffer tryOmit(int index, int count, int limit) { if (count <= limit * 2 + 2) { // 如果总行数只比保留行数多2行, 就没必要省略了 return this; } if (index == limit) { this.buffer.add(new OmitItem(true, index)); // 开始省略 } else if (index == count - limit) { this.buffer.add(new OmitItem(false, index)); // 结束省略 } return this; } /** * 所有缩进增加或减少n个TAB * * @param size 缩进量: 正数为增加, 负数为减少 * @return 返回当前SQL容器用于连写 */ public SqlBuffer tabAll(int size) { return this.tabAll(size, true); } /** * 所有缩进增加或减少n个TAB * * @param size 缩进量: 正数为增加, 负数为减少 * @param leading 开头要不要缩进 * @return 返回当前SQL容器用于连写 */ public SqlBuffer tabAll(int size, boolean leading) { if (size == 0) { return this; } boolean first = true; boolean needPrepend = false; // 以VariableItem开头, 且leading=true且size>0时, 需要在前面添加TAB for (Item item : this.buffer) { if (item == null) { continue; } if (item instanceof StringItem) { StringItem temp = (StringItem) item; if (temp.value.length() == 0) { continue; } // blankLineIndent=空行要不要缩进, 一定要传true // 因为这里的value只是片段, 后面可能还有内容, 并不能判断空行 IndentTools.space.tabAll(temp.value, size, first && leading, true); first = false; } else if (item instanceof RawValueItem) { RawValueItem temp = (RawValueItem) item; if (temp.value.length() == 0) { continue; } temp.setValue(IndentTools.space.tabAll(temp.value, size, first && leading, true)); first = false; } else if (item instanceof VariableItem) { if (first) { first = false; if (leading && size > 0) { needPrepend = true; } } } else if (item instanceof OmitItem) { continue; } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } if (needPrepend) { this.prepend(IndentTools.getIndentTabs(size)); } return this; } /** * 所有缩进设置为1个TAB, 以最小的缩进为基准 * * @return 返回当前SQL容器用于连写 * @deprecated 含义不明晰
* 如果是设置为1个TAB, 应改为indentAll(1);
* 如果是在原有的基础上缩进1个TAB, 应改为tabAll(1); */ @Deprecated public SqlBuffer indentAll() { return indentAll(1, true); } /** * 所有缩进设置为n个TAB, 以最小的缩进为基准 * * @param size 缩进量: 必须为正数或0, 负数视为0 * @return 返回当前SQL容器用于连写 */ public SqlBuffer indentAll(int size) { return this.indentAll(size, true); } /** * 所有缩进设置为n个TAB, 以最小的缩进为基准 * * @param size 缩进量: 必须为正数或0, 负数视为0 * @param leading 开头要不要缩进 * @return 返回当前SQL容器用于连写 */ public SqlBuffer indentAll(int size, boolean leading) { // minIndent<0表示未找到缩进, 只有leading=false才有可能<0 int minIndent = SqlTools.Indent.countMinIndentSize(this, leading); if (minIndent < 0 || size == minIndent) { return this; } return this.tabAll(size - minIndent, leading); } /** * 复制 * * @return 副本 */ public SqlBuffer copy() { SqlBuffer target = new SqlBuffer(dialect, plugins); this.copyTo(target); return target; } /** * 复制到另一个缓存容器中 * * @param target 目标容器 */ public void copyTo(SqlBuffer target) { for (Item item : this.buffer) { if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; target.getLastStringItem().append(stringItem.getValue().toString()); } else if (item instanceof VariableItem) { VariableItem variable = ((VariableItem) item); target.buffer.add(new VariableItem(target.index++, variable.getValue())); } else if (item instanceof RawValueItem) { RawValueItem rawItem = (RawValueItem) item; target.buffer.add(new RawValueItem(rawItem.getValue())); } else if (item instanceof OmitItem) { OmitItem omitItem = (OmitItem) item; target.buffer.add(new OmitItem(omitItem.enabled(), omitItem.index())); } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } } /** 获取预编译SQL语句 **/ public String getPreparedSqlString() { StringBuilder sql = new StringBuilder(); for (Item item : this.buffer) { if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; sql.append(stringItem.getValue()); } else if (item instanceof VariableItem) { sql.append(':').append(((VariableItem) item).getKey()); } else if (item instanceof RawValueItem) { RawValueItem rawValueItem = (RawValueItem) item; sql.append(plugins.resolveRawValue(rawValueItem.getValue(), dialect)); } else if (item instanceof OmitItem) { continue; } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } return sqlFormatToString(sql); } /** 获取预编译SQL参数 **/ public Map getPreparedVariables() { Map map = new HashMap<>(); for (Item item : this.buffer) { if (item instanceof VariableItem) { VariableItem variable = ((VariableItem) item); map.put(variable.getKey(), plugins.variableToDbValue(variable.getValue(), dialect)); } } return map; } /** 获取可执行SQL语句(预编译参数替换为拼写式参数) **/ public String getExecutableSqlString() { StringBuilder sql = new StringBuilder(); for (Item item : this.buffer) { if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; sql.append(stringItem.getValue()); } else if (item instanceof VariableItem) { VariableItem variable = ((VariableItem) item); String string = plugins.variableToString(variable.value, dialect); sql.append(string); } else if (item instanceof RawValueItem) { RawValueItem rawValueItem = (RawValueItem) item; sql.append(plugins.resolveRawValue(rawValueItem.getValue(), dialect)); } else if (item instanceof OmitItem) { continue; } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } return sqlFormatToString(sql); } /** * 获取用于日志输出的SQL语句(预编译参数替换为拼写式参数)
* 如果参数值长度超过100会被截断(例如大片的HTML富文本代码等)
* 批量SQL会省略部分语句不输出到日志中(几百几千个批量操作会导致SQL太长) * * @return SQL语句 */ public String getLoggingSqlString() { return getLoggingSqlString(true); } /** * 获取用于日志输出的SQL语句(预编译参数替换为拼写式参数) * * @param omitMode 是否使用省略模式
* 如果参数值长度超过100会被截断(例如大片的HTML富文本代码等);
* 批量SQL会省略部分语句不输出到日志中(几百几千个批量操作会导致SQL太长) * @return SQL语句 */ public String getLoggingSqlString(boolean omitMode) { return getLoggingSqlString(omitMode, true); } private String getLoggingSqlString(boolean omitMode, boolean format) { int valueLimit = 100; StringBuilder sql = new StringBuilder(); int charCount = 0; int lineCount = 0; // 解决OmitItem嵌套的问题 Stack omitStacks = new Stack<>(); for (Item item : this.buffer) { if (item instanceof StringItem) { StringItem stringItem = (StringItem) item; String stringValue = stringItem.getValue().toString(); if (omitMode && !omitStacks.isEmpty()) { // 省略模式下, 只需要统计数量 charCount += stringValue.length(); lineCount += IndentTools.countNewlineChars(stringValue); } else { sql.append(stringValue); } } else if (item instanceof VariableItem) { VariableItem variable = ((VariableItem) item); String stringValue = plugins.variableToString(variable.value, dialect); if (omitMode && !omitStacks.isEmpty()) { // 省略模式下, 只需要统计数量 charCount += stringValue == null ? 4 : stringValue.length(); lineCount += stringValue == null ? 0 : IndentTools.countNewlineChars(stringValue); } else { if (omitMode) { // 省略模式下, 截短超过长度的字段值 stringValue = tryCutStringOverlength(stringValue, valueLimit); } sql.append(stringValue); sql.append("/*").append(variable.getKey()).append("*/"); } } else if (item instanceof RawValueItem) { RawValueItem rawValueItem = (RawValueItem) item; String stringValue = plugins.resolveRawValue(rawValueItem.getValue(), dialect); if (omitMode && !omitStacks.isEmpty()) { // 省略模式下, 只需要统计数量 charCount += stringValue == null ? 4 : stringValue.length(); lineCount += stringValue == null ? 0 : IndentTools.countNewlineChars(stringValue); } else { sql.append(stringValue); } } else if (item instanceof OmitItem) { if (!omitMode) { continue; } boolean omitEnabled = !omitStacks.isEmpty(); OmitItem omitItem = (OmitItem) item; OmitItem srartItem = null; // 开始标记入栈, 结束标记出栈 if (omitItem.enabled()) { omitStacks.add(omitItem); } else { if (!omitStacks.isEmpty()) { srartItem = omitStacks.pop(); // } else { // 结束标记多于开始标记, 不作处理 } } // OmitItem堆栈之前不是空的, 现在变空了, 说明已经回到顶层且结束了 if (omitEnabled && omitStacks.isEmpty()) { if (charCount > 0) { // 插入省略信息 int itemCount = calcOmittedIndex(srartItem, omitItem); insertOmittedDetails(sql, charCount, lineCount, itemCount); } // 统计信息归零 lineCount = 0; charCount = 0; } } else { throw new UnsupportedOperationException("Unsupported item: " + item.getClass()); } } // 到最后了, OmitItem还不是空的, 说明开始标记多于结束标记 if (!omitStacks.isEmpty() && charCount > 0) { // 插入省略信息 insertOmittedDetails(sql, charCount, lineCount, -1); } return format ? sqlFormatToString(sql) : sql.toString(); } /** 替换\t为4个空格, 替换\r\n为\n, 替换单独的\r为\n; 清除末尾的空白 **/ protected String sqlFormatToString(StringBuilder sql) { StringTools.replace(sql, "\t", " ", "\r\n", "\n", "\r", "\n"); // 清除末尾的空白 int size = sql.length(); int lastIndex = size; // 从最后开始, 判断前一个字符是不是空白 for (int i = size; i > 0; i--) { char c = sql.charAt(i - 1); // 判断前一个字符 if (!StringTools.isAsciiWhitespace(c)) { lastIndex = i; break; } } if (lastIndex < size) { sql.setLength(lastIndex); } return sql.toString(); } protected void insertOmittedDetails(StringBuilder sql, int charCount, int lineCount, int itemCount) { // 计算省略掉的行数和字符数信息 // /* 10000 chars, 100 lines, 50 items are omitted here ... */ StringBuilder msg = generateOmittedDetails(charCount, lineCount, itemCount); // 在最后一个换行符之后插入省略信息 IndentTools.space.insertMessageAfterLastNewline(sql, msg); } // 生成省略掉的行数和字符数详细描述 // /* 10000 chars, 100 lines, 50 items are omitted here ... */ protected StringBuilder generateOmittedDetails(int charCount, int lineCount, int itemCount) { StringBuilder msg = new StringBuilder(); msg.append("/*").append(' '); msg.append(charCount).append(' ').append("chars"); if (lineCount > 0) { msg.append(',').append(' ').append(lineCount).append(' ').append("lines"); } if (itemCount > 0) { msg.append(',').append(' ').append(itemCount).append(' ').append("items"); } msg.append(' ').append("are omitted here").append(' ').append("...").append(' ').append("*/"); return msg; } private int calcOmittedIndex(OmitItem start, OmitItem end) { if (start == null || end == null) { return -1; } if (start.index() < 0 || end.index() < 0 || start.index() > end.index()) { return -1; } return end.index() - start.index(); } /** 尝试截短字符串 **/ protected static String tryCutStringOverlength(String string, int limit) { if (limit <= 0) { return string; } if (!string.startsWith("'") || !string.endsWith("'")) { return string; } int length = string.length() - 2; if (length <= limit) { return string; } string = string.substring(1, string.length() - 1); string = StringTools.ellipsis(string, limit) + '(' + length + ')'; return "'" + string + "'"; } public String toString() { return getLoggingSqlString(true, false); } protected List items() { return this.buffer; } /** 自动追加空格 **/ protected SqlBuffer autoAppendWhitespace(String part) { VerifyTools.requireNonNull(part, "part"); // 1. 空白后/符号后(右括号除外)不加 // 2. 空白前/符号前不加 // 3. 两个单词放一块时要加 // -- '作为单词而不是符号, SELECT '0' AS price if (this.isEmpty() || part.isEmpty()) { return this; } if (SqlTools.Text.startsWithChar(part, '(') && IndentTools.countNewlineChars(part) > 0) { this.append(' '); return this; } // 左侧是除右括号以外的空白或符号, 或者右侧是空白或符号, 不需要加空格 if (SqlTools.Text.endsWithSqlSymbol(this, ')') || SqlTools.Text.startsWithSqlSymbol(part)) { return this; } this.append(' '); // TODO // 运算符, 如果前面有空格, 则后面也加一个空格 // 换行时, 前面的未闭合的左括号前加一个空格 // 右括号前, 如果在本行找不到成对的左括号时, 加一个空格 // 右括号后, 如果右括号前有空格, 后面也加一个空格 return this; } /** 自动追加空格 **/ protected SqlBuffer autoAppendWhitespace(SqlBuffer part) { VerifyTools.requireNonNull(part, "part"); if (this.isEmpty() || part.isEmpty()) { return this; } if (SqlTools.Text.startsWithChar(part, '(') && SqlTools.Text.countNewlineChars(part) > 0) { this.append(' '); return this; } // 左侧是除右括号以外的空白或符号, 或者右侧是空白或符号, 不需要加空格 if (SqlTools.Text.endsWithSqlSymbol(this, ')') || SqlTools.Text.startsWithSqlSymbol(part)) { return this; } this.append(' '); return this; } /** 自动追加空格 **/ protected SqlBuffer autoAppendWhitespace() { if (this.isEmpty()) { return this; } if (SqlTools.Text.endsWithSqlSymbol(this, ')')) { return this; } this.append(' '); return this; } /** 自动在前面添加空格 **/ protected SqlBuffer autoPrependWhitespace(String part) { VerifyTools.requireNonNull(part, "part"); if (this.isEmpty() || part.isEmpty()) { return this; } if (SqlTools.Text.startsWithChar(this, '(') && SqlTools.Text.countNewlineChars(this) > 0) { this.prepend(' '); return this; } // 左侧是除右括号以外的空白或符号, 或者右侧是空白或符号, 不需要加空格 if (SqlTools.Text.endsWithSqlSymbol(part, ')') || SqlTools.Text.startsWithSqlSymbol(this)) { return this; } this.prepend(' '); return this; } /** 自动在前面添加空格 **/ protected SqlBuffer autoPrependWhitespace(SqlBuffer part) { VerifyTools.requireNonNull(part, "part"); if (this.isEmpty() || part.isEmpty()) { return this; } if (SqlTools.Text.startsWithChar(this, '(') && SqlTools.Text.countNewlineChars(this) > 0) { this.prepend(' '); return this; } // 左侧是除右括号以外的空白或符号, 或者右侧是空白或符号, 不需要加空格 if (SqlTools.Text.endsWithSqlSymbol(part, ')') || SqlTools.Text.startsWithSqlSymbol(this)) { return this; } this.prepend(' '); return this; } /** 清除最前面的缩进空白(返回清除了几个缩进量) **/ protected int clearLeadingIndentWhitespace() { return SqlTools.Indent.clearLeadingIndentWhitespace(this); } /** 清除最后的文字后面的缩进空白(返回清除了几个缩进量) **/ protected int clearTrailingIndentWhitespace() { return SqlTools.Indent.clearTrailingIndentWhitespace(this); } protected interface Item { } /** * 超级长的SQL在输出日志时可以省略掉一部分
* 省略哪一部分, 用OmitItem来标识起止位置 * * @author zhaohuihua * @version 20200712 */ protected static class OmitItem implements Item, Serializable { /** SerialVersionUID **/ private static final long serialVersionUID = 1L; private final boolean enabled; private final int index; public OmitItem(boolean enabled) { this.enabled = enabled; this.index = -1; } public OmitItem(boolean enabled, int index) { this.enabled = enabled; this.index = index; } public boolean enabled() { return enabled; } public int index() { return index; } } protected static class RawValueItem implements Item, Serializable { /** SerialVersionUID **/ private static final long serialVersionUID = 1L; private String value; public RawValueItem(String value) { VerifyTools.requireNonNull(value, "value"); this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } protected static class StringItem implements Item, Serializable { /** SerialVersionUID **/ private static final long serialVersionUID = 1L; private final StringBuilder value; public StringItem() { this.value = new StringBuilder(); } public void append(char... chars) { this.value.append(chars); } public void append(String value) { VerifyTools.requireNonNull(value, "value"); this.value.append(value); } public void append(String value, char suffix) { VerifyTools.requireNonNull(value, "value"); this.value.append(value).append(suffix); } public void append(char prefix, String value) { VerifyTools.requireNonNull(value, "value"); this.value.append(prefix).append(value); } public void append(char prefix, String value, char suffix) { VerifyTools.requireNonNull(value, "value"); this.value.append(prefix).append(value).append(suffix); } public void prepend(char... chars) { this.value.insert(0, chars); } public void prepend(String value) { VerifyTools.requireNonNull(value, "value"); this.value.insert(0, value); } public void prepend(String value, char suffix) { VerifyTools.requireNonNull(value, "value"); this.value.insert(0, suffix).insert(0, value); } public void prepend(char prefix, String value) { VerifyTools.requireNonNull(value, "value"); this.value.insert(0, value).insert(0, prefix); } public void prepend(char prefix, String value, char suffix) { VerifyTools.requireNonNull(value, "value"); this.value.insert(0, suffix).insert(0, value).insert(0, prefix); } /** * 删除左侧空白 * * @return 删除后剩下多少字符 */ public int trimLeft() { return trimLeftRight(true, false); } /** * 删除右侧空白 * * @return 删除后剩下多少字符 */ public int trimRight() { return trimLeftRight(false, true); } private int trimLeftRight(boolean trimLeft, boolean trimRight) { if (value.length() == 0) { return 0; } int size = value.length(); char[] chars = value.toString().toCharArray(); if (trimLeft) { int start = 0; while ((start < size) && (chars[start] <= ' ')) { start++; } if (start > 0) { value.delete(0, start); } } if (trimRight) { int end = size; while ((end > 0) && (chars[end - 1] <= ' ')) { end--; } if (end < size) { value.delete(end, size); } } return value.length(); } /** * 在第1个非空字符前插入前缀
* 删除prefixOverrides, 插入prefix
* 如果内容全部为空, 将不会做任何处理, 返回false
* 如果prefix为空, 又没有找到prefixOverrides, 也会返回false * * @param prefix 待插入的前缀 * @param prefixOverrides 待替换的前缀, 不区分大小写, 支持以|拆分的多个前缀, 如AND|OR * @return 是否有变更 */ public boolean insertPrefix(String prefix, String prefixOverrides) { if (value.length() == 0) { return false; } int last = value.length() - 1; int position = -1; // 查找插入点: 第1个非空字符的位置 for (int i = 0; i <= last; i++) { char c = value.charAt(i); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { continue; } else { position = i; break; // 位置找到了 } } if (position < 0) { return false; } boolean removed = false; boolean changed = false; if (VerifyTools.isNotBlank(prefixOverrides)) { String[] array = StringTools.split(prefixOverrides, '|'); for (String prefixOverride : array) { if (startsWith(value, prefixOverride, position)) { value.delete(position, position + prefixOverride.length()); removed = true; changed = true; break; } } } if (VerifyTools.isNotBlank(prefix)) { changed = true; if (removed) { value.insert(position, prefix); } else { String suffix = value.substring(position, Math.min(position + 10, value.length())); if (SqlTools.Text.endsWithSqlSymbol(prefix, ')') || SqlTools.Text.startsWithSqlSymbol(suffix)) { value.insert(position, prefix); } else { value.insert(position, prefix + ' '); } } } return changed; } /** * 在最后1个非空字符后插入后缀
* 删除suffixOverrides, 插入suffix
* 如果内容全部为空, 将不会做任何处理, 返回false
* 如果suffix为空, 又没有找到suffixOverrides, 也会返回false * * @param suffix 待插入的后缀 * @param suffixOverrides 待替换的后缀, 不区分大小写, 支持以|拆分的多个前缀, 如AND|OR * @return 是否有变更 */ public boolean insertSuffix(String suffix, String suffixOverrides) { if (value.length() == 0) { return false; } int last = value.length() - 1; int position = -1; // 查找插入点: 第1个非空字符之后的那个位置 for (int i = last; i >= 0; i--) { char c = value.charAt(i); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { continue; } else { position = i + 1; break; // 位置找到了 } } // 停在第1个非空字符之后, 所以不能等于0 if (position <= 0) { return false; } boolean removed = false; boolean changed = false; if (VerifyTools.isNotBlank(suffixOverrides)) { String[] array = StringTools.split(suffixOverrides, '|'); for (String suffixOverride : array) { if (endsWith(value, suffixOverride, position)) { value.delete(position - suffixOverride.length(), position); position -= suffixOverride.length(); removed = true; changed = true; break; } } } if (VerifyTools.isNotBlank(suffix)) { changed = true; if (removed) { value.insert(position, suffix); } else { String prefix = value.substring(Math.max(position - 10, 0), position); if (SqlTools.Text.endsWithSqlSymbol(prefix, ')') || SqlTools.Text.startsWithSqlSymbol(suffix)) { value.insert(position, suffix); } else { value.insert(position, ' ' + suffix); } } } return changed; } private static boolean startsWith(CharSequence string, String prefix, int index) { if (string.length() < index + prefix.length()) { return false; } int i = 0; for (; i < prefix.length(); i++) { if (Character.toUpperCase(prefix.charAt(i)) != Character.toUpperCase(string.charAt(i + index))) { return false; } } // 如果prefix是单词结尾, 则下一个字符必须不是单词 // 例如替换OR, 遇到ORG_ID, 应判定为不匹配 if (i + index < string.length() && StringTools.isWordChar(prefix.charAt(prefix.length() - 1))) { return !StringTools.isWordChar(string.charAt(i + index)); } return true; } private static boolean endsWith(CharSequence string, String suffix, int index) { int si = index - suffix.length(); if (si < 0) { return false; } for (int i = 0; i < suffix.length(); i++) { if (Character.toUpperCase(suffix.charAt(i)) != Character.toUpperCase(string.charAt(si + i))) { return false; } } // 如果suffix是单词开头, 则前一个字符必须不是单词 if (si > 0 && StringTools.isWordChar(suffix.charAt(0))) { return !StringTools.isWordChar(string.charAt(si - 1)); } return true; } public StringBuilder getValue() { return this.value; } public String toString() { return this.value.toString(); } } protected static class VariableItem implements Item, Serializable { /** SerialVersionUID **/ private static final long serialVersionUID = 1L; private int index; private final Object value; public VariableItem(int index, Object value) { this.index = index; this.value = value; } public String getKey() { return "$" + (index + 1); } public Object getValue() { return this.value; } public String toString() { return this.getKey(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy