fix: 自关联 Table:alias 拼接 SQL 表名异常,感谢 zxcwindy 的贡献 #750

https://github.com/Tencent/APIJSON/pull/750
This commit is contained in:
TommyLemon 2024-08-11 17:09:38 +08:00 committed by GitHub
commit 67bda099cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -143,9 +143,9 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
* 字段名映射隐藏真实字段名对安全要求很高的表可以这么做另外可以配置 name_tag:(name,tag) 来实现多字段 INlength_tag:length(tag) 来实现 SQL 函数复杂条件
*/
public static Map<String, String> COLUMN_KEY_MAP;
/**
* 允许批量增删改部分记录失败的表
*/
/**
* 允许批量增删改部分记录失败的表
*/
public static Map<String, String> ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP;
public static List<String> CONFIG_TABLE_LIST;
public static List<String> DATABASE_LIST;
@ -188,7 +188,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
TABLE_KEY_MAP.put(AllTableComment.class.getSimpleName(), AllTableComment.TABLE_NAME);
TABLE_KEY_MAP.put(AllColumnComment.class.getSimpleName(), AllColumnComment.TABLE_NAME);
ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP = new HashMap<>();
ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP = new HashMap<>();
CONFIG_TABLE_LIST = new ArrayList<>(); // Table, Column 等是系统表 AbstractVerifier.SYSTEM_ACCESS_MAP.keySet());
CONFIG_TABLE_LIST.add(Function.class.getSimpleName());
@ -492,8 +492,8 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
SQL_FUNCTION_MAP.put("json_array_insert", ""); // JSON_ARRAY_INSERT(json_doc, val) 插入JSON数组
SQL_FUNCTION_MAP.put("json_array_get", ""); // JSON_ARRAY_GET(json_doc, position) 从JSON数组提取指定位置的元素
SQL_FUNCTION_MAP.put("json_contains", ""); // JSON_CONTAINS(json_doc, val) JSON文档是否在路径中包含特定对象
SQL_FUNCTION_MAP.put("json_array_contains", ""); // JSON_ARRAY_CONTAINS(json_doc, path) JSON文档是否在路径中包含特定对象
SQL_FUNCTION_MAP.put("json_contains_path", ""); // JSON_CONTAINS_PATH(json_doc, path) JSON文档是否在路径中包含任何数据
SQL_FUNCTION_MAP.put("json_array_contains", ""); // JSON_ARRAY_CONTAINS(json_doc, path) JSON文档是否在路径中包含特定对象
SQL_FUNCTION_MAP.put("json_contains_path", ""); // JSON_CONTAINS_PATH(json_doc, path) JSON文档是否在路径中包含任何数据
SQL_FUNCTION_MAP.put("json_depth", ""); // JSON_DEPTH(json_doc) JSON文档的最大深度
SQL_FUNCTION_MAP.put("json_extract", ""); // JSON_EXTRACT(json_doc, path) 从JSON文档返回数据
SQL_FUNCTION_MAP.put("json_extract_scalar", ""); // JSON_EXTRACT_SCALAR(json_doc, path) 从JSON文档返回基础类型数据例如 Boolean, Number, String
@ -1117,7 +1117,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
return DATABASE_MYSQL.equals(db);
}
@Override
@Override
public boolean isPostgreSQL() {
return isPostgreSQL(getSQLDatabase());
}
@ -1133,7 +1133,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
return DATABASE_SQLSERVER.equals(db);
}
@Override
@Override
public boolean isOracle() {
return isOracle(getSQLDatabase());
}
@ -1149,7 +1149,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
return DATABASE_DB2.equals(db);
}
@Override
@Override
public boolean isMariaDB() {
return isMariaDB(getSQLDatabase());
}
@ -1157,7 +1157,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
return DATABASE_MARIADB.equals(db);
}
@Override
@Override
public boolean isTiDB() {
return isTiDB(getSQLDatabase());
}
@ -1384,6 +1384,12 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
String nt = TABLE_KEY_MAP.get(ot);
return StringUtil.isEmpty(nt) ? ot : nt;
}
@JSONField(serialize = false)
public String getSQLTableWithAlias(String table,String alias) {
return StringUtil.isEmpty(alias) ? table : table + ":" + alias; // 带上原表名避免 alias 和其它表名/字段名冲突
}
@JSONField(serialize = false)
@Override
public String getTablePath() {
@ -1547,7 +1553,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
}
List<String> raw = getRaw();
// 提前把 @having& 转为 @having或者干脆不允许 @raw:"@having&" boolean containRaw = raw != null && (raw.contains(KEY_HAVING) || raw.contains(KEY_HAVING_AND));
// 提前把 @having& 转为 @having或者干脆不允许 @raw:"@having&" boolean containRaw = raw != null && (raw.contains(KEY_HAVING) || raw.contains(KEY_HAVING_AND));
boolean containRaw = raw != null && raw.contains(KEY_HAVING);
// 直接把 having 类型从 Map<String, String> 定改为 Map<String, Object>避免额外拷贝
@ -2657,12 +2663,12 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
}
return getLimitString(
getPage()
, getCount()
, isOracle() || isSQLServer() || isDb2()
, isOracle() || isDameng() || isKingBase()
, isPresto() || isTrino()
);
getPage()
, getCount()
, isOracle() || isSQLServer() || isDb2()
, isOracle() || isDameng() || isKingBase()
, isPresto() || isTrino()
);
}
/**获取限制数量及偏移量
* @param page
@ -2672,8 +2678,8 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
* @return
*/
public static String getLimitString(int page, int count, boolean isTSQL, boolean isOracle) {
return getLimitString(page, count, isTSQL, isOracle, false);
}
return getLimitString(page, count, isTSQL, isOracle, false);
}
/**获取限制数量及偏移量
* @param page
* @param count
@ -2685,17 +2691,17 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
public static String getLimitString(int page, int count, boolean isTSQL, boolean isOracle, boolean isPresto) {
int offset = getOffset(page, count);
if (isOracle) { // TODO 判断版本高版本可以用 OFFSET FETCH
return " WHERE ROWNUM BETWEEN " + offset + " AND " + (offset + count);
}
if (isOracle) { // TODO 判断版本高版本可以用 OFFSET FETCH
return " WHERE ROWNUM BETWEEN " + offset + " AND " + (offset + count);
}
if (isTSQL) { // OFFSET FECTH 中所有关键词都不可省略, 另外 Oracle 数据库使用子查询加 where 分页
return " OFFSET " + offset + " ROWS FETCH FIRST " + count + " ROWS ONLY";
}
if (isPresto) { // https://prestodb.io/docs/current/sql/select.html
return (offset <= 0 ? "" : " OFFSET " + offset) + " LIMIT " + count;
}
if (isPresto) { // https://prestodb.io/docs/current/sql/select.html
return (offset <= 0 ? "" : " OFFSET " + offset) + " LIMIT " + count;
}
return " LIMIT " + count + (offset <= 0 ? "" : " OFFSET " + offset); // DELETE, UPDATE 不支持 OFFSET
}
@ -3868,17 +3874,17 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
if (isOracle() || isDameng() || isKingBase() || (isMySQL() && getDBVersionNums()[0] >= 8)) {
return "regexp_like(" + getKey(column) + ", " + getValue(key, column, value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
if (isPresto() || isTrino()) {
return "regexp_like(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "")
+ ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")";
}
if (isPresto() || isTrino()) {
return "regexp_like(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "")
+ ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")";
}
if (isClickHouse()) {
return "match(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "")
+ ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")";
}
if (isElasticsearch()) {
return getKey(column) + " RLIKE " + getValue(key, column, value);
}
if (isElasticsearch()) {
return getKey(column) + " RLIKE " + getValue(key, column, value);
}
if (isHive()) {
return (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "")
+ " REGEXP " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "");
@ -4135,7 +4141,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
/**WHERE key contains value
* @param key
* @param value
* @return {@link #getContainString(String, String, Object[], int)}
* @return {@link #getContainString(String, String, Object[], int)}
* @throws NotExistException
*/
@JSONField(serialize = false)
@ -4196,11 +4202,11 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
condition += ("json_textcontains(" + getKey(column) + ", " + (StringUtil.isEmpty(path, true)
? "'$'" : getValue(key, column, path)) + ", " + getValue(key, column, c == null ? null : c.toString()) + ")");
}
else if (isPresto() || isTrino()) {
condition += ("json_array_contains(cast(" + getKey(column) + " AS VARCHAR), "
else if (isPresto() || isTrino()) {
condition += ("json_array_contains(cast(" + getKey(column) + " AS VARCHAR), "
+ getValue(key, column, c) + (StringUtil.isEmpty(path, true)
? "" : ", " + getValue(key, column, path)) + ")");
}
}
else {
String v = c == null ? "null" : (c instanceof Boolean || c instanceof Number ? c.toString() : "\"" + c + "\"");
if (isClickHouse()) {
@ -4613,7 +4619,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
}
int offset = getOffset(getPage(), count);
String alias = getAliasWithQuote();
String quote = getQuote();
String quote = getQuote();
return "SELECT * FROM (SELECT " + alias + ".*, ROWNUM "+ quote + "RN" + quote +" FROM (" + sql + ") " + alias
+ " WHERE ROWNUM <= " + (offset + count) + ") WHERE "+ quote + "RN" + quote +" > " + offset;
}
@ -4790,10 +4796,10 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
//if (changed) {
// List<Object> opvl = getPreparedValueList();
// if (opvl != null && opvl.isEmpty() == false) {
// pvl.addAll(opvl);
// }
// List<Object> opvl = getPreparedValueList();
// if (opvl != null && opvl.isEmpty() == false) {
// pvl.addAll(opvl);
// }
setPreparedValueList(pvl);
//}
@ -4816,7 +4822,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
String rt = on.getRelateType();
if (StringUtil.isEmpty(rt, false)) {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? " != " : " = ")
+ quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
else {
onJoinComplexRelation(sql, quote, j, jt, onList, on);
@ -4828,7 +4834,7 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
}
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + " " + rt + " "
+ quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
else if (rt.endsWith("$")) {
String t = rt.substring(0, rt.length() - 1);
@ -4874,11 +4880,11 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
if (l <= 0 && r <= 0) {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
+ " LIKE " + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ " LIKE " + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
else {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
+ (l <= 0 ? " LIKE concat(" : " LIKE concat('" + l + "', ") + quote + on.getTargetTable() + quote
+ (l <= 0 ? " LIKE concat(" : " LIKE concat('" + l + "', ") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote
+ "." + quote + on.getTargetKey() + quote + (r <= 0 ? ")" : ", '" + r + "')");
}
}
@ -4887,38 +4893,38 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
if (isPostgreSQL() || isInfluxDB()) {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote
+ (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ")
+ quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
else if (isOracle() || isDameng() || isKingBase()) {
sql += (first ? ON : AND) + "regexp_like(" + quote + jt + quote + "." + quote + on.getKey() + quote
+ ", " + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote
+ ", " + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote
+ (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
else if (isPresto() || isTrino()) {
sql += (first ? ON : AND) + "regexp_like(" + (ignoreCase ? "lower(" : "") + quote
else if (isPresto() || isTrino()) {
sql += (first ? ON : AND) + "regexp_like(" + (ignoreCase ? "lower(" : "") + quote
+ jt + quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
+ ", " + (ignoreCase ? "lower(" : "") + quote + on.getTargetTable()
+ ", " + (ignoreCase ? "lower(" : "") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias())
+ quote + "." + quote + on.getTargetKey() + quote + (ignoreCase ? ")" : "") + ")";
}
}
else if (isClickHouse()) {
sql += (first ? ON : AND) + "match(" + (ignoreCase ? "lower(" : "") + quote + jt
+ quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
+ ", " + (ignoreCase ? "lower(" : "") + quote + on.getTargetTable()
+ ", " + (ignoreCase ? "lower(" : "") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias())
+ quote + "." + quote + on.getTargetKey() + quote + (ignoreCase ? ")" : "") + ")";
}
else if (isElasticsearch()) {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
+ " RLIKE " + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
}
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
+ " RLIKE " + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
else if (isHive()) {
sql += (first ? ON : AND) + (ignoreCase ? "lower(" : "") + quote + jt + quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
+ " REGEXP " + (ignoreCase ? "lower(" : "") + quote + on.getTargetTable()
sql += (first ? ON : AND) + (ignoreCase ? "lower(" : "") + quote + jt + quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
+ " REGEXP " + (ignoreCase ? "lower(" : "") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias())
+ quote + "." + quote + on.getTargetKey() + quote + (ignoreCase ? ")" : "");
}
}
else {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
+ " REGEXP " + (ignoreCase ? "" : "BINARY ")
+ quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
}
else if ("{}".equals(rt) || "<>".equals(rt)) {
@ -4950,12 +4956,12 @@ public abstract class AbstractSQLConfig<T extends Object> implements SQLConfig<T
String arrKeyPath;
String itemKeyPath;
if ("{}".equals(rt)) {
arrKeyPath = quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
arrKeyPath = quote + getSQLTableWithAlias(on.getTargetTable(),on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
itemKeyPath = quote + jt + quote + "." + quote + on.getKey() + quote;
}
else {
arrKeyPath = quote + jt + quote + "." + quote + on.getKey() + quote;
itemKeyPath = quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
itemKeyPath = quote + getSQLTableWithAlias(on.getTargetTable(),on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
}
if (isPostgreSQL() || isInfluxDB()) { //operator does not exist: jsonb @> character varying "[" + c + "]");