001/* 002 * Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.dialect.impl; 017 018import com.mybatisflex.core.dialect.IDialect; 019import com.mybatisflex.core.dialect.KeywordWrap; 020import com.mybatisflex.core.dialect.LimitOffsetProcessor; 021import com.mybatisflex.core.dialect.OperateType; 022import com.mybatisflex.core.exception.FlexExceptions; 023import com.mybatisflex.core.exception.locale.LocalizedFormats; 024import com.mybatisflex.core.logicdelete.LogicDeleteManager; 025import com.mybatisflex.core.query.CPI; 026import com.mybatisflex.core.query.Join; 027import com.mybatisflex.core.query.QueryColumn; 028import com.mybatisflex.core.query.QueryCondition; 029import com.mybatisflex.core.query.QueryOrderBy; 030import com.mybatisflex.core.query.QueryTable; 031import com.mybatisflex.core.query.QueryWrapper; 032import com.mybatisflex.core.query.UnionWrapper; 033import com.mybatisflex.core.query.With; 034import com.mybatisflex.core.row.Row; 035import com.mybatisflex.core.row.RowCPI; 036import com.mybatisflex.core.table.TableInfo; 037import com.mybatisflex.core.update.RawValue; 038import com.mybatisflex.core.util.ArrayUtil; 039import com.mybatisflex.core.util.CollectionUtil; 040import com.mybatisflex.core.util.SqlUtil; 041import com.mybatisflex.core.util.StringUtil; 042 043import java.util.Collection; 044import java.util.Collections; 045import java.util.List; 046import java.util.Map; 047import java.util.Set; 048import java.util.StringJoiner; 049import java.util.function.Function; 050import java.util.stream.Collectors; 051import java.util.stream.IntStream; 052 053import static com.mybatisflex.core.constant.SqlConsts.AND; 054import static com.mybatisflex.core.constant.SqlConsts.ASTERISK; 055import static com.mybatisflex.core.constant.SqlConsts.BLANK; 056import static com.mybatisflex.core.constant.SqlConsts.BRACKET_LEFT; 057import static com.mybatisflex.core.constant.SqlConsts.BRACKET_RIGHT; 058import static com.mybatisflex.core.constant.SqlConsts.DELETE; 059import static com.mybatisflex.core.constant.SqlConsts.DELETE_FROM; 060import static com.mybatisflex.core.constant.SqlConsts.DELIMITER; 061import static com.mybatisflex.core.constant.SqlConsts.DUAL; 062import static com.mybatisflex.core.constant.SqlConsts.EMPTY; 063import static com.mybatisflex.core.constant.SqlConsts.EQUALS; 064import static com.mybatisflex.core.constant.SqlConsts.EQUALS_PLACEHOLDER; 065import static com.mybatisflex.core.constant.SqlConsts.FROM; 066import static com.mybatisflex.core.constant.SqlConsts.GROUP_BY; 067import static com.mybatisflex.core.constant.SqlConsts.HAVING; 068import static com.mybatisflex.core.constant.SqlConsts.HINT_END; 069import static com.mybatisflex.core.constant.SqlConsts.HINT_START; 070import static com.mybatisflex.core.constant.SqlConsts.INSERT_INTO; 071import static com.mybatisflex.core.constant.SqlConsts.OR; 072import static com.mybatisflex.core.constant.SqlConsts.ORDER_BY; 073import static com.mybatisflex.core.constant.SqlConsts.PLACEHOLDER; 074import static com.mybatisflex.core.constant.SqlConsts.REFERENCE; 075import static com.mybatisflex.core.constant.SqlConsts.SELECT; 076import static com.mybatisflex.core.constant.SqlConsts.SELECT_ALL_FROM; 077import static com.mybatisflex.core.constant.SqlConsts.SEMICOLON; 078import static com.mybatisflex.core.constant.SqlConsts.SET; 079import static com.mybatisflex.core.constant.SqlConsts.UPDATE; 080import static com.mybatisflex.core.constant.SqlConsts.VALUES; 081import static com.mybatisflex.core.constant.SqlConsts.WHERE; 082 083/** 084 * 通用的方言设计,其他方言可以继承于当前 CommonsDialectImpl 085 * 创建或获取方言请参考 {@link com.mybatisflex.core.dialect.DialectFactory} 086 */ 087public class CommonsDialectImpl implements IDialect { 088 089 protected KeywordWrap keywordWrap = KeywordWrap.BACK_QUOTE; 090 private LimitOffsetProcessor limitOffsetProcessor = LimitOffsetProcessor.MYSQL; 091 092 public CommonsDialectImpl() { 093 } 094 095 public CommonsDialectImpl(LimitOffsetProcessor limitOffsetProcessor) { 096 this.limitOffsetProcessor = limitOffsetProcessor; 097 } 098 099 public CommonsDialectImpl(KeywordWrap keywordWrap, LimitOffsetProcessor limitOffsetProcessor) { 100 this.keywordWrap = keywordWrap; 101 this.limitOffsetProcessor = limitOffsetProcessor; 102 } 103 104 @Override 105 public String wrap(String keyword) { 106 return ASTERISK.equals(keyword) || DUAL.equalsIgnoreCase(StringUtil.tryTrim(keyword)) ? 107 keyword : keywordWrap.wrap(keyword); 108 } 109 110 @Override 111 public String wrapColumnAlias(String keyword) { 112// return ASTERISK.equals(keyword) ? keyword : keywordWrap.getPrefix() + keyword + keywordWrap.getSuffix(); 113 return ASTERISK.equals(keyword) ? keyword : keywordWrap.wrap(keyword); 114 } 115 116 @Override 117 public String forHint(String hintString) { 118 return StringUtil.hasText(hintString) ? HINT_START + hintString + HINT_END : EMPTY; 119 } 120 121 @Override 122 public String forInsertRow(String schema, String tableName, Row row) { 123 StringBuilder fields = new StringBuilder(); 124 StringBuilder paramsOrPlaceholder = new StringBuilder(); 125 126 // 插入数据时,可能包含主键 127 Set<String> modifyAttrs = RowCPI.getInsertAttrs(row); 128 int index = 0; 129 for (String attr : modifyAttrs) { 130 fields.append(wrap(attr)); 131 132 Object value = row.get(attr); 133 if (value instanceof RawValue) { 134 paramsOrPlaceholder.append(((RawValue) value).toSql(this)); 135 } else { 136 paramsOrPlaceholder.append(PLACEHOLDER); 137 } 138 if (index != modifyAttrs.size() - 1) { 139 fields.append(DELIMITER); 140 paramsOrPlaceholder.append(DELIMITER); 141 } 142 index++; 143 } 144 145 String table = getRealTable(tableName, OperateType.INSERT); 146 StringBuilder sql = new StringBuilder(); 147 sql.append(INSERT_INTO); 148 if (StringUtil.hasText(schema)) { 149 sql.append(wrap(getRealSchema(schema, table, OperateType.INSERT))).append(REFERENCE); 150 } 151 sql.append(wrap(table)); 152 sql.append(BRACKET_LEFT).append(fields).append(BRACKET_RIGHT); 153 sql.append(VALUES).append(BRACKET_LEFT).append(paramsOrPlaceholder).append(BRACKET_RIGHT); 154 return sql.toString(); 155 } 156 157 158 @Override 159 public String forInsertBatchWithFirstRowColumns(String schema, String tableName, List<Row> rows) { 160 StringBuilder fields = new StringBuilder(); 161 StringBuilder questions = new StringBuilder(); 162 163 Row firstRow = rows.get(0); 164 Set<String> attrs = RowCPI.getInsertAttrs(firstRow); 165 int index = 0; 166 for (String column : attrs) { 167 fields.append(wrap(column)); 168 if (index != attrs.size() - 1) { 169 fields.append(DELIMITER); 170 } 171 index++; 172 } 173 174 for (int i = 0; i < rows.size(); i++) { 175 questions.append(SqlUtil.buildSqlParamPlaceholder(attrs.size())); 176 if (i != rows.size() - 1) { 177 questions.append(DELIMITER); 178 } 179 } 180 181 String table = getRealTable(tableName, OperateType.INSERT); 182 StringBuilder sql = new StringBuilder(); 183 sql.append(INSERT_INTO); 184 if (StringUtil.hasText(schema)) { 185 sql.append(wrap(getRealSchema(schema, table, OperateType.INSERT))).append(REFERENCE); 186 } 187 sql.append(wrap(table)); 188 sql.append(BLANK).append(BRACKET_LEFT) 189 .append(fields) 190 .append(BRACKET_RIGHT).append(BLANK); 191 sql.append(VALUES).append(questions); 192 return sql.toString(); 193 } 194 195 196 @Override 197 public String forDeleteById(String schema, String tableName, String[] primaryKeys) { 198 String table = getRealTable(tableName, OperateType.DELETE); 199 StringBuilder sql = new StringBuilder(); 200 sql.append(DELETE_FROM); 201 if (StringUtil.hasText(schema)) { 202 sql.append(wrap(getRealSchema(schema, table, OperateType.DELETE))).append(REFERENCE); 203 } 204 sql.append(wrap(table)); 205 sql.append(WHERE); 206 for (int i = 0; i < primaryKeys.length; i++) { 207 if (i > 0) { 208 sql.append(AND); 209 } 210 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 211 } 212 prepareAuth(schema, table, sql, OperateType.DELETE); 213 return sql.toString(); 214 } 215 216 217 @Override 218 public String forDeleteBatchByIds(String schema, String tableName, String[] primaryKeys, Object[] ids) { 219 String table = getRealTable(tableName, OperateType.DELETE); 220 StringBuilder sql = new StringBuilder(); 221 sql.append(DELETE_FROM); 222 if (StringUtil.hasText(schema)) { 223 sql.append(wrap(getRealSchema(schema, table, OperateType.DELETE))).append(REFERENCE); 224 } 225 226 sql.append(wrap(table)); 227 sql.append(WHERE); 228 229 // 多主键的场景 230 if (primaryKeys.length > 1) { 231 for (int i = 0; i < ids.length / primaryKeys.length; i++) { 232 if (i > 0) { 233 sql.append(OR); 234 } 235 sql.append(BRACKET_LEFT); 236 for (int j = 0; j < primaryKeys.length; j++) { 237 if (j > 0) { 238 sql.append(AND); 239 } 240 sql.append(wrap(primaryKeys[j])).append(EQUALS_PLACEHOLDER); 241 } 242 sql.append(BRACKET_RIGHT); 243 } 244 } 245 // 单主键 246 else { 247 for (int i = 0; i < ids.length; i++) { 248 if (i > 0) { 249 sql.append(OR); 250 } 251 sql.append(wrap(primaryKeys[0])).append(EQUALS_PLACEHOLDER); 252 } 253 } 254 prepareAuth(schema, table, sql, OperateType.DELETE); 255 return sql.toString(); 256 } 257 258 @Override 259 public String forDeleteByQuery(QueryWrapper queryWrapper) { 260 prepareAuth(queryWrapper, OperateType.DELETE); 261 return buildDeleteSql(queryWrapper); 262 } 263 264 @Override 265 public String forUpdateById(String schema, String tableName, Row row) { 266 String table = getRealTable(tableName, OperateType.UPDATE); 267 StringBuilder sql = new StringBuilder(); 268 Set<String> modifyAttrs = RowCPI.getModifyAttrs(row); 269 Map<String, RawValue> rawValueMap = RowCPI.getRawValueMap(row); 270 String[] primaryKeys = RowCPI.obtainsPrimaryKeyStrings(row); 271 272 sql.append(UPDATE); 273 if (StringUtil.hasText(schema)) { 274 sql.append(wrap(getRealSchema(schema, table, OperateType.UPDATE))).append(REFERENCE); 275 } 276 277 sql.append(wrap(table)).append(SET); 278 int index = 0; 279 for (Map.Entry<String, Object> e : row.entrySet()) { 280 String colName = e.getKey(); 281 if (modifyAttrs.contains(colName) && !ArrayUtil.contains(primaryKeys, colName)) { 282 if (index > 0) { 283 sql.append(DELIMITER); 284 } 285 sql.append(wrap(colName)); 286 287 if (rawValueMap.containsKey(colName)) { 288 sql.append(EQUALS).append(rawValueMap.get(colName).toSql(this)); 289 } else { 290 sql.append(EQUALS_PLACEHOLDER); 291 } 292 293 index++; 294 } 295 } 296 sql.append(WHERE); 297 for (int i = 0; i < primaryKeys.length; i++) { 298 if (i > 0) { 299 sql.append(AND); 300 } 301 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 302 } 303 prepareAuth(schema, table, sql, OperateType.UPDATE); 304 return sql.toString(); 305 } 306 307 @Override 308 public String forUpdateByQuery(QueryWrapper queryWrapper, Row row) { 309 prepareAuth(queryWrapper, OperateType.UPDATE); 310 StringBuilder sqlBuilder = new StringBuilder(); 311 312 Set<String> modifyAttrs = RowCPI.getModifyAttrs(row); 313 Map<String, RawValue> rawValueMap = RowCPI.getRawValueMap(row); 314 315 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 316 if (queryTables == null || queryTables.size() != 1) { 317 throw FlexExceptions.wrap(LocalizedFormats.UPDATE_ONLY_SUPPORT_1_TABLE); 318 } 319 320 // fix: support schema 321 QueryTable queryTable = queryTables.get(0); 322 sqlBuilder.append(UPDATE).append(queryTable.toSql(this, OperateType.UPDATE)).append(SET); 323 int index = 0; 324 for (String modifyAttr : modifyAttrs) { 325 if (index > 0) { 326 sqlBuilder.append(DELIMITER); 327 } 328 329 sqlBuilder.append(wrap(modifyAttr)); 330 331 if (rawValueMap.containsKey(modifyAttr)) { 332 sqlBuilder.append(EQUALS).append(rawValueMap.get(modifyAttr).toSql(this)); 333 } else { 334 sqlBuilder.append(EQUALS_PLACEHOLDER); 335 } 336 337 index++; 338 } 339 340 buildJoinSql(sqlBuilder, queryWrapper, queryTables, OperateType.UPDATE); 341 buildWhereSql(sqlBuilder, queryWrapper, queryTables, false); 342 buildGroupBySql(sqlBuilder, queryWrapper, queryTables); 343 buildHavingSql(sqlBuilder, queryWrapper, queryTables); 344 345 // ignore orderBy and limit 346 buildOrderBySql(sqlBuilder, queryWrapper, queryTables); 347 348 Long limitRows = CPI.getLimitRows(queryWrapper); 349 Long limitOffset = CPI.getLimitOffset(queryWrapper); 350 if (limitRows != null || limitOffset != null) { 351 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 352 } 353 354 return sqlBuilder.toString(); 355 } 356 357 @Override 358 public String forUpdateBatchById(String schema, String tableName, List<Row> rows) { 359 if (rows.size() == 1) { 360 return forUpdateById(schema, tableName, rows.get(0)); 361 } 362 StringBuilder sql = new StringBuilder(); 363 for (Row row : rows) { 364 sql.append(forUpdateById(schema, tableName, row)).append(SEMICOLON).append(BLANK); 365 } 366 return sql.toString(); 367 } 368 369 370 @Override 371 public String forSelectOneById(String schema, String tableName, String[] primaryKeys, Object[] primaryValues) { 372 String table = getRealTable(tableName, OperateType.SELECT); 373 StringBuilder sql = new StringBuilder(SELECT_ALL_FROM); 374 if (StringUtil.hasText(schema)) { 375 sql.append(wrap(getRealSchema(schema, table, OperateType.SELECT))).append(REFERENCE); 376 } 377 sql.append(wrap(table)).append(WHERE); 378 for (int i = 0; i < primaryKeys.length; i++) { 379 if (i > 0) { 380 sql.append(AND); 381 } 382 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 383 } 384 prepareAuth(schema, table, sql, OperateType.SELECT); 385 return sql.toString(); 386 } 387 388 @Override 389 public String forSelectByQuery(QueryWrapper queryWrapper) { 390 prepareAuth(queryWrapper, OperateType.SELECT); 391 return buildSelectSql(queryWrapper); 392 } 393 394 395 ////////////build query sql/////// 396 @Override 397 public String buildSelectSql(QueryWrapper queryWrapper) { 398 return buildSelectSql(queryWrapper, Collections.emptyList()); 399 } 400 401 @Override 402 public String buildSelectSql(QueryWrapper queryWrapper, List<QueryTable> contextTables) { 403 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 404 405 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 406 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 407 allTables = CollectionUtil.merge(allTables, contextTables); 408 409 List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper); 410 411 // 多个表,非 SELECT * 时,需要处理重名字段 412 if (allTables.size() > 1 && selectColumns != null && selectColumns.size() > 1) { 413 IntStream.range(0, selectColumns.size()) 414 .boxed() 415 // 生成 索引-字段值 对应关系 416 .collect(Collectors.toMap(Function.identity(), selectColumns::get)) 417 .entrySet() 418 .stream() 419 // 需要处理别名的情况 420 .filter(e -> StringUtil.hasText(e.getValue().getName())) 421 .filter(e -> StringUtil.noText(e.getValue().getAlias())) 422 .filter(e -> !"*".equals(e.getValue().getName())) 423 // 将相同字段对象放在一个集合里 424 .collect(Collectors.groupingBy(e -> e.getValue().getName(), 425 Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))) 426 .values() 427 .stream() 428 // 过滤出来重名的字段 429 .filter(e -> e.size() > 1) 430 // 合并所有需要加别名的字段 431 .flatMap(Collection::stream) 432 // 过滤出来可以添加别名的列 433 .filter(e -> e.getValue().getTable() != null) 434 .filter(e -> StringUtil.hasText(e.getValue().getTable().getName())) 435 // 添加别名并放回原集合索引位置 436 .forEach(e -> selectColumns.set(e.getKey(), 437 e.getValue().as(e.getValue().getTable().getName() + "$" + e.getValue().getName()))); 438 } 439 440 StringBuilder sqlBuilder = new StringBuilder(); 441 With with = CPI.getWith(queryWrapper); 442 if (with != null) { 443 sqlBuilder.append(with.toSql(this)); 444 } 445 446 buildSelectColumnSql(sqlBuilder, allTables, selectColumns, CPI.getHint(queryWrapper)); 447 448 449 if(CollectionUtil.isNotEmpty(queryTables)) { 450 sqlBuilder.append(FROM).append(StringUtil.join(DELIMITER, queryTables, queryTable -> queryTable.toSql(this, OperateType.SELECT))); 451 } 452 453 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.SELECT); 454 buildWhereSql(sqlBuilder, queryWrapper, allTables, true); 455 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 456 buildHavingSql(sqlBuilder, queryWrapper, allTables); 457 buildOrderBySql(sqlBuilder, queryWrapper, allTables); 458 459 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 460 if (CollectionUtil.isNotEmpty(unions)) { 461 sqlBuilder.insert(0, BRACKET_LEFT).append(BRACKET_RIGHT); 462 for (UnionWrapper unionWrapper : unions) { 463 unionWrapper.buildSql(sqlBuilder, this); 464 } 465 } 466 467 Long limitRows = CPI.getLimitRows(queryWrapper); 468 Long limitOffset = CPI.getLimitOffset(queryWrapper); 469 if (limitRows != null || limitOffset != null) { 470 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 471 } 472 473 List<String> endFragments = CPI.getEndFragments(queryWrapper); 474 if (CollectionUtil.isNotEmpty(endFragments)) { 475 for (String endFragment : endFragments) { 476 sqlBuilder.append(BLANK).append(endFragment); 477 } 478 } 479 480 return sqlBuilder.toString(); 481 } 482 483 @Override 484 public String buildNoSelectSql(QueryWrapper queryWrapper) { 485 StringBuilder sqlBuilder = new StringBuilder(); 486 487 buildJoinSql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST, OperateType.SELECT); 488 buildWhereSql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST, true); 489 buildGroupBySql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST); 490 buildHavingSql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST); 491 buildOrderBySql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST); 492 493 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 494 if (CollectionUtil.isNotEmpty(unions)) { 495 if (sqlBuilder.length() > 0) { 496 sqlBuilder.insert(0, BRACKET_LEFT).append(BRACKET_RIGHT); 497 } 498 for (UnionWrapper unionWrapper : unions) { 499 unionWrapper.buildSql(sqlBuilder, this); 500 } 501 } 502 503 Long limitRows = CPI.getLimitRows(queryWrapper); 504 Long limitOffset = CPI.getLimitOffset(queryWrapper); 505 if (limitRows != null || limitOffset != null) { 506 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 507 } 508 509 List<String> endFragments = CPI.getEndFragments(queryWrapper); 510 if (CollectionUtil.isNotEmpty(endFragments)) { 511 for (String endFragment : endFragments) { 512 sqlBuilder.append(BLANK).append(endFragment); 513 } 514 } 515 516 return sqlBuilder.toString(); 517 } 518 519 private void buildSelectColumnSql(StringBuilder sqlBuilder, List<QueryTable> queryTables, List<QueryColumn> selectColumns, String hint) { 520 sqlBuilder.append(SELECT); 521 sqlBuilder.append(forHint(hint)); 522 if (selectColumns == null || selectColumns.isEmpty()) { 523 sqlBuilder.append(ASTERISK); 524 } else { 525 int index = 0; 526 for (QueryColumn selectColumn : selectColumns) { 527 String selectColumnSql = CPI.toSelectSql(selectColumn, queryTables, this); 528 sqlBuilder.append(selectColumnSql); 529 if (index != selectColumns.size() - 1) { 530 sqlBuilder.append(DELIMITER); 531 } 532 index++; 533 } 534 } 535 } 536 537 538 @Override 539 public String buildDeleteSql(QueryWrapper queryWrapper) { 540 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 541 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 542 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 543 544 // ignore selectColumns 545 StringBuilder sqlBuilder = new StringBuilder(DELETE); 546 String hint = CPI.getHint(queryWrapper); 547 if (StringUtil.hasText(hint)) { 548 sqlBuilder.append(BLANK).append(hint).deleteCharAt(sqlBuilder.length() - 1); 549 } 550 551 // delete with join 552 if (joinTables != null && !joinTables.isEmpty()) { 553 if (queryTables == null || queryTables.isEmpty()) { 554 throw new IllegalArgumentException("Delete with join sql must designate the from table."); 555 } else if (queryTables.size() != 1) { 556 throw new IllegalArgumentException("Delete with join sql must has 1 table only. but current has " + queryTables.size()); 557 } 558 QueryTable queryTable = queryTables.get(0); 559 String table = getRealTable(queryTable.getName(), OperateType.DELETE); 560 if (StringUtil.hasText(queryTable.getSchema())) { 561 sqlBuilder.append(wrap(getRealSchema(queryTable.getSchema(), table, OperateType.DELETE))).append(REFERENCE); 562 } 563 sqlBuilder.append(BLANK).append(wrap(getRealTable(table, OperateType.DELETE))); 564 } 565 566 567 sqlBuilder.append(FROM).append(StringUtil.join(DELIMITER, queryTables, queryTable -> queryTable.toSql(this, OperateType.DELETE))); 568 569 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.DELETE); 570 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 571 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 572 buildHavingSql(sqlBuilder, queryWrapper, allTables); 573 574 // ignore orderBy and limit 575 buildOrderBySql(sqlBuilder, queryWrapper, allTables); 576 577 Long limitRows = CPI.getLimitRows(queryWrapper); 578 Long limitOffset = CPI.getLimitOffset(queryWrapper); 579 if (limitRows != null || limitOffset != null) { 580 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 581 } 582 583 List<String> endFragments = CPI.getEndFragments(queryWrapper); 584 if (CollectionUtil.isNotEmpty(endFragments)) { 585 for (String endFragment : endFragments) { 586 sqlBuilder.append(BLANK).append(endFragment); 587 } 588 } 589 590 return sqlBuilder.toString(); 591 } 592 593 594 @Override 595 public String buildWhereConditionSql(QueryWrapper queryWrapper) { 596 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 597 return whereQueryCondition != null ? whereQueryCondition.toSql(CPI.getQueryTables(queryWrapper), this) : EMPTY; 598 } 599 600 601 @Override 602 public String forInsertEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 603 StringBuilder sql = new StringBuilder(); 604 sql.append(INSERT_INTO).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.INSERT)); 605 606 String[] insertColumns = tableInfo.obtainInsertColumns(entity, ignoreNulls); 607 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 608 609 Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); 610 611 StringJoiner sqlFields = new StringJoiner(DELIMITER); 612 StringJoiner sqlValues = new StringJoiner(DELIMITER); 613 614 for (String insertColumn : insertColumns) { 615 sqlFields.add(wrap(insertColumn)); 616 if (rawValueMap.containsKey(insertColumn)) { 617 sqlValues.add(rawValueMap.remove(insertColumn).toSql(this)); 618 } else if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 619 sqlValues.add(onInsertColumns.get(insertColumn)); 620 } else { 621 sqlValues.add(PLACEHOLDER); 622 } 623 } 624 625 rawValueMap.forEach((k, v) -> { 626 sqlFields.add(wrap(k)); 627 sqlValues.add(v.toSql(this)); 628 }); 629 630 return sql.append(BRACKET_LEFT).append(sqlFields).append(BRACKET_RIGHT) 631 .append(VALUES) 632 .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) 633 .toString(); 634 } 635 636 637 @Override 638 public String forInsertEntityWithPk(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 639 640 StringBuilder sql = new StringBuilder(); 641 sql.append(INSERT_INTO).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.INSERT)); 642 643 String[] insertColumns = tableInfo.obtainInsertColumnsWithPk(entity, ignoreNulls); 644 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 645 646 StringJoiner sqlFields = new StringJoiner(DELIMITER); 647 StringJoiner sqlValues = new StringJoiner(DELIMITER); 648 649 for (String insertColumn : insertColumns) { 650 sqlFields.add(wrap(insertColumn)); 651 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 652 sqlValues.add(onInsertColumns.get(insertColumn)); 653 } else { 654 sqlValues.add(PLACEHOLDER); 655 } 656 } 657 658 return sql.append(BRACKET_LEFT).append(sqlFields).append(BRACKET_RIGHT) 659 .append(VALUES) 660 .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) 661 .toString(); 662 } 663 664 665 @Override 666 public String forInsertEntityBatch(TableInfo tableInfo, Collection<?> entities) { 667 StringBuilder sql = new StringBuilder(); 668 sql.append(INSERT_INTO).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.INSERT)); 669 String[] insertColumns = tableInfo.obtainInsertColumns(null, false); 670 String[] warpedInsertColumns = new String[insertColumns.length]; 671 for (int i = 0; i < insertColumns.length; i++) { 672 warpedInsertColumns[i] = wrap(insertColumns[i]); 673 } 674 sql.append(BRACKET_LEFT) 675 .append(StringUtil.join(DELIMITER, warpedInsertColumns)) 676 .append(BRACKET_RIGHT); 677 sql.append(VALUES); 678 679 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 680 for (int i = 0; i < entities.size(); i++) { 681 StringJoiner stringJoiner = new StringJoiner(DELIMITER, BRACKET_LEFT, BRACKET_RIGHT); 682 for (String insertColumn : insertColumns) { 683 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 684 // 直接读取 onInsert 配置的值,而不用 "?" 代替 685 stringJoiner.add(onInsertColumns.get(insertColumn)); 686 } else { 687 stringJoiner.add(PLACEHOLDER); 688 } 689 } 690 sql.append(stringJoiner); 691 if (i != entities.size() - 1) { 692 sql.append(DELIMITER); 693 } 694 } 695 696 return sql.toString(); 697 } 698 699 @Override 700 public String forDeleteEntityById(TableInfo tableInfo) { 701 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 702 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 703 704 // 正常删除 705 if (StringUtil.noText(logicDeleteColumn)) { 706 String deleteByIdSql = forDeleteById(tableInfo.getSchema(), tableInfo.getTableName(), tableInfo.getPrimaryColumns()); 707 return tableInfo.buildTenantCondition(deleteByIdSql, tenantIdArgs, this); 708 } 709 710 // 逻辑删除 711 StringBuilder sql = new StringBuilder(); 712 String[] primaryKeys = tableInfo.getPrimaryColumns(); 713 714 sql.append(UPDATE).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)); 715 sql.append(SET).append(buildLogicDeletedSet(logicDeleteColumn, tableInfo)); 716 sql.append(WHERE); 717 for (int i = 0; i < primaryKeys.length; i++) { 718 if (i > 0) { 719 sql.append(AND); 720 } 721 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 722 } 723 724 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 725 726 // 租户ID 727 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 728 prepareAuth(tableInfo, sql, OperateType.DELETE); 729 return sql.toString(); 730 } 731 732 733 @Override 734 public String forDeleteEntityBatchByIds(TableInfo tableInfo, Object[] primaryValues) { 735 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 736 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 737 738 // 正常删除 739 if (StringUtil.noText(logicDeleteColumn)) { 740 String deleteSQL = forDeleteBatchByIds(tableInfo.getSchema(), tableInfo.getTableName(), tableInfo.getPrimaryColumns(), primaryValues); 741 742 // 多租户 743 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 744 deleteSQL = deleteSQL.replace(WHERE, WHERE + BRACKET_LEFT) + BRACKET_RIGHT; 745 deleteSQL = tableInfo.buildTenantCondition(deleteSQL, tenantIdArgs, this); 746 } 747 return deleteSQL; 748 } 749 750 StringBuilder sql = new StringBuilder(); 751 sql.append(UPDATE); 752 sql.append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)); 753 sql.append(SET).append(buildLogicDeletedSet(logicDeleteColumn, tableInfo)); 754 sql.append(WHERE); 755 sql.append(BRACKET_LEFT); 756 757 String[] primaryKeys = tableInfo.getPrimaryColumns(); 758 759 // 多主键的场景 760 if (primaryKeys.length > 1) { 761 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 762 if (i > 0) { 763 sql.append(OR); 764 } 765 sql.append(BRACKET_LEFT); 766 for (int j = 0; j < primaryKeys.length; j++) { 767 if (j > 0) { 768 sql.append(AND); 769 } 770 sql.append(wrap(primaryKeys[j])).append(EQUALS_PLACEHOLDER); 771 } 772 sql.append(BRACKET_RIGHT); 773 } 774 } 775 // 单主键 776 else { 777 for (int i = 0; i < primaryValues.length; i++) { 778 if (i > 0) { 779 sql.append(OR); 780 } 781 sql.append(wrap(primaryKeys[0])).append(EQUALS_PLACEHOLDER); 782 } 783 } 784 785 sql.append(BRACKET_RIGHT).append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 786 787 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 788 prepareAuth(tableInfo, sql, OperateType.DELETE); 789 return sql.toString(); 790 } 791 792 @Override 793 public String forDeleteEntityBatchByQuery(TableInfo tableInfo, QueryWrapper queryWrapper) { 794 795 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 796 797 // 正常删除 798 if (StringUtil.noText(logicDeleteColumn)) { 799 return forDeleteByQuery(queryWrapper); 800 } 801 802 803 prepareAuth(queryWrapper, OperateType.DELETE); 804 // 逻辑删除 805 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 806 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 807 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 808 809 // ignore selectColumns 810 StringBuilder sqlBuilder = new StringBuilder(UPDATE).append(forHint(CPI.getHint(queryWrapper))); 811 sqlBuilder.append(tableInfo.getWrapSchemaAndTableName(this, OperateType.DELETE)); 812 sqlBuilder.append(SET).append(buildLogicDeletedSet(logicDeleteColumn, tableInfo)); 813 814 815 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.DELETE); 816 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 817 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 818 buildHavingSql(sqlBuilder, queryWrapper, allTables); 819 820 // ignore orderBy and limit 821 // buildOrderBySql(sqlBuilder, queryWrapper) 822 // buildLimitSql(sqlBuilder, queryWrapper) 823 824 return sqlBuilder.toString(); 825 } 826 827 828 @Override 829 public String forUpdateEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 830 StringBuilder sql = new StringBuilder(); 831 832 Set<String> updateColumns = tableInfo.obtainUpdateColumns(entity, ignoreNulls, false); 833 Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); 834 String[] primaryKeys = tableInfo.getPrimaryColumns(); 835 836 sql.append(UPDATE).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)).append(SET); 837 838 StringJoiner stringJoiner = new StringJoiner(DELIMITER); 839 840 for (String updateColumn : updateColumns) { 841 if (rawValueMap.containsKey(updateColumn)) { 842 stringJoiner.add(wrap(updateColumn) + EQUALS + rawValueMap.get(updateColumn).toSql(this)); 843 } else { 844 stringJoiner.add(wrap(updateColumn) + EQUALS_PLACEHOLDER); 845 } 846 } 847 848 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 849 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 850 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + EQUALS + value)); 851 } 852 853 // 乐观锁字段 854 String versionColumn = tableInfo.getVersionColumn(); 855 if (StringUtil.hasText(tableInfo.getOptimisticLockColumnOrSkip())) { 856 stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 "); 857 } 858 859 sql.append(stringJoiner); 860 861 sql.append(WHERE); 862 for (int i = 0; i < primaryKeys.length; i++) { 863 if (i > 0) { 864 sql.append(AND); 865 } 866 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 867 } 868 869 // 逻辑删除条件,已删除的数据不能被修改 870 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 871 if (StringUtil.hasText(logicDeleteColumn)) { 872 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 873 } 874 875 876 // 租户ID字段 877 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 878 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 879 880 // 乐观锁条件 881 if (StringUtil.hasText(tableInfo.getOptimisticLockColumnOrSkip())) { 882 Object versionValue = tableInfo.buildColumnSqlArg(entity, versionColumn); 883 if (versionValue == null) { 884 throw FlexExceptions.wrap(LocalizedFormats.ENTITY_VERSION_NULL, entity); 885 } 886 sql.append(AND).append(wrap(versionColumn)).append(EQUALS).append(versionValue); 887 } 888 889 prepareAuth(tableInfo, sql, OperateType.UPDATE); 890 return sql.toString(); 891 } 892 893 @Override 894 public String forUpdateEntityByQuery(TableInfo tableInfo, Object entity, boolean ignoreNulls, QueryWrapper queryWrapper) { 895 prepareAuth(queryWrapper, OperateType.UPDATE); 896 StringBuilder sqlBuilder = new StringBuilder(); 897 898 Set<String> updateColumns = tableInfo.obtainUpdateColumns(entity, ignoreNulls, true); 899 Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); 900 901 sqlBuilder.append(UPDATE).append(forHint(CPI.getHint(queryWrapper))); 902 sqlBuilder.append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)); 903 904 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 905 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 906 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 907 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.UPDATE); 908 909 910 sqlBuilder.append(SET); 911 912 StringJoiner stringJoiner = new StringJoiner(DELIMITER); 913 914 for (String modifyAttr : updateColumns) { 915 if (rawValueMap.containsKey(modifyAttr)) { 916 stringJoiner.add(wrap(modifyAttr) + EQUALS + rawValueMap.get(modifyAttr).toSql(this)); 917 } else { 918 stringJoiner.add(wrap(modifyAttr) + EQUALS_PLACEHOLDER); 919 } 920 } 921 922 923 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 924 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 925 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + EQUALS + value)); 926 } 927 928 // 乐观锁字段 929 String versionColumn = tableInfo.getVersionColumn(); 930 if (StringUtil.hasText(tableInfo.getOptimisticLockColumnOrSkip())) { 931 stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 "); 932 } 933 934 sqlBuilder.append(stringJoiner); 935 936 937 buildWhereSql(sqlBuilder, queryWrapper, queryTables, false); 938 buildGroupBySql(sqlBuilder, queryWrapper, queryTables); 939 buildHavingSql(sqlBuilder, queryWrapper, queryTables); 940 941 // ignore orderBy and limit 942 buildOrderBySql(sqlBuilder, queryWrapper, queryTables); 943 944 Long limitRows = CPI.getLimitRows(queryWrapper); 945 Long limitOffset = CPI.getLimitOffset(queryWrapper); 946 if (limitRows != null || limitOffset != null) { 947 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 948 } 949 950 951 List<String> endFragments = CPI.getEndFragments(queryWrapper); 952 if (CollectionUtil.isNotEmpty(endFragments)) { 953 for (String endFragment : endFragments) { 954 sqlBuilder.append(BLANK).append(endFragment); 955 } 956 } 957 958 return sqlBuilder.toString(); 959 } 960 961 962 @Override 963 public String forSelectOneEntityById(TableInfo tableInfo) { 964 StringBuilder sql = new StringBuilder(); 965 buildSelectColumnSql(sql, null, null, null); 966 sql.append(FROM).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.SELECT)); 967 sql.append(WHERE); 968 String[] pKeys = tableInfo.getPrimaryColumns(); 969 for (int i = 0; i < pKeys.length; i++) { 970 if (i > 0) { 971 sql.append(AND); 972 } 973 sql.append(wrap(pKeys[i])).append(EQUALS_PLACEHOLDER); 974 } 975 976 // 逻辑删除的情况下,需要添加逻辑删除的条件 977 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 978 if (StringUtil.hasText(logicDeleteColumn)) { 979 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 980 } 981 982 // 多租户 983 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 984 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 985 prepareAuth(tableInfo, sql, OperateType.SELECT); 986 return sql.toString(); 987 } 988 989 990 @Override 991 public String forSelectEntityListByIds(TableInfo tableInfo, Object[] primaryValues) { 992 StringBuilder sql = new StringBuilder(); 993 buildSelectColumnSql(sql, null, tableInfo.getDefaultQueryColumn(), null); 994 sql.append(FROM).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.SELECT)); 995 sql.append(WHERE); 996 String[] primaryKeys = tableInfo.getPrimaryColumns(); 997 998 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 999 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 1000 if (StringUtil.hasText(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 1001 sql.append(BRACKET_LEFT); 1002 } 1003 1004 // 多主键的场景 1005 if (primaryKeys.length > 1) { 1006 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 1007 if (i > 0) { 1008 sql.append(OR); 1009 } 1010 sql.append(BRACKET_LEFT); 1011 for (int j = 0; j < primaryKeys.length; j++) { 1012 if (j > 0) { 1013 sql.append(AND); 1014 } 1015 sql.append(wrap(primaryKeys[j])).append(EQUALS_PLACEHOLDER); 1016 } 1017 sql.append(BRACKET_RIGHT); 1018 } 1019 } 1020 // 单主键 1021 else { 1022 for (int i = 0; i < primaryValues.length; i++) { 1023 if (i > 0) { 1024 sql.append(OR); 1025 } 1026 sql.append(wrap(primaryKeys[0])).append(EQUALS_PLACEHOLDER); 1027 } 1028 } 1029 1030 if (StringUtil.hasText(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 1031 sql.append(BRACKET_RIGHT); 1032 } 1033 1034 1035 if (StringUtil.hasText(logicDeleteColumn)) { 1036 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 1037 } 1038 1039 // 多租户 1040 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 1041 prepareAuth(tableInfo, sql, OperateType.SELECT); 1042 return sql.toString(); 1043 } 1044 1045 1046 protected boolean buildJoinSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables, OperateType operateType) { 1047 List<Join> joins = CPI.getJoins(queryWrapper); 1048 boolean joinSuccess = false; 1049 if (joins != null && !joins.isEmpty()) { 1050 for (Join join : joins) { 1051 if (!join.checkEffective()) { 1052 continue; 1053 } 1054 sqlBuilder.append(join.toSql(queryTables, this, operateType)); 1055 joinSuccess = true; 1056 } 1057 } 1058 return joinSuccess; 1059 } 1060 1061 1062 protected void buildWhereSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables, boolean allowNoCondition) { 1063 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 1064 if (whereQueryCondition != null) { 1065 String whereSql = whereQueryCondition.toSql(queryTables, this); 1066 if (StringUtil.hasText(whereSql)) { 1067 sqlBuilder.append(WHERE).append(whereSql); 1068 } else if (!allowNoCondition) { 1069 throw FlexExceptions.wrap(LocalizedFormats.UPDATE_OR_DELETE_NOT_ALLOW); 1070 } 1071 } else { 1072 // whereQueryCondition == null 1073 if (!allowNoCondition) { 1074 throw FlexExceptions.wrap(LocalizedFormats.UPDATE_OR_DELETE_NOT_ALLOW); 1075 } 1076 } 1077 } 1078 1079 1080 protected void buildGroupBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 1081 List<QueryColumn> groupByColumns = CPI.getGroupByColumns(queryWrapper); 1082 if (groupByColumns != null && !groupByColumns.isEmpty()) { 1083 sqlBuilder.append(GROUP_BY); 1084 int index = 0; 1085 for (QueryColumn groupByColumn : groupByColumns) { 1086 String groupBy = CPI.toConditionSql(groupByColumn, queryTables, this); 1087 sqlBuilder.append(groupBy); 1088 if (index != groupByColumns.size() - 1) { 1089 sqlBuilder.append(DELIMITER); 1090 } 1091 index++; 1092 } 1093 } 1094 } 1095 1096 1097 protected void buildHavingSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 1098 QueryCondition havingQueryCondition = CPI.getHavingQueryCondition(queryWrapper); 1099 if (havingQueryCondition != null) { 1100 String havingSql = havingQueryCondition.toSql(queryTables, this); 1101 if (StringUtil.hasText(havingSql)) { 1102 sqlBuilder.append(HAVING).append(havingSql); 1103 } 1104 } 1105 } 1106 1107 1108 protected void buildOrderBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 1109 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 1110 if (orderBys != null && !orderBys.isEmpty()) { 1111 sqlBuilder.append(ORDER_BY); 1112 int index = 0; 1113 for (QueryOrderBy orderBy : orderBys) { 1114 sqlBuilder.append(orderBy.toSql(queryTables, this)); 1115 if (index != orderBys.size() - 1) { 1116 sqlBuilder.append(DELIMITER); 1117 } 1118 index++; 1119 } 1120 } 1121 } 1122 1123 1124 /** 1125 * 构建 limit 和 offset 的参数 1126 */ 1127 protected StringBuilder buildLimitOffsetSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, Long limitRows, Long limitOffset) { 1128 return limitOffsetProcessor.process(this, sqlBuilder, queryWrapper, limitRows, limitOffset); 1129 } 1130 1131 1132 protected String buildLogicNormalCondition(String logicColumn, TableInfo tableInfo) { 1133 return LogicDeleteManager.getProcessor().buildLogicNormalCondition(logicColumn, tableInfo, this); 1134 } 1135 1136 1137 protected String buildLogicDeletedSet(String logicColumn, TableInfo tableInfo) { 1138 return LogicDeleteManager.getProcessor().buildLogicDeletedSet(logicColumn, tableInfo, this); 1139 } 1140 1141 1142}