|
26 | 26 | import org.apache.paimon.format.FileFormat; |
27 | 27 | import org.apache.paimon.mergetree.compact.aggregate.FieldAggregator; |
28 | 28 | import org.apache.paimon.mergetree.compact.aggregate.factory.FieldAggregatorFactory; |
| 29 | +import org.apache.paimon.mergetree.compact.aggregate.factory.FieldLastNonNullValueAggFactory; |
29 | 30 | import org.apache.paimon.options.ConfigOption; |
30 | 31 | import org.apache.paimon.options.Options; |
31 | 32 | import org.apache.paimon.table.BucketMode; |
@@ -450,11 +451,15 @@ private static void validateFieldsPrefix(TableSchema schema, CoreOptions options |
450 | 451 |
|
451 | 452 | private static void validateSequenceGroup(TableSchema schema, CoreOptions options) { |
452 | 453 | Map<String, Set<String>> fields2Group = new HashMap<>(); |
| 454 | + Set<Integer> sequenceGroupFieldIndexs = new HashSet<>(); |
| 455 | + List<String> fieldNames = schema.fieldNames(); |
453 | 456 | for (Map.Entry<String, String> entry : options.toMap().entrySet()) { |
454 | 457 | String k = entry.getKey(); |
455 | 458 | String v = entry.getValue(); |
456 | | - List<String> fieldNames = schema.fieldNames(); |
457 | 459 | if (k.startsWith(FIELDS_PREFIX) && k.endsWith(SEQUENCE_GROUP)) { |
| 460 | + Arrays.stream(v.split(FIELDS_SEPARATOR)) |
| 461 | + .map(fieldName -> requireField(fieldName, fieldNames)) |
| 462 | + .forEach(sequenceGroupFieldIndexs::add); |
458 | 463 | String[] sequenceFieldNames = |
459 | 464 | k.substring( |
460 | 465 | FIELDS_PREFIX.length() + 1, |
@@ -492,8 +497,33 @@ private static void validateSequenceGroup(TableSchema schema, CoreOptions option |
492 | 497 | Set<String> group = fields2Group.computeIfAbsent(field, p -> new HashSet<>()); |
493 | 498 | group.addAll(sequenceFieldsList); |
494 | 499 | } |
| 500 | + |
| 501 | + // add self |
| 502 | + Arrays.stream(sequenceFieldNames) |
| 503 | + .mapToInt(fieldName -> requireField(fieldName, fieldNames)) |
| 504 | + .forEach(sequenceGroupFieldIndexs::add); |
495 | 505 | } |
496 | 506 | } |
| 507 | + |
| 508 | + if (options.mergeEngine() == MergeEngine.PARTIAL_UPDATE) { |
| 509 | + for (String fieldName : fieldNames) { |
| 510 | + String aggFunc = options.fieldAggFunc(fieldName); |
| 511 | + String aggFuncName = aggFunc == null ? options.fieldsDefaultFunc() : aggFunc; |
| 512 | + if (schema.primaryKeys().contains(fieldName)) { |
| 513 | + continue; |
| 514 | + } |
| 515 | + if (aggFuncName != null) { |
| 516 | + // last_non_null_value doesn't require sequence group |
| 517 | + checkArgument( |
| 518 | + aggFuncName.equals(FieldLastNonNullValueAggFactory.NAME) |
| 519 | + || sequenceGroupFieldIndexs.contains( |
| 520 | + fieldNames.indexOf(fieldName)), |
| 521 | + "Must use sequence group for aggregation functions but not found for field %s.", |
| 522 | + fieldName); |
| 523 | + } |
| 524 | + } |
| 525 | + } |
| 526 | + |
497 | 527 | Set<String> illegalGroup = |
498 | 528 | fields2Group.values().stream() |
499 | 529 | .flatMap(Collection::stream) |
@@ -689,6 +719,15 @@ private static void validateIncrementalClustering(TableSchema schema, CoreOption |
689 | 719 | } |
690 | 720 | } |
691 | 721 |
|
| 722 | + private static int requireField(String fieldName, List<String> fieldNames) { |
| 723 | + int field = fieldNames.indexOf(fieldName); |
| 724 | + if (field == -1) { |
| 725 | + throw new IllegalArgumentException( |
| 726 | + String.format("Field %s can not be found in table schema.", fieldName)); |
| 727 | + } |
| 728 | + return field; |
| 729 | + } |
| 730 | + |
692 | 731 | public static void validateChainTable(TableSchema schema, CoreOptions options) { |
693 | 732 | if (options.isChainTable()) { |
694 | 733 | boolean isPrimaryTbl = schema.primaryKeys() != null && !schema.primaryKeys().isEmpty(); |
|
0 commit comments