Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,11 @@ public void executeOperation(org.apache.hadoop.hive.ql.metadata.Table hmsTable,
case REWRITE_MANIFESTS:
IcebergTableUtil.rewriteManifests(icebergTable);
break;
case ANCESTORS_OF:
AlterTableExecuteSpec.AncestorsOfSpec ancestorsOfSpec =
(AlterTableExecuteSpec.AncestorsOfSpec) executeSpec.getOperationParams();
IcebergTableUtil.printAncestorsOf(icebergTable, ancestorsOfSpec.snapshotId());
break;
case DELETE_METADATA:
AlterTableExecuteSpec.DeleteMetadataSpec deleteMetadataSpec =
(AlterTableExecuteSpec.DeleteMetadataSpec) executeSpec.getOperationParams();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -999,4 +999,43 @@
properties -> IcebergTableUtil.formatVersion(tableProperties) >= 3 &&
FileFormat.PARQUET == IcebergTableUtil.defaultFileFormat(properties::getOrDefault)).isPresent();
}

/**
* Returns the ancestors of a given Iceberg snapshot. If snapshotId is null, it defaults to the
* current snapshot of the table.
*/
public static Iterable<Snapshot> getAncestorsOf(Table table, Long snapshotId) {
long targetSnapshotId = snapshotId != null ? snapshotId : table.currentSnapshot().snapshotId();
return SnapshotUtil.ancestorsOf(targetSnapshotId, table::snapshot);
}

