@@ -172,9 +172,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws
172172 long executedSQLStartTime = System .currentTimeMillis ();
173173
174174 boolean isPrepared = config .isPrepared ();
175-
176175 final String sql = config .getSQL (false );
177-
178176 config .setPrepared (isPrepared );
179177
180178 if (StringUtil .isEmpty (sql , true )) {
@@ -265,8 +263,9 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws
265263 Log .i (TAG , ">>> execute result = getCache('" + sql + "', " + position + ") = " + result );
266264 if (result != null ) {
267265 cachedSQLCount ++;
268- if (getCache (sql ,config ).size () > 1 ) {
269- result .put (KEY_RAW_LIST , getCache (sql ,config ));
266+ List <JSONObject > cache = getCache (sql , config );
267+ if (cache != null && cache .size () > 1 ) {
268+ result .put (KEY_RAW_LIST , cache );
270269 }
271270 Log .d (TAG , "\n \n execute result != null >> return result;" + "\n >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n \n " );
272271 return result ;
@@ -282,7 +281,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws
282281 }
283282 break ;
284283
285- default ://OPTIONS, TRACE等
284+ default : //OPTIONS, TRACE等
286285 Log .e (TAG , "execute sql = " + sql + " ; method = " + config .getMethod () + " >> return null;" );
287286 return null ;
288287 }
@@ -663,47 +662,79 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
663662 SQLConfig jc = join .getJoinConfig ();
664663
665664 List <On > onList = join .getOnList ();
666- int size = onList == null ? 0 : onList .size ();
667- if (size > 0 ) {
668- for (int j = size - 1 ; j >= 0 ; j --) {
669- On on = onList .get (j );
670- String ok = on == null ? null : on .getOriginKey ();
671- if (ok == null ) {
672- throw new NullPointerException ("服务器内部错误,List<Join> 中 Join.onList[" + j + (on == null ? "] = null!" : ".getOriginKey() = null!" ));
673- }
674-
675- // 取出 "id@": "@/User/userId" 中所有 userId 的值
676- List <Object > targetValueList = new ArrayList <>();
677-
678- for (int i = 0 ; i < resultList .size (); i ++) {
679- JSONObject mainTable = resultList .get (i );
680- Object targetValue = mainTable == null ? null : mainTable .get (on .getTargetKey ());
665+ On on = onList == null || onList .isEmpty () ? null : onList .get (0 ); // APP JOIN 应该有且只有一个 ON 条件
666+ String originKey = on == null ? null : on .getOriginKey ();
667+ if (originKey == null ) {
668+ throw new NullPointerException ("服务器内部错误,List<Join> 中 Join.onList[0" + (on == null ? "] = null!" : ".getOriginKey() = null!" ));
669+ }
670+ String key = on .getKey ();
671+ if (key == null ) {
672+ throw new NullPointerException ("服务器内部错误,List<Join> 中 Join.onList[0" + (on == null ? "] = null!" : ".getKey() = null!" ));
673+ }
681674
682- if (targetValue != null && targetValueList .contains (targetValue ) == false ) {
683- targetValueList .add (targetValue );
684- }
685- }
675+ // 取出 "id@": "@/User/userId" 中所有 userId 的值
676+ List <Object > targetValueList = new ArrayList <>();
686677
687- if ( targetValueList . isEmpty () && config . isExplain () == false ) {
688- throw new NotExistException ( "targetValueList.isEmpty() && config.isExplain() == false" );
689- }
678+ for ( int i = 0 ; i < resultList . size (); i ++ ) {
679+ JSONObject mainTable = resultList . get ( i );
680+ Object targetValue = mainTable == null ? null : mainTable . get ( on . getTargetKey ());
690681
691- // 替换为 "id{}": [userId1, userId2, userId3...]
692- jc .putWhere (ok , null , false ); // remove originKey
693- jc .putWhere (on .getKey () + "{}" , targetValueList , true ); // add originKey{} }
682+ if (targetValue != null && targetValueList .contains (targetValue ) == false ) {
683+ targetValueList .add (targetValue );
694684 }
695685 }
696686
687+ if (targetValueList .isEmpty () && config .isExplain () == false ) {
688+ throw new NotExistException ("targetValueList.isEmpty() && config.isExplain() == false" );
689+ }
690+
691+ // 替换为 "id{}": [userId1, userId2, userId3...]
692+ jc .putWhere (originKey , null , false ); // remove originKey
693+ jc .putWhere (key + "{}" , targetValueList , true ); // add originKey{} }
694+
697695 jc .setMain (true ).setPreparedValueList (new ArrayList <>());
698696
697+ // 放一块逻辑更清晰,也避免解析 * 等不支持或性能开销
698+ // String q = jc.getQuote();
699+ // if (allChildCount > 0 && jc.getCount() <= 0) {
700+ // List<String> column = jc.getColumn();
701+ // if (column == null || column.isEmpty()) {
702+ // column = Arrays.asList("*;row_number()OVER(PARTITION BY " + q + key + q + " ORDER BY " + q + key + q + " ASC):_row_num_");
703+ // }
704+ // else {
705+ // column.add("row_number()OVER(PARTITION BY " + q + key + q + " ORDER BY " + q + key + q + " ASC):_row_num_");
706+ // }
707+ // jc.setColumn(column);
708+ // }
709+
699710 boolean prepared = jc .isPrepared ();
700- final String sql = jc .getSQL (false );
711+ String sql = jc .getSQL (false );
701712 jc .setPrepared (prepared );
702713
703714 if (StringUtil .isEmpty (sql , true )) {
704715 throw new NullPointerException (TAG + ".executeAppJoin StringUtil.isEmpty(sql, true) >> return null;" );
705716 }
706717
718+ int childCount = cc .getCount ();
719+ int allChildCount = childCount *config .getCount (); // 所有分组子项数量总和
720+
721+ String sql2 = null ;
722+ if (childCount > 0 && (childCount != 1 || join .isOne2Many ())) { // TODO 判断 MySQL >= 8.0
723+ String q = jc .getQuote ();
724+ sql2 = prepared ? jc .getSQL (true ) : sql ;
725+
726+ String prefix = "SELECT * FROM(" ;
727+ String rnStr = ", row_number() OVER (PARTITION BY " + q + key + q + ((AbstractSQLConfig ) jc ).getOrderString (true ) + ") _row_num_ FROM " ;
728+ String suffix = ") _t WHERE ( (_row_num_ <= " + childCount + ") ) LIMIT " + allChildCount ;
729+
730+ sql2 = prefix
731+ // 放一块逻辑更清晰,也避免解析 * 等不支持或性能开销 + sql
732+ + sql2 .replaceFirst (" FROM " , rnStr ) // * 居然只能放在 row_number() 前面,放后面就报错 "SELECT ", rnStr)
733+ + suffix ;
734+
735+ sql = prepared ? (prefix + sql .replaceFirst (" FROM " , rnStr ) + suffix ) : sql2 ;
736+ }
737+
707738 boolean isExplain = jc .isExplain ();
708739 if (isExplain == false ) {
709740 generatedSQLCount ++;
@@ -723,13 +754,11 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
723754 executedSQLCount ++;
724755 executedSQLStartTime = System .currentTimeMillis ();
725756 }
726- rs = executeQuery (jc );
757+ rs = executeQuery (jc , sql2 );
727758 if (isExplain == false ) {
728759 executedSQLDuration += System .currentTimeMillis () - executedSQLStartTime ;
729760 }
730761
731- int childCount = cc .getCount ();
732- int allChildCount = childCount *config .getCount (); // 所有分组子项数量总和
733762 int count = 0 ;
734763
735764 int index = -1 ;
@@ -760,15 +789,8 @@ protected void executeAppJoin(SQLConfig config, List<JSONObject> resultList, Map
760789 Log .d (TAG , "\n executeAppJoin while (rs.next()) { resultList.put( " + index + ", result); "
761790 + "\n >>>>>>>>>>>>>>>>>>>>>>>>>>> \n \n " );
762791
763- if (onList != null ) {
764- for (On on : onList ) { // APP JOIN 应该有且只有一个 ON 条件
765- String ok = on .getOriginKey ();
766- String vk = ok .substring (0 , ok .length () - 1 );
767- //TODO 兼容复杂关联
768- cc .putWhere (on .getKey (), result .get (on .getKey ()), true );
769- }
770- }
771-
792+ //TODO 兼容复杂关联
793+ cc .putWhere (key , result .get (key ), true ); // APP JOIN 应该有且只有一个 ON 条件
772794 String cacheSql = cc .getSQL (false );
773795 List <JSONObject > results = childMap .get (cacheSql );
774796
@@ -1010,22 +1032,25 @@ public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int
10101032
10111033
10121034
1013- /**
1014- * @param config
1015- * @return
1016- * @throws Exception
1017- */
1018- @ Override
1035+ @ Override // 重写是为了返回类型从 Statement 改为 PreparedStatement,避免其它方法出错
10191036 public PreparedStatement getStatement (@ NotNull SQLConfig config ) throws Exception {
1037+ return getStatement (config , null );
1038+ }
1039+ @ Override
1040+ public PreparedStatement getStatement (@ NotNull SQLConfig config , String sql ) throws Exception {
1041+ if (StringUtil .isEmpty (sql )) {
1042+ sql = config .getSQL (config .isPrepared ());
1043+ }
1044+
10201045 PreparedStatement statement ; //创建Statement对象
10211046 if (config .getMethod () == RequestMethod .POST && config .getId () == null ) { //自增id
1022- statement = getConnection (config ).prepareStatement (config . getSQL ( config . isPrepared ()) , Statement .RETURN_GENERATED_KEYS );
1047+ statement = getConnection (config ).prepareStatement (sql , Statement .RETURN_GENERATED_KEYS );
10231048 }
10241049 else if (RequestMethod .isGetMethod (config .getMethod (), true )) {
1025- statement = getConnection (config ).prepareStatement (config . getSQL ( config . isPrepared ()) , ResultSet .TYPE_SCROLL_SENSITIVE , ResultSet .CONCUR_UPDATABLE );
1050+ statement = getConnection (config ).prepareStatement (sql , ResultSet .TYPE_SCROLL_SENSITIVE , ResultSet .CONCUR_UPDATABLE );
10261051 }
10271052 else {
1028- statement = getConnection (config ).prepareStatement (config . getSQL ( config . isPrepared ()) );
1053+ statement = getConnection (config ).prepareStatement (sql );
10291054 }
10301055
10311056 List <Object > valueList = config .isPrepared () ? config .getPreparedValueList () : null ;
@@ -1162,8 +1187,8 @@ public void close() {
11621187 }
11631188
11641189 @ Override
1165- public ResultSet executeQuery (@ NotNull SQLConfig config ) throws Exception {
1166- PreparedStatement stt = getStatement (config );
1190+ public ResultSet executeQuery (@ NotNull SQLConfig config , String sql ) throws Exception {
1191+ PreparedStatement stt = getStatement (config , sql );
11671192 ResultSet rs = stt .executeQuery (); //PreparedStatement 不用传 SQL
11681193 // if (config.isExplain() && (config.isSQLServer() || config.isOracle())) {
11691194 // FIXME 返回的是 boolean 值 rs = stt.getMoreResults(Statement.CLOSE_CURRENT_RESULT);
@@ -1173,7 +1198,7 @@ public ResultSet executeQuery(@NotNull SQLConfig config) throws Exception {
11731198 }
11741199
11751200 @ Override
1176- public int executeUpdate (@ NotNull SQLConfig config ) throws Exception {
1201+ public int executeUpdate (@ NotNull SQLConfig config , String sql ) throws Exception {
11771202 PreparedStatement stt = getStatement (config );
11781203 int count = stt .executeUpdate (); // PreparedStatement 不用传 SQL
11791204
0 commit comments