Skip to content

Commit 39bdc58

Browse files
committed
对存储过程单独传自定义的 数据库名/模式名 时支持横杠,但不允许 -- 上横杠,例如可写为 @key():"api-json.function(arg)",反引号可去掉
1 parent d504e38 commit 39bdc58

File tree

2 files changed

+58
-22
lines changed

2 files changed

+58
-22
lines changed

APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.lang.reflect.Method;
2121
import java.util.*;
2222

23+
import static apijson.orm.AbstractSQLConfig.PATTERN_SCHEMA;
24+
2325
/**可远程调用的函数类
2426
* @author Lemon
2527
*/
@@ -363,15 +365,13 @@ public static FunctionBean parseFunction(@NotNull String function, @NotNull JSON
363365
+ "总体必须为 function(key0,key1,...) 这种单函数格式!"
364366
+ "\nfunction必须符合 " + (isSQLFunction ? "SQL 函数/SQL 存储过程" : "Java 函数") + " 命名,key 是用于在 request 内取值的键!");
365367
}
366-
if (isSQLFunction != true && StringUtil.isNotEmpty(schema, true)) {
368+
if (isSQLFunction != true && schema != null) { // StringUtil.isNotEmpty(schema, false)) {
367369
throw new IllegalArgumentException("字符 " + schema + " 不合法!远程函数不允许指定类名!"
368370
+ "且必须为 function(key0,key1,...) 这种单函数格式!"
369371
+ "\nfunction必须符合 " + (isSQLFunction ? "SQL 函数/SQL 存储过程" : "Java 函数") + " 命名,key 是用于在 request 内取值的键!");
370372
}
371-
if (schema != null && StringUtil.isName(schema) == false) {
372-
throw new IllegalArgumentException("字符 " + schema + " 不合法!数据库名/模式名 不能为空且必须符合命名规范!"
373-
+ "且必须为 function(key0,key1,...) 这种单函数格式!"
374-
+ "\nfunction必须符合 " + (isSQLFunction ? "SQL 函数/SQL 存储过程" : "Java 函数") + " 命名,key 是用于在 request 内取值的键!");
373+
if (schema != null) { // StringUtil.isName(schema) == false) {
374+
schema = extractSchema(schema, null);
375375
}
376376

377377
String[] keys = StringUtil.split(function.substring(start + 1, end));
@@ -446,6 +446,40 @@ else if (v instanceof Collection) { // 泛型兼容? // JSONArray
446446
return fb;
447447
}
448448

449+
public static void verifySchema(String sch, String table) {
450+
extractSchema(sch, table);
451+
}
452+
453+
public static String extractSchema(String sch, String table) {
454+
if (table == null) {
455+
table = "Table";
456+
}
457+
458+
int ind = sch.indexOf("`");
459+
if (ind > 0) {
460+
throw new IllegalArgumentException(table + ": { @key(): value } 对应存储过程 value 中字符 "
461+
+ sch + " 不合法!`schema` 当有 ` 包裹时一定是首尾各一个,不能多也不能少!");
462+
}
463+
464+
if (ind == 0) {
465+
sch = sch.substring(1);
466+
if (sch.indexOf("`") != sch.length() - 1) {
467+
throw new IllegalArgumentException(table + ": { @key(): value } 对应存储过程 value 中字符 `"
468+
+ sch + " 不合法!`schema` 当有 ` 包裹时一定是首尾各一个,不能多也不能少!");
469+
}
470+
471+
sch = sch.substring(0, sch.length() - 1);
472+
}
473+
474+
if (PATTERN_SCHEMA.matcher(sch).matches() == false || sch.contains("--")) {
475+
throw new IllegalArgumentException(table + ": { @key(): value } 对应存储过程 value 中字符 "
476+
+ sch + " 不合法!schema.function(arg) 中 schema 必须符合 数据库名/模式名 的命名规则!"
477+
+ "一般只能传英文字母、数字、下划线!不允许 -- 等可能导致 SQL 注入的符号!");
478+
}
479+
480+
return sch;
481+
}
482+
449483

450484
/**
451485
* @param method

APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ public abstract class AbstractSQLConfig implements SQLConfig {
109109
public static String DEFAULT_SCHEMA = "sys";
110110
public static String PREFIX_DISTINCT = "DISTINCT ";
111111

112+
public static Pattern PATTERN_SCHEMA;
112113
// * 和 / 不能同时出现,防止 /* */ 段注释! # 和 -- 不能出现,防止行注释! ; 不能出现,防止隔断SQL语句!空格不能出现,防止 CRUD,DROP,SHOW TABLES等语句!
113-
private static Pattern PATTERN_RANGE;
114-
private static Pattern PATTERN_FUNCTION;
114+
public static Pattern PATTERN_RANGE;
115+
public static Pattern PATTERN_FUNCTION;
115116

116117
/**
117118
* 表名映射,隐藏真实表名,对安全要求很高的表可以这么做
@@ -131,6 +132,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
131132
public static Map<String, String> SQL_FUNCTION_MAP;
132133

133134
static { // 凡是 SQL 边界符、分隔符、注释符 都不允许,例如 ' " ` ( ) ; # -- /**/ ,以免拼接 SQL 时被注入意外可执行指令
135+
PATTERN_SCHEMA = Pattern.compile("^[A-Za-z0-9_-]+$");
134136
PATTERN_RANGE = Pattern.compile("^[0-9%,!=\\<\\>/\\.\\+\\-\\*\\^]+$"); // ^[a-zA-Z0-9_*%!=<>(),"]+$ 导致 exists(select*from(Comment)) 通过!
135137
PATTERN_FUNCTION = Pattern.compile("^[A-Za-z0-9%,:_@&~`!=\\<\\>\\|\\[\\]\\{\\} /\\.\\+\\-\\*\\^\\?\\(\\)\\$]+$"); //TODO 改成更好的正则,校验前面为单词,中间为操作符,后面为值
136138

@@ -841,9 +843,9 @@ public boolean limitSQLCount() {
841843
public boolean allowPartialUpdateFailed() {
842844
return allowPartialUpdateFailed(getTable());
843845
}
844-
public static boolean allowPartialUpdateFailed(String table) {
845-
return ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP.containsKey(table);
846-
}
846+
public static boolean allowPartialUpdateFailed(String table) {
847+
return ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP.containsKey(table);
848+
}
847849

848850
@NotNull
849851
@Override
@@ -1246,11 +1248,7 @@ public String getSQLSchema() {
12461248
@Override
12471249
public AbstractSQLConfig setSchema(String schema) {
12481250
if (schema != null) {
1249-
String quote = getQuote();
1250-
String s = schema.startsWith(quote) && schema.endsWith(quote) ? schema.substring(1, schema.length() - 1) : schema;
1251-
if (StringUtil.isEmpty(s, true) == false && StringUtil.isName(s) == false) {
1252-
throw new IllegalArgumentException("@schema:value 中value必须是1个单词!");
1253-
}
1251+
AbstractFunctionParser.verifySchema(schema, getTable());
12541252
}
12551253
this.schema = schema;
12561254
return this;
@@ -4291,10 +4289,14 @@ public static String getSQL(AbstractSQLConfig config) throws Exception {
42914289
// for (...) { Call procedure1();\n SQL \n; Call procedure2(); ... }
42924290
// 貌似不需要,因为 ObjectParser 里就已经处理的顺序等,只是这里要解决下 Schema 问题。
42934291

4294-
String sch = config.getSQLSchema();
4295-
if (StringUtil.isNotEmpty(config.getProcedure(), true)) {
4292+
String procedure = config.getProcedure();
4293+
if (StringUtil.isNotEmpty(procedure, true)) {
4294+
int ind = procedure.indexOf(".");
4295+
boolean hasPrefix = ind >= 0 && ind < procedure.indexOf("(");
4296+
String sch = hasPrefix ? AbstractFunctionParser.extractSchema(procedure.substring(0, ind), config.getTable()) : config.getSQLSchema();
4297+
42964298
String q = config.getQuote();
4297-
return "CALL " + q + sch + q + "."+ config.getProcedure();
4299+
return "CALL " + q + sch + q + "." + (hasPrefix ? procedure.substring(ind + 1) : procedure);
42984300
}
42994301

43004302
String tablePath = config.getTablePath();
@@ -4765,13 +4767,13 @@ protected void onJoinComplexRelation(String sql, String quote, Join join, String
47654767
/**已废弃,最早 6.2.0 移除,请改用 onJoinComplexRelation
47664768
*/
47674769
@Deprecated
4768-
protected void onJoinComplextRelation(String sql, String quote, Join j, String jt, List<On> onList, On on) {
4769-
onJoinComplexRelation(sql, quote, j, jt, onList, on);
4770+
protected void onJoinComplextRelation(String sql, String quote, Join join, String table, List<On> onList, On on) {
4771+
onJoinComplexRelation(sql, quote, join, table, onList, on);
47704772
}
47714773

4772-
protected void onGetJoinString(Join j) throws UnsupportedOperationException {
4774+
protected void onGetJoinString(Join join) throws UnsupportedOperationException {
47734775
}
4774-
protected void onGetCrossJoinString(Join j) throws UnsupportedOperationException {
4776+
protected void onGetCrossJoinString(Join join) throws UnsupportedOperationException {
47754777
throw new UnsupportedOperationException("已禁用 * CROSS JOIN !性能很差、需求极少,如要取消禁用可在后端重写相关方法!");
47764778
}
47774779

0 commit comments

Comments
 (0)