|
30 | 30 | import org.zstack.utils.*; |
31 | 31 | import org.zstack.utils.gson.JSONObjectUtil; |
32 | 32 | import org.zstack.utils.logging.CLogger; |
| 33 | +import org.zstack.core.db.EntityMetadata; |
33 | 34 | import org.zstack.zql.ZQL; |
34 | 35 | import org.zstack.zql.ZQLContext; |
35 | 36 | import org.zstack.zql.ZQLQueryReturn; |
@@ -483,7 +484,17 @@ public ZQLQueryReturn queryUseZQL(APIQueryMessage msg, Class inventoryClass) { |
483 | 484 | } |
484 | 485 |
|
485 | 486 | if (msg.getSortBy() != null) { |
486 | | - sb.add(String.format("order by %s %s", msg.getSortBy(), msg.getSortDirection())); |
| 487 | + String orderBy = String.format("order by %s %s", msg.getSortBy(), msg.getSortDirection()); |
| 488 | + String pkFieldName = getPrimaryKeyFieldNameSafely(targetInventoryClass); |
| 489 | + if (pkFieldName != null && !msg.getSortBy().equals(pkFieldName)) { |
| 490 | + orderBy += String.format(", %s asc", pkFieldName); |
| 491 | + } |
| 492 | + sb.add(orderBy); |
| 493 | + } else if (!msg.isCount() && (msg.getLimit() != null || msg.getStart() != null)) { |
| 494 | + String pkFieldName = getPrimaryKeyFieldNameSafely(targetInventoryClass); |
| 495 | + if (pkFieldName != null) { |
| 496 | + sb.add(String.format("order by %s asc", pkFieldName)); |
| 497 | + } |
487 | 498 | } |
488 | 499 |
|
489 | 500 | if (msg.getLimit() != null) { |
@@ -515,6 +526,24 @@ public ZQLQueryReturn queryUseZQL(APIQueryMessage msg, Class inventoryClass) { |
515 | 526 | return result; |
516 | 527 | } |
517 | 528 |
|
| 529 | + private String getPrimaryKeyFieldNameSafely(Class inventoryClass) { |
| 530 | + try { |
| 531 | + ZQLMetadata.InventoryMetadata meta = ZQLMetadata.findInventoryMetadata( |
| 532 | + ZQL.queryTargetNameFromInventoryClass(inventoryClass)); |
| 533 | + Class voClass = meta.inventoryAnnotation.mappingVOClass(); |
| 534 | + Field pkField = EntityMetadata.getPrimaryKeyField(voClass); |
| 535 | + String pkName = pkField.getName(); |
| 536 | + if (!meta.selfInventoryFieldNames.contains(pkName)) { |
| 537 | + return null; |
| 538 | + } |
| 539 | + return pkName; |
| 540 | + } catch (Exception e) { |
| 541 | + logger.trace(String.format("cannot resolve PK for %s, skip pagination tiebreaker: %s", |
| 542 | + inventoryClass.getSimpleName(), e.getMessage())); |
| 543 | + return null; |
| 544 | + } |
| 545 | + } |
| 546 | + |
518 | 547 | private QueryBelongFilter validateFilterNameAndGetExp(String filterName) { |
519 | 548 | if (filterName.split(":").length < 2) { |
520 | 549 | throw new OperationFailureException(argerr(ORG_ZSTACK_QUERY_10015, "filterName must be formatted as [filterType:condition(s)]")); |
|
0 commit comments