/**
* Prints the ancestors of a given Iceberg snapshot to the Hive console. If snapshotId is null, it
* defaults to the current snapshot of the table.
*/
public static void printAncestorsOf(Table table, Long snapshotId) {
long targetSnapshotId = snapshotId != null ? snapshotId : table.currentSnapshot().snapshotId();
Iterable<Snapshot> ancestors = getAncestorsOf(table, snapshotId);
SessionState.LogHelper console = SessionState.getConsole();
if (console != null) {
// A width of 25 is used because it fits the column headers. It also safely fits the data,
// since a 64-bit long (used for IDs and timestamps) has a maximum of 19 digits.
console.printInfo("+---------------------------+---------------------------+");

Check failure on line 1023 in iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/IcebergTableUtil.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "+---------------------------+---------------------------+" 3 times.

See more on https://sonarcloud.io/project/issues?id=apache_hive&issues=AZ_Y2lX64OfOpyy8fZbG&open=AZ_Y2lX64OfOpyy8fZbG&pullRequest=6681
console.printInfo(
String.format(
"| %s | %s |",
StringUtils.center("snapshot_id", 25), StringUtils.center("timestamp_ms", 25)));
console.printInfo("+---------------------------+---------------------------+");
for (Snapshot snapshot : ancestors) {
console.printInfo(
String.format("| %-25s | %-25s |", snapshot.snapshotId(), snapshot.timestampMillis()));
}
console.printInfo("+---------------------------+---------------------------+");
} else {
LOG.info("Ancestors of snapshot {}:", targetSnapshotId);
for (Snapshot snapshot : ancestors) {
LOG.info("{} - {}", snapshot.snapshotId(), snapshot.timestampMillis());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,45 @@
icebergTable.refresh();
return icebergTable.currentSnapshot().allManifests(icebergTable.io()).size();
}
@Test
public void testAncestorsOf() throws Exception {

Check warning on line 242 in iceberg/iceberg-handler/src/test/java/org/apache/iceberg/mr/hive/TestHiveIcebergSnapshotOperations.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the declaration of thrown exception 'java.lang.Exception', as it cannot be thrown from method's body.

See more on https://sonarcloud.io/project/issues?id=apache_hive&issues=AZ_Y2laN4OfOpyy8fZbH&open=AZ_Y2laN4OfOpyy8fZbH&pullRequest=6681
TableIdentifier identifier = TableIdentifier.of("default", "testAncestorsOf");
shell.executeStatement(
String.format(
"CREATE EXTERNAL TABLE %s (id INT) STORED BY iceberg %s %s",
identifier.name(),
testTables.locationForCreateTableSQL(identifier),
testTables.propertiesForCreateTableSQL(ImmutableMap.of())));

// Create 3 snapshots
shell.executeStatement(String.format("INSERT INTO TABLE %s VALUES(1)", identifier.name()));
shell.executeStatement(String.format("INSERT INTO TABLE %s VALUES(2)", identifier.name()));
shell.executeStatement(String.format("INSERT INTO TABLE %s VALUES(3)", identifier.name()));

org.apache.iceberg.Table icebergTable = testTables.loadTable(identifier);
icebergTable.refresh();

// 1. Positive Test: The command should execute successfully without errors
shell.executeStatement(String.format("ALTER TABLE %s EXECUTE ANCESTORS_OF", identifier.name()));

// 2. Positive Test: Run with a specific valid snapshot ID
long currentSnapshotId = icebergTable.currentSnapshot().snapshotId();
shell.executeStatement(
String.format(
"ALTER TABLE %s EXECUTE ANCESTORS_OF(%d)", identifier.name(), currentSnapshotId));

// 3. Negative Test: Run with a completely fake/invalid snapshot ID
long fakeSnapshotId = 99999999999999999L;
try {
shell.executeStatement(
String.format(
"ALTER TABLE %s EXECUTE ANCESTORS_OF(%d)", identifier.name(), fakeSnapshotId));
Assert.fail("Expected an exception to be thrown for an invalid snapshot ID");
} catch (Exception e) {
Assert.assertTrue(
"Exception message should indicate failure to find snapshot",
e.getMessage().contains("Cannot find snapshot") ||
e.getMessage().contains("Cannot find"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ alterStatementSuffixExecute
-> ^(TOK_ALTERTABLE_EXECUTE KW_EXPIRE_SNAPSHOTS $expireParam?)
| KW_EXECUTE KW_REWRITE_MANIFESTS
-> ^(TOK_ALTERTABLE_EXECUTE KW_REWRITE_MANIFESTS)
| KW_EXECUTE KW_ANCESTORS_OF (LPAREN (snapshotParam=expression) RPAREN)?
-> ^(TOK_ALTERTABLE_EXECUTE KW_ANCESTORS_OF $snapshotParam?)
| KW_EXECUTE KW_SET_CURRENT_SNAPSHOT LPAREN (snapshotParam=expression) RPAREN
-> ^(TOK_ALTERTABLE_EXECUTE KW_SET_CURRENT_SNAPSHOT $snapshotParam)
| KW_EXECUTE KW_FAST_FORWARD sourceBranch=StringLiteral (targetBranch=StringLiteral)?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ KW_SYSTEM_TIME: 'SYSTEM_TIME';
KW_SYSTEM_VERSION: 'SYSTEM_VERSION';
KW_EXPIRE_SNAPSHOTS: 'EXPIRE_SNAPSHOTS';
KW_REWRITE_MANIFESTS: 'REWRITE_MANIFESTS';
KW_ANCESTORS_OF: 'ANCESTORS_OF';
KW_SET_CURRENT_SNAPSHOT: 'SET_CURRENT_SNAPSHOT';
KW_BRANCH: 'BRANCH';
KW_SNAPSHOTS: 'SNAPSHOTS';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,7 @@ nonReserved
| KW_SYSTEM_TIME | KW_SYSTEM_VERSION
| KW_EXPIRE_SNAPSHOTS
| KW_REWRITE_MANIFESTS
| KW_ANCESTORS_OF
| KW_SET_CURRENT_SNAPSHOT
| KW_BRANCH | KW_SNAPSHOTS | KW_RETAIN | KW_RETENTION
| KW_TAG
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import static org.apache.hadoop.hive.ql.parse.AlterTableExecuteSpec.ExecuteOperationType.FAST_FORWARD;
import static org.apache.hadoop.hive.ql.parse.AlterTableExecuteSpec.ExecuteOperationType.ROLLBACK;
import static org.apache.hadoop.hive.ql.parse.AlterTableExecuteSpec.ExecuteOperationType.SET_CURRENT_SNAPSHOT;
import static org.apache.hadoop.hive.ql.parse.AlterTableExecuteSpec.ExecuteOperationType.ANCESTORS_OF;
import static org.apache.hadoop.hive.ql.parse.AlterTableExecuteSpec.RollbackSpec.RollbackType.TIME;
import static org.apache.hadoop.hive.ql.parse.AlterTableExecuteSpec.RollbackSpec.RollbackType.VERSION;
import static org.apache.hadoop.hive.ql.parse.HiveLexer.KW_RETAIN;
Expand Down Expand Up @@ -106,7 +107,10 @@
case HiveParser.KW_REWRITE_MANIFESTS:
desc = new AlterTableExecuteDesc(tableName, partitionSpec,
new AlterTableExecuteSpec(AlterTableExecuteSpec.ExecuteOperationType.REWRITE_MANIFESTS, null));
break;

Check warning on line 110 in ql/src/java/org/apache/hadoop/hive/ql/ddl/table/execute/AlterTableExecuteAnalyzer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'block' child has incorrect indentation level 8, expected level should be 6.

See more on https://sonarcloud.io/project/issues?id=apache_hive&issues=AZ_Y2lA-4OfOpyy8fZbD&open=AZ_Y2lA-4OfOpyy8fZbD&pullRequest=6681
case HiveParser.KW_ANCESTORS_OF:

Check warning on line 111 in ql/src/java/org/apache/hadoop/hive/ql/ddl/table/execute/AlterTableExecuteAnalyzer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'case' child has incorrect indentation level 6, expected level should be 4.

See more on https://sonarcloud.io/project/issues?id=apache_hive&issues=AZ_Y2lA-4OfOpyy8fZbE&open=AZ_Y2lA-4OfOpyy8fZbE&pullRequest=6681
desc = getAncestorsOfDesc(tableName, partitionSpec, command);

Check warning on line 112 in ql/src/java/org/apache/hadoop/hive/ql/ddl/table/execute/AlterTableExecuteAnalyzer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'block' child has incorrect indentation level 8, expected level should be 6.

See more on https://sonarcloud.io/project/issues?id=apache_hive&issues=AZ_Y2lA-4OfOpyy8fZbF&open=AZ_Y2lA-4OfOpyy8fZbF&pullRequest=6681
break;
}

rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), desc)));
Expand Down Expand Up @@ -216,6 +220,20 @@
return new AlterTableExecuteDesc(tableName, partitionSpec, spec);
}

