FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: 支持 KingbaseES MySQL、Oracle、SQL Server 三种兼容模式 by fuziran · Pull Request #868 · APIJSON/APIJSON · GitHub

105 changes: 85 additions & 20 deletions APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ public abstract class AbstractSQLConfig<T, M extends Map<String, Object>, L exte
DATABASE_LIST.add(DATABASE_COCKROACHDB);
DATABASE_LIST.add(DATABASE_DAMENG);
DATABASE_LIST.add(DATABASE_KINGBASE);
DATABASE_LIST.add(DATABASE_KINGBASE_MYSQL);
DATABASE_LIST.add(DATABASE_KINGBASE_ORACLE);
DATABASE_LIST.add(DATABASE_KINGBASE_SQLSERVER);
DATABASE_LIST.add(DATABASE_ELASTICSEARCH);
DATABASE_LIST.add(DATABASE_MANTICORE);
DATABASE_LIST.add(DATABASE_CLICKHOUSE);
Expand Down Expand Up @@ -894,6 +897,7 @@ public String getUserIdKey() {
private boolean main = true;

private Object id; // Table 的 id
private boolean idGeneratedByAPIJSON;
private Object idIn; // User Table 的 id IN
private Object userId; // Table 的 userId
private Object userIdIn; // Table 的 userId IN
Expand Down Expand Up @@ -1011,6 +1015,15 @@ public AbstractSQLConfig<T, M, L> setId(Object id) {
this.id = id;
return this;
}
@Override
public boolean isIdGeneratedByAPIJSON() {
return idGeneratedByAPIJSON;
}
@Override
public AbstractSQLConfig<T, M, L> setIdGeneratedByAPIJSON(boolean generated) {
this.idGeneratedByAPIJSON = generated;
return this;
}

@Override
public Object getIdIn() {
Expand Down Expand Up @@ -1084,11 +1097,11 @@ public String gainSQLDatabase() {

@Override
public boolean isTSQL() { // 兼容 TSQL 语法
return isOracle() || isSQLServer() || isDb2();
return isOracle() || isSQLServer() || isDb2() || isKingBaseOracle() || isKingBaseSQLServer();
}
@Override
public boolean isMSQL() { // 兼容 MySQL 语法,但不一定可以使用它的 JDBC/ODBC
return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine();
return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine() || isKingBaseMySQL();
}
@Override
public boolean isPSQL() { // 兼容 PostgreSQL 语法,但不一定可以使用它的 JDBC/ODBC
Expand Down Expand Up @@ -1172,7 +1185,31 @@ public boolean isKingBase() {
return isKingBase(gainSQLDatabase());
}
public static boolean isKingBase(String db) {
return DATABASE_KINGBASE.equals(db);
return KingbaseSQLDialect.from(db).isKingbase();
}

@Override
public boolean isKingBaseMySQL() {
return isKingBaseMySQL(gainSQLDatabase());
}
public static boolean isKingBaseMySQL(String db) {
return KingbaseSQLDialect.from(db).isMySQL();
}

@Override
public boolean isKingBaseOracle() {
return isKingBaseOracle(gainSQLDatabase());
}
public static boolean isKingBaseOracle(String db) {
return KingbaseSQLDialect.from(db).isOracle();
}

@Override
public boolean isKingBaseSQLServer() {
return isKingBaseSQLServer(gainSQLDatabase());
}
public static boolean isKingBaseSQLServer(String db) {
return KingbaseSQLDialect.from(db).isSQLServer();
}

@Override
Expand Down Expand Up @@ -1389,6 +1426,10 @@ public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col"
if(isElasticsearch() || isManticore() || isIoTDB() || isSurrealDB()) {
return "";
}
KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(gainSQLDatabase());
if (kingbaseDialect.isKingbase()) {
return kingbaseDialect.getIdentifierQuote();
}
return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() || isDoris() || isStarRocks() ? "`" : "\"";
}

Expand Down Expand Up @@ -1525,7 +1566,7 @@ public AbstractSQLConfig<T, M, L> setTable(String table) { //Table已经在Parse
}

public String gainAs() {
return isOracle() || isManticore() ? " " : " AS ";
return isOracle() || isKingBaseOracle() || isManticore() ? " " : " AS ";
}

@Override
Expand Down Expand Up @@ -2074,7 +2115,7 @@ public String gainOrderString(boolean hasPrefix) {
// return (hasPrefix ? " ORDER BY " : "") + StringUtil.concat(order, joinOrder, ", ");
// }

if (getCount() > 0 && (isSQLServer() || isDb2())) {
if (getCount() > 0 && (isSQLServer() || isKingBaseSQLServer() || isDb2())) {
// Oracle, SQL Server, DB2 的 OFFSET 必须加 ORDER BY.去掉Oracle,Oracle里面没有offset关键字

// String[] ss = StringUtil.split(order);
Expand Down Expand Up @@ -3073,8 +3114,14 @@ else if (isSurrealDB()) {
}
}

KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(gainSQLDatabase());
String kingbaseLimit = kingbaseDialect.getSelectLimit(getOffset(page, count), count);
if (kingbaseLimit != null) {
return kingbaseLimit;
}

boolean isOracle = isOracle();
return gainLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBase(), isPresto() || isTrino());
return gainLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBaseOracle(), isPresto() || isTrino());
}
/**获取限制数量及偏移量
* @param page
Expand Down Expand Up @@ -4014,7 +4061,7 @@ public String gainCompareString(String key, String column, Object value, String
public String gainKey(@NotNull String key) {
String lenFun = "";
if (key.endsWith("[")) {
lenFun = isSQLServer() ? "datalength" : "length";
lenFun = isSQLServer() || isKingBaseSQLServer() ? "datalength" : "length";
key = key.substring(0, key.length() - 1);
}
else if (key.endsWith("{")) {
Expand Down Expand Up @@ -4302,10 +4349,11 @@ public String gainRegExpString(String key, String column, Object[] values, int t
* @return key REGEXP 'value'
*/
public String gainRegExpString(String key, String column, String value, boolean ignoreCase) {
if (isPSQL()) {
if (isPSQL() || isKingBaseSQLServer()) {
return gainKey(column) + " ~" + (ignoreCase ? "* " : " ") + gainValue(key, column, value);
}
if (isOracle() || isDameng() || isKingBase() || (isMySQL() && gainDBVersionNums()[0] >= 8)) {
if (isOracle() || isDameng() || DATABASE_KINGBASE.equals(gainSQLDatabase())
|| isKingBaseOracle() || isKingBaseMySQL() || (isMySQL() && gainDBVersionNums()[0] >= 8)) {
return "regexp_like(" + gainKey(column) + ", " + gainValue(key, column, value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
if (isPresto() || isTrino()) {
Expand Down Expand Up @@ -4624,7 +4672,10 @@ public String gainContainString(String key, String column, Object[] childs, int
condition += (gainKey(column) + " @> " + gainValue(key, column, newJSONArray(c)));
// operator does not exist: jsonb @> character varying "[" + c + "]");
}
else if (isOracle() || isDameng() || isKingBase()) {
else if (isKingBase() && isKingBaseOracle() == false) {
condition += (gainKey(column) + "::jsonb @> " + gainValue(key, column, newJSONArray(c)) + "::jsonb");
}
else if (isOracle() || isDameng() || isKingBaseOracle()) {
condition += ("json_textcontains(" + gainKey(column) + ", " + (StringUtil.isEmpty(path, true)
? "'$'" : gainValue(key, column, path)) + ", " + gainValue(key, column, c == null ? null : c.toString()) + ")");
}
Expand Down Expand Up @@ -4671,7 +4722,7 @@ public List<String> getWithAsExprSQLList() {
}
private void clearWithAsExprListIfNeed() {
// mysql8版本以上,子查询支持with as表达式
if(this.isMySQL() && this.gainDBVersionNums()[0] >= 8) {
if((this.isMySQL() || this.isKingBaseMySQL()) && this.gainDBVersionNums()[0] >= 8) {
this.withAsExprSQLList = new ArrayList<>();
}
}
Expand Down Expand Up @@ -4725,7 +4776,7 @@ private String withAsExprSubqueryString(SQLConfig<T, M, L> cfg, Subquery<T, M, L
} else {
withAsExpreSql = cfg.gainSQL(isPrepared());
// mysql 才存在这个问题, 主表和子表是一张表
if (isWithAsEnable && isMySQL() && StringUtil.equals(getTable(), subquery.gainFrom())) {
if (isWithAsEnable && (isMySQL() || isKingBaseMySQL()) && StringUtil.equals(getTable(), subquery.gainFrom())) {
withAsExpreSql = " SELECT * FROM (" + withAsExpreSql + ")" + as + quote + subquery.gainKey() + quote;
}
}
Expand Down Expand Up @@ -4988,20 +5039,23 @@ public static <T, M extends Map<String, Object>, L extends List<Object>> String
return "ALTER TABLE " + tablePath + " UPDATE" + config.gainSetString() + config.gainWhereString(true);
}
cSql = "UPDATE " + tablePath + config.gainSetString() + config.gainWhereString(true)
+ (config.isMySQL() ? config.gainLimitString() : "");
+ (config.isMySQL() || KingbaseSQLDialect.from(config.gainSQLDatabase()).supportsDmlLimit() ? config.gainLimitString() : "");
cSql = buildWithAsExprSql(config, cSql);
return cSql;
case DELETE:
if(config.isClickHouse()){
return "ALTER TABLE " + tablePath + " DELETE" + config.gainWhereString(true);
}
cSql = "DELETE FROM " + tablePath + config.gainWhereString(true)
+ (config.isMySQL() ? config.gainLimitString() : ""); // PostgreSQL 不允许 LIMIT
+ (config.isMySQL() || KingbaseSQLDialect.from(config.gainSQLDatabase()).supportsDmlLimit() ? config.gainLimitString() : ""); // PostgreSQL 不允许 LIMIT
cSql = buildWithAsExprSql(config, cSql);
return cSql;
default:
String explain = config.isExplain() ? (config.isSQLServer() ? "SET STATISTICS PROFILE ON "
: (config.isOracle() || config.isDameng() || config.isKingBase() ? "EXPLAIN PLAN FOR " : "EXPLAIN ")) : "";
KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(config.gainSQLDatabase());
String kingbaseExplain = kingbaseDialect.getExplainPrefix();
String explain = config.isExplain() ? (kingbaseExplain != null ? kingbaseExplain
: (config.isSQLServer() ? "SET STATISTICS PROFILE ON "
: (config.isOracle() || config.isDameng() ? "EXPLAIN PLAN FOR " : "EXPLAIN "))) : "";
if (config.isTest() && RequestMethod.isGetMethod(config.getMethod(), true)) { // FIXME 为啥是 code 而不是 count ?
String q = config.getQuote(); // 生成 SELECT ( (24 >=0 AND 24 <3) ) AS `code` LIMIT 1 OFFSET 0
return explain + "SELECT " + config.gainWhereString(false)
Expand All @@ -5010,7 +5064,7 @@ public static <T, M extends Map<String, Object>, L extends List<Object>> String

config.setPreparedValueList(new ArrayList<Object>());
String column = config.gainColumnString();
if (config.isOracle() || config.isDameng() || config.isKingBase()) {
if (config.isOracle() || config.isDameng() || config.isKingBaseOracle()) {
//When config's database is oracle,Using subquery since Oracle12 below does not support OFFSET FETCH paging syntax.
//针对oracle分组后条数的统计
if (StringUtil.isNotEmpty(config.getGroup(),true) && RequestMethod.isHeadMethod(config.getMethod(), true)){
Expand Down Expand Up @@ -5053,7 +5107,7 @@ private static <T, M extends Map<String, Object>, L extends List<Object>> String

@Override
public boolean isWithAsEnable() {
return ENABLE_WITH_AS && (isMySQL() == false || gainDBVersionNums()[0] >= 8);
return ENABLE_WITH_AS && ((isMySQL() || isKingBaseMySQL()) == false || gainDBVersionNums()[0] >= 8);
}

/**Oracle的分页获取
Expand Down Expand Up @@ -5358,7 +5412,11 @@ else if (rt.endsWith("~")) {
if (isPSQL()) {
sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ") + rk;
}
else if (isOracle() || isDameng() || isKingBase()) {
else if (isKingBaseSQLServer()) {
sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ") + rk;
}
else if (isOracle() || isDameng() || DATABASE_KINGBASE.equals(gainSQLDatabase())
|| isKingBaseOracle() || isKingBaseMySQL()) {
sql += (first ? ON : AND) + "regexp_like(" + lk + ", " + rk + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
else if (isPresto() || isTrino()) {
Expand Down Expand Up @@ -5414,7 +5472,11 @@ else if ("{}".equals(rt) || "<>".equals(rt)) {
sql += (first ? ON : AND) + (isNot ? "( " : "") + gainCondition(isNot, arrKeyPath
+ " IS NOT NULL AND " + arrKeyPath + " @> " + itemKeyPath) + (isNot ? ") " : "");
}
else if (isOracle() || isDameng() || isKingBase()) {
else if (isKingBase() && isKingBaseOracle() == false) {
sql += (first ? ON : AND) + (isNot ? "( " : "") + gainCondition(isNot, arrKeyPath
+ " IS NOT NULL AND " + arrKeyPath + "::jsonb @> " + itemKeyPath + "::jsonb") + (isNot ? ") " : "");
}
else if (isOracle() || isDameng() || isKingBaseOracle()) {
sql += (first ? ON : AND) + (isNot ? "( " : "") + gainCondition(isNot, arrKeyPath
+ " IS NOT NULL AND json_textcontains(" + arrKeyPath
+ ", '$', " + itemKeyPath + ")") + (isNot ? ") " : "");
Expand Down Expand Up @@ -5545,8 +5607,10 @@ public static <T, M extends Map<String, Object>, L extends List<Object>> SQLConf
}

Object id = request.get(idKey);
boolean idGeneratedByAPIJSON = false;
if (id == null && method == POST) {
id = callback.newId(method, database, datasource, namespace, catalog, schema, table); // null 表示数据库自增 id
idGeneratedByAPIJSON = id != null;
}

if (id != null) { // null 无效
Expand Down Expand Up @@ -6177,6 +6241,7 @@ else if (keyMap != null) {

config.setRole(role);
config.setId(id);
config.setIdGeneratedByAPIJSON(idGeneratedByAPIJSON);
config.setIdIn(idIn);
config.setUserId(userId);
config.setUserIdIn(userIdIn);
Expand Down
Loading

Back | FazBrowse Home | New Git URL