-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[SPARK-30192][SQL] support column position in DS v2 #26817
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,11 +17,12 @@ | |
|
|
||
| package org.apache.spark.sql.connector.catalog; | ||
|
|
||
| import org.apache.spark.annotation.Experimental; | ||
| import org.apache.spark.sql.types.DataType; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.Objects; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| import org.apache.spark.annotation.Experimental; | ||
| import org.apache.spark.sql.types.DataType; | ||
|
|
||
| /** | ||
| * TableChange subclasses represent requested changes to a table. These are passed to | ||
|
|
@@ -76,7 +77,7 @@ static TableChange removeProperty(String property) { | |
| * @return a TableChange for the addition | ||
| */ | ||
| static TableChange addColumn(String[] fieldNames, DataType dataType) { | ||
| return new AddColumn(fieldNames, dataType, true, null); | ||
| return new AddColumn(fieldNames, dataType, true, null, null); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -92,7 +93,7 @@ static TableChange addColumn(String[] fieldNames, DataType dataType) { | |
| * @return a TableChange for the addition | ||
| */ | ||
| static TableChange addColumn(String[] fieldNames, DataType dataType, boolean isNullable) { | ||
| return new AddColumn(fieldNames, dataType, isNullable, null); | ||
| return new AddColumn(fieldNames, dataType, isNullable, null, null); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -113,7 +114,30 @@ static TableChange addColumn( | |
| DataType dataType, | ||
| boolean isNullable, | ||
| String comment) { | ||
| return new AddColumn(fieldNames, dataType, isNullable, comment); | ||
| return new AddColumn(fieldNames, dataType, isNullable, comment, null); | ||
| } | ||
|
|
||
| /** | ||
| * Create a TableChange for adding a column. | ||
| * <p> | ||
| * If the field already exists, the change will result in an {@link IllegalArgumentException}. | ||
| * If the new field is nested and its parent does not exist or is not a struct, the change will | ||
| * result in an {@link IllegalArgumentException}. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. quick nit. I noticed that the error was wrapped in a SparkException when running
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doc is for catalog implementations. They should throw |
||
| * | ||
| * @param fieldNames field names of the new column | ||
| * @param dataType the new column's data type | ||
| * @param isNullable whether the new column can contain null | ||
| * @param comment the new field's comment string | ||
| * @param position the new columns's position | ||
| * @return a TableChange for the addition | ||
| */ | ||
| static TableChange addColumn( | ||
| String[] fieldNames, | ||
| DataType dataType, | ||
| boolean isNullable, | ||
| String comment, | ||
| ColumnPosition position) { | ||
| return new AddColumn(fieldNames, dataType, isNullable, comment, position); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -180,6 +204,21 @@ static TableChange updateColumnComment(String[] fieldNames, String newComment) { | |
| return new UpdateColumnComment(fieldNames, newComment); | ||
| } | ||
|
|
||
| /** | ||
| * Create a TableChange for updating the position of a field. | ||
| * <p> | ||
| * The name is used to find the field to update. | ||
| * <p> | ||
| * If the field does not exist, the change will result in an {@link IllegalArgumentException}. | ||
| * | ||
| * @param fieldNames field names of the column to update | ||
| * @param newPosition the new position | ||
| * @return a TableChange for the update | ||
| */ | ||
| static TableChange updateColumnPosition(String[] fieldNames, ColumnPosition newPosition) { | ||
| return new UpdateColumnPosition(fieldNames, newPosition); | ||
| } | ||
|
|
||
| /** | ||
| * Create a TableChange for deleting a field. | ||
| * <p> | ||
|
|
@@ -259,6 +298,69 @@ public int hashCode() { | |
| } | ||
| } | ||
|
|
||
| interface ColumnPosition { | ||
|
|
||
| static ColumnPosition first() { | ||
| return First.SINGLETON; | ||
| } | ||
|
|
||
| static ColumnPosition after(String column) { | ||
| return new After(column); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Column position FIRST means the specified column should be the first column. | ||
| * Note that, the specified column may be a nested field, and then FIRST means this field should | ||
| * be the first one within the struct. | ||
| */ | ||
| final class First implements ColumnPosition { | ||
| private static final First SINGLETON = new First(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| private First() {} | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "FIRST"; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Column position AFTER means the specified column should be put after the given `column`. | ||
| * Note that, the specified column may be a nested field, and then the given `column` refers to | ||
| * a field in the same struct. | ||
| */ | ||
| final class After implements ColumnPosition { | ||
| private final String column; | ||
|
|
||
| private After(String column) { | ||
| assert column != null; | ||
| this.column = column; | ||
| } | ||
|
|
||
| public String column() { | ||
| return column; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "AFTER " + column; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| After after = (After) o; | ||
| return column.equals(after.column); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(column); | ||
| } | ||
| } | ||
|
|
||
| interface ColumnChange extends TableChange { | ||
| String[] fieldNames(); | ||
| } | ||
|
|
@@ -275,12 +377,19 @@ final class AddColumn implements ColumnChange { | |
| private final DataType dataType; | ||
| private final boolean isNullable; | ||
| private final String comment; | ||
|
|
||
| private AddColumn(String[] fieldNames, DataType dataType, boolean isNullable, String comment) { | ||
| private final ColumnPosition position; | ||
|
|
||
| private AddColumn( | ||
| String[] fieldNames, | ||
| DataType dataType, | ||
| boolean isNullable, | ||
| String comment, | ||
| ColumnPosition position) { | ||
| this.fieldNames = fieldNames; | ||
| this.dataType = dataType; | ||
| this.isNullable = isNullable; | ||
| this.comment = comment; | ||
| this.position = position; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -296,10 +405,16 @@ public boolean isNullable() { | |
| return isNullable; | ||
| } | ||
|
|
||
| @Nullable | ||
| public String comment() { | ||
| return comment; | ||
| } | ||
|
|
||
| @Nullable | ||
| public ColumnPosition position() { | ||
| return position; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
|
|
@@ -308,12 +423,13 @@ public boolean equals(Object o) { | |
| return isNullable == addColumn.isNullable && | ||
| Arrays.equals(fieldNames, addColumn.fieldNames) && | ||
| dataType.equals(addColumn.dataType) && | ||
| comment.equals(addColumn.comment); | ||
| Objects.equals(comment, addColumn.comment) && | ||
| Objects.equals(position, addColumn.position); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| int result = Objects.hash(dataType, isNullable, comment); | ||
| int result = Objects.hash(dataType, isNullable, comment, position); | ||
| result = 31 * result + Arrays.hashCode(fieldNames); | ||
| return result; | ||
| } | ||
|
|
@@ -453,6 +569,48 @@ public int hashCode() { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * A TableChange to update the position of a field. | ||
| * <p> | ||
| * The field names are used to find the field to update. | ||
| * <p> | ||
| * If the field does not exist, the change must result in an {@link IllegalArgumentException}. | ||
| */ | ||
| final class UpdateColumnPosition implements ColumnChange { | ||
| private final String[] fieldNames; | ||
| private final ColumnPosition position; | ||
|
|
||
| private UpdateColumnPosition(String[] fieldNames, ColumnPosition position) { | ||
| this.fieldNames = fieldNames; | ||
| this.position = position; | ||
| } | ||
|
|
||
| @Override | ||
| public String[] fieldNames() { | ||
| return fieldNames; | ||
| } | ||
|
|
||
| public ColumnPosition position() { | ||
| return position; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| UpdateColumnPosition that = (UpdateColumnPosition) o; | ||
| return Arrays.equals(fieldNames, that.fieldNames) && | ||
| position.equals(that.position); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| int result = Objects.hash(position); | ||
| result = 31 * result + Arrays.hashCode(fieldNames); | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * A TableChange to delete a field. | ||
| * <p> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this causing validation to fail? I think we generally want to avoid changes like this unless they are enforced by a linter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not enforced by the linter but we do require it in the style guide.