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