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