private AlterTableExecuteDesc getAncestorsOfDesc(
TableName tableName, Map<String, String> partitionSpec, ASTNode command)
throws SemanticException {
Long snapshotId = null;
if (command.getChildCount() == 2) {
ASTNode childNode = (ASTNode) command.getChild(1);
snapshotId = Long.parseLong(childNode.getText());
}
AlterTableExecuteSpec spec =
new AlterTableExecuteSpec(
ANCESTORS_OF, new AlterTableExecuteSpec.AncestorsOfSpec(snapshotId));
return new AlterTableExecuteDesc(tableName, partitionSpec, spec);
}

private long getTimeStampMillis(ASTNode childNode) {
String childNodeText = PlanUtils.stripQuotes(childNode.getText());
ZoneId timeZone = conf.getLocalTimeZone();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.hadoop.hive.ql.io.sarg.SearchArgument;

import java.util.Arrays;
import org.jetbrains.annotations.NotNull;

/**
* Execute operation specification. It stores the type of the operation and its parameters.
Expand All @@ -44,7 +45,8 @@ public enum ExecuteOperationType {
CHERRY_PICK,
DELETE_METADATA,
DELETE_ORPHAN_FILES,
REWRITE_MANIFESTS;
REWRITE_MANIFESTS,
ANCESTORS_OF;
}

private final ExecuteOperationType operationType;
Expand Down Expand Up @@ -257,6 +259,21 @@ public String toString() {
}
}

/**
* Value object class, that stores the ancestors of operation specific parameters.
*
* <ul>
* <li>snapshotId: the snapshotId to find ancestors of (optional)
* </ul>
*/
public record AncestorsOfSpec(Long snapshotId) {

@Override
public @NotNull String toString() {
return MoreObjects.toStringHelper(this).add("snapshotId", snapshotId).toString();
}
}

public static class DeleteMetadataSpec {
private final String branchName;
private final SearchArgument sarg;
Expand Down
Loading