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 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 399 400 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 401 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 402 403 List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper); 404 405 // 多个表,非 SELECT * 时,需要处理重名字段 406 if (allTables.size() > 1 && selectColumns != null && selectColumns.size() > 1) { 407 IntStream.range(0, selectColumns.size()) 408 .boxed() 409 // 生成 索引-字段值 对应关系 410 .collect(Collectors.toMap(Function.identity(), selectColumns::get)) 411 .entrySet() 412 .stream() 413 // 需要处理别名的情况 414 .filter(e -> StringUtil.hasText(e.getValue().getName())) 415 .filter(e -> StringUtil.noText(e.getValue().getAlias())) 416 .filter(e -> !"*".equals(e.getValue().getName())) 417 // 将相同字段对象放在一个集合里 418 .collect(Collectors.groupingBy(e -> e.getValue().getName(), 419 Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))) 420 .values() 421 .stream() 422 // 过滤出来重名的字段 423 .filter(e -> e.size() > 1) 424 // 合并所有需要加别名的字段 425 .flatMap(Collection::stream) 426 // 过滤出来可以添加别名的列 427 .filter(e -> e.getValue().getTable() != null) 428 .filter(e -> StringUtil.hasText(e.getValue().getTable().getName())) 429 // 添加别名并放回原集合索引位置 430 .forEach(e -> selectColumns.set(e.getKey(), 431 e.getValue().as(e.getValue().getTable().getName() + "$" + e.getValue().getName()))); 432 } 433 434 StringBuilder sqlBuilder = new StringBuilder(); 435 With with = CPI.getWith(queryWrapper); 436 if (with != null) { 437 sqlBuilder.append(with.toSql(this)); 438 } 439 440 buildSelectColumnSql(sqlBuilder, allTables, selectColumns, CPI.getHint(queryWrapper)); 441 442 443 if(CollectionUtil.isNotEmpty(queryTables)) { 444 sqlBuilder.append(FROM).append(StringUtil.join(DELIMITER, queryTables, queryTable -> queryTable.toSql(this, OperateType.SELECT))); 445 } 446 447 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.SELECT); 448 buildWhereSql(sqlBuilder, queryWrapper, allTables, true); 449 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 450 buildHavingSql(sqlBuilder, queryWrapper, allTables); 451 buildOrderBySql(sqlBuilder, queryWrapper, allTables); 452 453 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 454 if (CollectionUtil.isNotEmpty(unions)) { 455 sqlBuilder.insert(0, BRACKET_LEFT).append(BRACKET_RIGHT); 456 for (UnionWrapper unionWrapper : unions) { 457 unionWrapper.buildSql(sqlBuilder, this); 458 } 459 } 460 461 Long limitRows = CPI.getLimitRows(queryWrapper); 462 Long limitOffset = CPI.getLimitOffset(queryWrapper); 463 if (limitRows != null || limitOffset != null) { 464 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 465 } 466 467 List<String> endFragments = CPI.getEndFragments(queryWrapper); 468 if (CollectionUtil.isNotEmpty(endFragments)) { 469 for (String endFragment : endFragments) { 470 sqlBuilder.append(BLANK).append(endFragment); 471 } 472 } 473 474 return sqlBuilder.toString(); 475 } 476 477 @Override 478 public String buildNoSelectSql(QueryWrapper queryWrapper) { 479 StringBuilder sqlBuilder = new StringBuilder(); 480 481 buildJoinSql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST, OperateType.SELECT); 482 buildWhereSql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST, true); 483 buildGroupBySql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST); 484 buildHavingSql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST); 485 buildOrderBySql(sqlBuilder, queryWrapper, Collections.EMPTY_LIST); 486 487 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 488 if (CollectionUtil.isNotEmpty(unions)) { 489 if (sqlBuilder.length() > 0) { 490 sqlBuilder.insert(0, BRACKET_LEFT).append(BRACKET_RIGHT); 491 } 492 for (UnionWrapper unionWrapper : unions) { 493 unionWrapper.buildSql(sqlBuilder, this); 494 } 495 } 496 497 Long limitRows = CPI.getLimitRows(queryWrapper); 498 Long limitOffset = CPI.getLimitOffset(queryWrapper); 499 if (limitRows != null || limitOffset != null) { 500 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 501 } 502 503 List<String> endFragments = CPI.getEndFragments(queryWrapper); 504 if (CollectionUtil.isNotEmpty(endFragments)) { 505 for (String endFragment : endFragments) { 506 sqlBuilder.append(BLANK).append(endFragment); 507 } 508 } 509 510 return sqlBuilder.toString(); 511 } 512 513 private void buildSelectColumnSql(StringBuilder sqlBuilder, List<QueryTable> queryTables, List<QueryColumn> selectColumns, String hint) { 514 sqlBuilder.append(SELECT); 515 sqlBuilder.append(forHint(hint)); 516 if (selectColumns == null || selectColumns.isEmpty()) { 517 sqlBuilder.append(ASTERISK); 518 } else { 519 int index = 0; 520 for (QueryColumn selectColumn : selectColumns) { 521 String selectColumnSql = CPI.toSelectSql(selectColumn, queryTables, this); 522 sqlBuilder.append(selectColumnSql); 523 if (index != selectColumns.size() - 1) { 524 sqlBuilder.append(DELIMITER); 525 } 526 index++; 527 } 528 } 529 } 530 531 532 @Override 533 public String buildDeleteSql(QueryWrapper queryWrapper) { 534 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 535 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 536 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 537 538 // ignore selectColumns 539 StringBuilder sqlBuilder = new StringBuilder(DELETE); 540 String hint = CPI.getHint(queryWrapper); 541 if (StringUtil.hasText(hint)) { 542 sqlBuilder.append(BLANK).append(hint).deleteCharAt(sqlBuilder.length() - 1); 543 } 544 545 // delete with join 546 if (joinTables != null && !joinTables.isEmpty()) { 547 if (queryTables == null || queryTables.isEmpty()) { 548 throw new IllegalArgumentException("Delete with join sql must designate the from table."); 549 } else if (queryTables.size() != 1) { 550 throw new IllegalArgumentException("Delete with join sql must has 1 table only. but current has " + queryTables.size()); 551 } 552 QueryTable queryTable = queryTables.get(0); 553 String table = getRealTable(queryTable.getName(), OperateType.DELETE); 554 if (StringUtil.hasText(queryTable.getSchema())) { 555 sqlBuilder.append(wrap(getRealSchema(queryTable.getSchema(), table, OperateType.DELETE))).append(REFERENCE); 556 } 557 sqlBuilder.append(BLANK).append(wrap(getRealTable(table, OperateType.DELETE))); 558 } 559 560 561 sqlBuilder.append(FROM).append(StringUtil.join(DELIMITER, queryTables, queryTable -> queryTable.toSql(this, OperateType.DELETE))); 562 563 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.DELETE); 564 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 565 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 566 buildHavingSql(sqlBuilder, queryWrapper, allTables); 567 568 // ignore orderBy and limit 569 buildOrderBySql(sqlBuilder, queryWrapper, allTables); 570 571 Long limitRows = CPI.getLimitRows(queryWrapper); 572 Long limitOffset = CPI.getLimitOffset(queryWrapper); 573 if (limitRows != null || limitOffset != null) { 574 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 575 } 576 577 List<String> endFragments = CPI.getEndFragments(queryWrapper); 578 if (CollectionUtil.isNotEmpty(endFragments)) { 579 for (String endFragment : endFragments) { 580 sqlBuilder.append(BLANK).append(endFragment); 581 } 582 } 583 584 return sqlBuilder.toString(); 585 } 586 587 588 @Override 589 public String buildWhereConditionSql(QueryWrapper queryWrapper) { 590 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 591 return whereQueryCondition != null ? whereQueryCondition.toSql(CPI.getQueryTables(queryWrapper), this) : EMPTY; 592 } 593 594 595 @Override 596 public String forInsertEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 597 StringBuilder sql = new StringBuilder(); 598 sql.append(INSERT_INTO).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.INSERT)); 599 600 String[] insertColumns = tableInfo.obtainInsertColumns(entity, ignoreNulls); 601 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 602 603 Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); 604 605 StringJoiner sqlFields = new StringJoiner(DELIMITER); 606 StringJoiner sqlValues = new StringJoiner(DELIMITER); 607 608 for (String insertColumn : insertColumns) { 609 sqlFields.add(wrap(insertColumn)); 610 if (rawValueMap.containsKey(insertColumn)) { 611 sqlValues.add(rawValueMap.remove(insertColumn).toSql(this)); 612 } else if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 613 sqlValues.add(onInsertColumns.get(insertColumn)); 614 } else { 615 sqlValues.add(PLACEHOLDER); 616 } 617 } 618 619 rawValueMap.forEach((k, v) -> { 620 sqlFields.add(wrap(k)); 621 sqlValues.add(v.toSql(this)); 622 }); 623 624 return sql.append(BRACKET_LEFT).append(sqlFields).append(BRACKET_RIGHT) 625 .append(VALUES) 626 .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) 627 .toString(); 628 } 629 630 631 @Override 632 public String forInsertEntityWithPk(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 633 634 StringBuilder sql = new StringBuilder(); 635 sql.append(INSERT_INTO).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.INSERT)); 636 637 String[] insertColumns = tableInfo.obtainInsertColumnsWithPk(entity, ignoreNulls); 638 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 639 640 StringJoiner sqlFields = new StringJoiner(DELIMITER); 641 StringJoiner sqlValues = new StringJoiner(DELIMITER); 642 643 for (String insertColumn : insertColumns) { 644 sqlFields.add(wrap(insertColumn)); 645 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 646 sqlValues.add(onInsertColumns.get(insertColumn)); 647 } else { 648 sqlValues.add(PLACEHOLDER); 649 } 650 } 651 652 return sql.append(BRACKET_LEFT).append(sqlFields).append(BRACKET_RIGHT) 653 .append(VALUES) 654 .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) 655 .toString(); 656 } 657 658 659 @Override 660 public String forInsertEntityBatch(TableInfo tableInfo, Collection<?> entities) { 661 StringBuilder sql = new StringBuilder(); 662 sql.append(INSERT_INTO).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.INSERT)); 663 String[] insertColumns = tableInfo.obtainInsertColumns(null, false); 664 String[] warpedInsertColumns = new String[insertColumns.length]; 665 for (int i = 0; i < insertColumns.length; i++) { 666 warpedInsertColumns[i] = wrap(insertColumns[i]); 667 } 668 sql.append(BRACKET_LEFT) 669 .append(StringUtil.join(DELIMITER, warpedInsertColumns)) 670 .append(BRACKET_RIGHT); 671 sql.append(VALUES); 672 673 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 674 for (int i = 0; i < entities.size(); i++) { 675 StringJoiner stringJoiner = new StringJoiner(DELIMITER, BRACKET_LEFT, BRACKET_RIGHT); 676 for (String insertColumn : insertColumns) { 677 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 678 // 直接读取 onInsert 配置的值,而不用 "?" 代替 679 stringJoiner.add(onInsertColumns.get(insertColumn)); 680 } else { 681 stringJoiner.add(PLACEHOLDER); 682 } 683 } 684 sql.append(stringJoiner); 685 if (i != entities.size() - 1) { 686 sql.append(DELIMITER); 687 } 688 } 689 690 return sql.toString(); 691 } 692 693 @Override 694 public String forDeleteEntityById(TableInfo tableInfo) { 695 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 696 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 697 698 // 正常删除 699 if (StringUtil.noText(logicDeleteColumn)) { 700 String deleteByIdSql = forDeleteById(tableInfo.getSchema(), tableInfo.getTableName(), tableInfo.getPrimaryColumns()); 701 return tableInfo.buildTenantCondition(deleteByIdSql, tenantIdArgs, this); 702 } 703 704 // 逻辑删除 705 StringBuilder sql = new StringBuilder(); 706 String[] primaryKeys = tableInfo.getPrimaryColumns(); 707 708 sql.append(UPDATE).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)); 709 sql.append(SET).append(buildLogicDeletedSet(logicDeleteColumn, tableInfo)); 710 sql.append(WHERE); 711 for (int i = 0; i < primaryKeys.length; i++) { 712 if (i > 0) { 713 sql.append(AND); 714 } 715 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 716 } 717 718 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 719 720 // 租户ID 721 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 722 prepareAuth(tableInfo, sql, OperateType.DELETE); 723 return sql.toString(); 724 } 725 726 727 @Override 728 public String forDeleteEntityBatchByIds(TableInfo tableInfo, Object[] primaryValues) { 729 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 730 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 731 732 // 正常删除 733 if (StringUtil.noText(logicDeleteColumn)) { 734 String deleteSQL = forDeleteBatchByIds(tableInfo.getSchema(), tableInfo.getTableName(), tableInfo.getPrimaryColumns(), primaryValues); 735 736 // 多租户 737 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 738 deleteSQL = deleteSQL.replace(WHERE, WHERE + BRACKET_LEFT) + BRACKET_RIGHT; 739 deleteSQL = tableInfo.buildTenantCondition(deleteSQL, tenantIdArgs, this); 740 } 741 return deleteSQL; 742 } 743 744 StringBuilder sql = new StringBuilder(); 745 sql.append(UPDATE); 746 sql.append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)); 747 sql.append(SET).append(buildLogicDeletedSet(logicDeleteColumn, tableInfo)); 748 sql.append(WHERE); 749 sql.append(BRACKET_LEFT); 750 751 String[] primaryKeys = tableInfo.getPrimaryColumns(); 752 753 // 多主键的场景 754 if (primaryKeys.length > 1) { 755 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 756 if (i > 0) { 757 sql.append(OR); 758 } 759 sql.append(BRACKET_LEFT); 760 for (int j = 0; j < primaryKeys.length; j++) { 761 if (j > 0) { 762 sql.append(AND); 763 } 764 sql.append(wrap(primaryKeys[j])).append(EQUALS_PLACEHOLDER); 765 } 766 sql.append(BRACKET_RIGHT); 767 } 768 } 769 // 单主键 770 else { 771 for (int i = 0; i < primaryValues.length; i++) { 772 if (i > 0) { 773 sql.append(OR); 774 } 775 sql.append(wrap(primaryKeys[0])).append(EQUALS_PLACEHOLDER); 776 } 777 } 778 779 sql.append(BRACKET_RIGHT).append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 780 781 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 782 prepareAuth(tableInfo, sql, OperateType.DELETE); 783 return sql.toString(); 784 } 785 786 @Override 787 public String forDeleteEntityBatchByQuery(TableInfo tableInfo, QueryWrapper queryWrapper) { 788 789 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 790 791 // 正常删除 792 if (StringUtil.noText(logicDeleteColumn)) { 793 return forDeleteByQuery(queryWrapper); 794 } 795 796 797 prepareAuth(queryWrapper, OperateType.DELETE); 798 // 逻辑删除 799 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 800 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 801 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 802 803 // ignore selectColumns 804 StringBuilder sqlBuilder = new StringBuilder(UPDATE).append(forHint(CPI.getHint(queryWrapper))); 805 sqlBuilder.append(tableInfo.getWrapSchemaAndTableName(this, OperateType.DELETE)); 806 sqlBuilder.append(SET).append(buildLogicDeletedSet(logicDeleteColumn, tableInfo)); 807 808 809 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.DELETE); 810 buildWhereSql(sqlBuilder, queryWrapper, allTables, false); 811 buildGroupBySql(sqlBuilder, queryWrapper, allTables); 812 buildHavingSql(sqlBuilder, queryWrapper, allTables); 813 814 // ignore orderBy and limit 815 // buildOrderBySql(sqlBuilder, queryWrapper) 816 // buildLimitSql(sqlBuilder, queryWrapper) 817 818 return sqlBuilder.toString(); 819 } 820 821 822 @Override 823 public String forUpdateEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls) { 824 StringBuilder sql = new StringBuilder(); 825 826 Set<String> updateColumns = tableInfo.obtainUpdateColumns(entity, ignoreNulls, false); 827 Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); 828 String[] primaryKeys = tableInfo.getPrimaryColumns(); 829 830 sql.append(UPDATE).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)).append(SET); 831 832 StringJoiner stringJoiner = new StringJoiner(DELIMITER); 833 834 for (String updateColumn : updateColumns) { 835 if (rawValueMap.containsKey(updateColumn)) { 836 stringJoiner.add(wrap(updateColumn) + EQUALS + rawValueMap.get(updateColumn).toSql(this)); 837 } else { 838 stringJoiner.add(wrap(updateColumn) + EQUALS_PLACEHOLDER); 839 } 840 } 841 842 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 843 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 844 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + EQUALS + value)); 845 } 846 847 // 乐观锁字段 848 String versionColumn = tableInfo.getVersionColumn(); 849 if (StringUtil.hasText(tableInfo.getOptimisticLockColumnOrSkip())) { 850 stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 "); 851 } 852 853 sql.append(stringJoiner); 854 855 sql.append(WHERE); 856 for (int i = 0; i < primaryKeys.length; i++) { 857 if (i > 0) { 858 sql.append(AND); 859 } 860 sql.append(wrap(primaryKeys[i])).append(EQUALS_PLACEHOLDER); 861 } 862 863 // 逻辑删除条件,已删除的数据不能被修改 864 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 865 if (StringUtil.hasText(logicDeleteColumn)) { 866 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 867 } 868 869 870 // 租户ID字段 871 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 872 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 873 874 // 乐观锁条件 875 if (StringUtil.hasText(tableInfo.getOptimisticLockColumnOrSkip())) { 876 Object versionValue = tableInfo.buildColumnSqlArg(entity, versionColumn); 877 if (versionValue == null) { 878 throw FlexExceptions.wrap(LocalizedFormats.ENTITY_VERSION_NULL, entity); 879 } 880 sql.append(AND).append(wrap(versionColumn)).append(EQUALS).append(versionValue); 881 } 882 883 prepareAuth(tableInfo, sql, OperateType.UPDATE); 884 return sql.toString(); 885 } 886 887 @Override 888 public String forUpdateEntityByQuery(TableInfo tableInfo, Object entity, boolean ignoreNulls, QueryWrapper queryWrapper) { 889 prepareAuth(queryWrapper, OperateType.UPDATE); 890 StringBuilder sqlBuilder = new StringBuilder(); 891 892 Set<String> updateColumns = tableInfo.obtainUpdateColumns(entity, ignoreNulls, true); 893 Map<String, RawValue> rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); 894 895 sqlBuilder.append(UPDATE).append(forHint(CPI.getHint(queryWrapper))); 896 sqlBuilder.append(tableInfo.getWrapSchemaAndTableName(this, OperateType.UPDATE)); 897 898 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 899 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 900 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 901 buildJoinSql(sqlBuilder, queryWrapper, allTables, OperateType.UPDATE); 902 903 904 sqlBuilder.append(SET); 905 906 StringJoiner stringJoiner = new StringJoiner(DELIMITER); 907 908 for (String modifyAttr : updateColumns) { 909 if (rawValueMap.containsKey(modifyAttr)) { 910 stringJoiner.add(wrap(modifyAttr) + EQUALS + rawValueMap.get(modifyAttr).toSql(this)); 911 } else { 912 stringJoiner.add(wrap(modifyAttr) + EQUALS_PLACEHOLDER); 913 } 914 } 915 916 917 Map<String, String> onUpdateColumns = tableInfo.getOnUpdateColumns(); 918 if (onUpdateColumns != null && !onUpdateColumns.isEmpty()) { 919 onUpdateColumns.forEach((column, value) -> stringJoiner.add(wrap(column) + EQUALS + value)); 920 } 921 922 // 乐观锁字段 923 String versionColumn = tableInfo.getVersionColumn(); 924 if (StringUtil.hasText(tableInfo.getOptimisticLockColumnOrSkip())) { 925 stringJoiner.add(wrap(versionColumn) + EQUALS + wrap(versionColumn) + " + 1 "); 926 } 927 928 sqlBuilder.append(stringJoiner); 929 930 931 buildWhereSql(sqlBuilder, queryWrapper, queryTables, false); 932 buildGroupBySql(sqlBuilder, queryWrapper, queryTables); 933 buildHavingSql(sqlBuilder, queryWrapper, queryTables); 934 935 // ignore orderBy and limit 936 buildOrderBySql(sqlBuilder, queryWrapper, queryTables); 937 938 Long limitRows = CPI.getLimitRows(queryWrapper); 939 Long limitOffset = CPI.getLimitOffset(queryWrapper); 940 if (limitRows != null || limitOffset != null) { 941 sqlBuilder = buildLimitOffsetSql(sqlBuilder, queryWrapper, limitRows, limitOffset); 942 } 943 944 945 List<String> endFragments = CPI.getEndFragments(queryWrapper); 946 if (CollectionUtil.isNotEmpty(endFragments)) { 947 for (String endFragment : endFragments) { 948 sqlBuilder.append(BLANK).append(endFragment); 949 } 950 } 951 952 return sqlBuilder.toString(); 953 } 954 955 956 @Override 957 public String forSelectOneEntityById(TableInfo tableInfo) { 958 StringBuilder sql = new StringBuilder(); 959 buildSelectColumnSql(sql, null, null, null); 960 sql.append(FROM).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.SELECT)); 961 sql.append(WHERE); 962 String[] pKeys = tableInfo.getPrimaryColumns(); 963 for (int i = 0; i < pKeys.length; i++) { 964 if (i > 0) { 965 sql.append(AND); 966 } 967 sql.append(wrap(pKeys[i])).append(EQUALS_PLACEHOLDER); 968 } 969 970 // 逻辑删除的情况下,需要添加逻辑删除的条件 971 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 972 if (StringUtil.hasText(logicDeleteColumn)) { 973 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 974 } 975 976 // 多租户 977 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 978 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 979 prepareAuth(tableInfo, sql, OperateType.SELECT); 980 return sql.toString(); 981 } 982 983 984 @Override 985 public String forSelectEntityListByIds(TableInfo tableInfo, Object[] primaryValues) { 986 StringBuilder sql = new StringBuilder(); 987 buildSelectColumnSql(sql, null, tableInfo.getDefaultQueryColumn(), null); 988 sql.append(FROM).append(tableInfo.getWrapSchemaAndTableName(this, OperateType.SELECT)); 989 sql.append(WHERE); 990 String[] primaryKeys = tableInfo.getPrimaryColumns(); 991 992 String logicDeleteColumn = tableInfo.getLogicDeleteColumnOrSkip(); 993 Object[] tenantIdArgs = tableInfo.buildTenantIdArgs(); 994 if (StringUtil.hasText(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 995 sql.append(BRACKET_LEFT); 996 } 997 998 // 多主键的场景 999 if (primaryKeys.length > 1) { 1000 for (int i = 0; i < primaryValues.length / primaryKeys.length; i++) { 1001 if (i > 0) { 1002 sql.append(OR); 1003 } 1004 sql.append(BRACKET_LEFT); 1005 for (int j = 0; j < primaryKeys.length; j++) { 1006 if (j > 0) { 1007 sql.append(AND); 1008 } 1009 sql.append(wrap(primaryKeys[j])).append(EQUALS_PLACEHOLDER); 1010 } 1011 sql.append(BRACKET_RIGHT); 1012 } 1013 } 1014 // 单主键 1015 else { 1016 for (int i = 0; i < primaryValues.length; i++) { 1017 if (i > 0) { 1018 sql.append(OR); 1019 } 1020 sql.append(wrap(primaryKeys[0])).append(EQUALS_PLACEHOLDER); 1021 } 1022 } 1023 1024 if (StringUtil.hasText(logicDeleteColumn) || ArrayUtil.isNotEmpty(tenantIdArgs)) { 1025 sql.append(BRACKET_RIGHT); 1026 } 1027 1028 1029 if (StringUtil.hasText(logicDeleteColumn)) { 1030 sql.append(AND).append(buildLogicNormalCondition(logicDeleteColumn, tableInfo)); 1031 } 1032 1033 // 多租户 1034 tableInfo.buildTenantCondition(sql, tenantIdArgs, this); 1035 prepareAuth(tableInfo, sql, OperateType.SELECT); 1036 return sql.toString(); 1037 } 1038 1039 1040 protected boolean buildJoinSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables, OperateType operateType) { 1041 List<Join> joins = CPI.getJoins(queryWrapper); 1042 boolean joinSuccess = false; 1043 if (joins != null && !joins.isEmpty()) { 1044 for (Join join : joins) { 1045 if (!join.checkEffective()) { 1046 continue; 1047 } 1048 sqlBuilder.append(join.toSql(queryTables, this, operateType)); 1049 joinSuccess = true; 1050 } 1051 } 1052 return joinSuccess; 1053 } 1054 1055 1056 protected void buildWhereSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables, boolean allowNoCondition) { 1057 QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(queryWrapper); 1058 if (whereQueryCondition != null) { 1059 String whereSql = whereQueryCondition.toSql(queryTables, this); 1060 if (StringUtil.hasText(whereSql)) { 1061 sqlBuilder.append(WHERE).append(whereSql); 1062 } else if (!allowNoCondition) { 1063 throw FlexExceptions.wrap(LocalizedFormats.UPDATE_OR_DELETE_NOT_ALLOW); 1064 } 1065 } else { 1066 // whereQueryCondition == null 1067 if (!allowNoCondition) { 1068 throw FlexExceptions.wrap(LocalizedFormats.UPDATE_OR_DELETE_NOT_ALLOW); 1069 } 1070 } 1071 } 1072 1073 1074 protected void buildGroupBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 1075 List<QueryColumn> groupByColumns = CPI.getGroupByColumns(queryWrapper); 1076 if (groupByColumns != null && !groupByColumns.isEmpty()) { 1077 sqlBuilder.append(GROUP_BY); 1078 int index = 0; 1079 for (QueryColumn groupByColumn : groupByColumns) { 1080 String groupBy = CPI.toConditionSql(groupByColumn, queryTables, this); 1081 sqlBuilder.append(groupBy); 1082 if (index != groupByColumns.size() - 1) { 1083 sqlBuilder.append(DELIMITER); 1084 } 1085 index++; 1086 } 1087 } 1088 } 1089 1090 1091 protected void buildHavingSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 1092 QueryCondition havingQueryCondition = CPI.getHavingQueryCondition(queryWrapper); 1093 if (havingQueryCondition != null) { 1094 String havingSql = havingQueryCondition.toSql(queryTables, this); 1095 if (StringUtil.hasText(havingSql)) { 1096 sqlBuilder.append(HAVING).append(havingSql); 1097 } 1098 } 1099 } 1100 1101 1102 protected void buildOrderBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 1103 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 1104 if (orderBys != null && !orderBys.isEmpty()) { 1105 sqlBuilder.append(ORDER_BY); 1106 int index = 0; 1107 for (QueryOrderBy orderBy : orderBys) { 1108 sqlBuilder.append(orderBy.toSql(queryTables, this)); 1109 if (index != orderBys.size() - 1) { 1110 sqlBuilder.append(DELIMITER); 1111 } 1112 index++; 1113 } 1114 } 1115 } 1116 1117 1118 /** 1119 * 构建 limit 和 offset 的参数 1120 */ 1121 protected StringBuilder buildLimitOffsetSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, Long limitRows, Long limitOffset) { 1122 return limitOffsetProcessor.process(this, sqlBuilder, queryWrapper, limitRows, limitOffset); 1123 } 1124 1125 1126 protected String buildLogicNormalCondition(String logicColumn, TableInfo tableInfo) { 1127 return LogicDeleteManager.getProcessor().buildLogicNormalCondition(logicColumn, tableInfo, this); 1128 } 1129 1130 1131 protected String buildLogicDeletedSet(String logicColumn, TableInfo tableInfo) { 1132 return LogicDeleteManager.getProcessor().buildLogicDeletedSet(logicColumn, tableInfo, this); 1133 } 1134 1135 1136}