Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one or more
0003  * contributor license agreements.  See the NOTICE file distributed with
0004  * this work for additional information regarding copyright ownership.
0005  * The ASF licenses this file to You under the Apache License, Version 2.0
0006  * (the "License"); you may not use this file except in compliance with
0007  * the License.  You may obtain a copy of the License at
0008  *
0009  *    http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  */
0017 
0018 package org.apache.spark.sql.connector.catalog;
0019 
0020 import java.util.Arrays;
0021 import java.util.Objects;
0022 import javax.annotation.Nullable;
0023 
0024 import org.apache.spark.annotation.Evolving;
0025 import org.apache.spark.sql.types.DataType;
0026 
0027 /**
0028  * TableChange subclasses represent requested changes to a table. These are passed to
0029  * {@link TableCatalog#alterTable}. For example,
0030  * <pre>
0031  *   import TableChange._
0032  *   val catalog = Catalogs.load(name)
0033  *   catalog.asTableCatalog.alterTable(ident,
0034  *       addColumn("x", IntegerType),
0035  *       renameColumn("a", "b"),
0036  *       deleteColumn("c")
0037  *     )
0038  * </pre>
0039  *
0040  * @since 3.0.0
0041  */
0042 @Evolving
0043 public interface TableChange {
0044 
0045   /**
0046    * Create a TableChange for setting a table property.
0047    * <p>
0048    * If the property already exists, it will be replaced with the new value.
0049    *
0050    * @param property the property name
0051    * @param value the new property value
0052    * @return a TableChange for the addition
0053    */
0054   static TableChange setProperty(String property, String value) {
0055     return new SetProperty(property, value);
0056   }
0057 
0058   /**
0059    * Create a TableChange for removing a table property.
0060    * <p>
0061    * If the property does not exist, the change will succeed.
0062    *
0063    * @param property the property name
0064    * @return a TableChange for the addition
0065    */
0066   static TableChange removeProperty(String property) {
0067     return new RemoveProperty(property);
0068   }
0069 
0070   /**
0071    * Create a TableChange for adding an optional column.
0072    * <p>
0073    * If the field already exists, the change will result in an {@link IllegalArgumentException}.
0074    * If the new field is nested and its parent does not exist or is not a struct, the change will
0075    * result in an {@link IllegalArgumentException}.
0076    *
0077    * @param fieldNames field names of the new column
0078    * @param dataType the new column's data type
0079    * @return a TableChange for the addition
0080    */
0081   static TableChange addColumn(String[] fieldNames, DataType dataType) {
0082     return new AddColumn(fieldNames, dataType, true, null, null);
0083   }
0084 
0085   /**
0086    * Create a TableChange for adding a column.
0087    * <p>
0088    * If the field already exists, the change will result in an {@link IllegalArgumentException}.
0089    * If the new field is nested and its parent does not exist or is not a struct, the change will
0090    * result in an {@link IllegalArgumentException}.
0091    *
0092    * @param fieldNames field names of the new column
0093    * @param dataType the new column's data type
0094    * @param isNullable whether the new column can contain null
0095    * @return a TableChange for the addition
0096    */
0097   static TableChange addColumn(String[] fieldNames, DataType dataType, boolean isNullable) {
0098     return new AddColumn(fieldNames, dataType, isNullable, null, null);
0099   }
0100 
0101   /**
0102    * Create a TableChange for adding a column.
0103    * <p>
0104    * If the field already exists, the change will result in an {@link IllegalArgumentException}.
0105    * If the new field is nested and its parent does not exist or is not a struct, the change will
0106    * result in an {@link IllegalArgumentException}.
0107    *
0108    * @param fieldNames field names of the new column
0109    * @param dataType the new column's data type
0110    * @param isNullable whether the new column can contain null
0111    * @param comment the new field's comment string
0112    * @return a TableChange for the addition
0113    */
0114   static TableChange addColumn(
0115       String[] fieldNames,
0116       DataType dataType,
0117       boolean isNullable,
0118       String comment) {
0119     return new AddColumn(fieldNames, dataType, isNullable, comment, null);
0120   }
0121 
0122   /**
0123    * Create a TableChange for adding a column.
0124    * <p>
0125    * If the field already exists, the change will result in an {@link IllegalArgumentException}.
0126    * If the new field is nested and its parent does not exist or is not a struct, the change will
0127    * result in an {@link IllegalArgumentException}.
0128    *
0129    * @param fieldNames field names of the new column
0130    * @param dataType the new column's data type
0131    * @param isNullable whether the new column can contain null
0132    * @param comment the new field's comment string
0133    * @param position the new columns's position
0134    * @return a TableChange for the addition
0135    */
0136   static TableChange addColumn(
0137       String[] fieldNames,
0138       DataType dataType,
0139       boolean isNullable,
0140       String comment,
0141       ColumnPosition position) {
0142     return new AddColumn(fieldNames, dataType, isNullable, comment, position);
0143   }
0144 
0145   /**
0146    * Create a TableChange for renaming a field.
0147    * <p>
0148    * The name is used to find the field to rename. The new name will replace the leaf field name.
0149    * For example, renameColumn(["a", "b", "c"], "x") should produce column a.b.x.
0150    * <p>
0151    * If the field does not exist, the change will result in an {@link IllegalArgumentException}.
0152    *
0153    * @param fieldNames the current field names
0154    * @param newName the new name
0155    * @return a TableChange for the rename
0156    */
0157   static TableChange renameColumn(String[] fieldNames, String newName) {
0158     return new RenameColumn(fieldNames, newName);
0159   }
0160 
0161   /**
0162    * Create a TableChange for updating the type of a field that is nullable.
0163    * <p>
0164    * The field names are used to find the field to update.
0165    * <p>
0166    * If the field does not exist, the change will result in an {@link IllegalArgumentException}.
0167    *
0168    * @param fieldNames field names of the column to update
0169    * @param newDataType the new data type
0170    * @return a TableChange for the update
0171    */
0172   static TableChange updateColumnType(String[] fieldNames, DataType newDataType) {
0173     return new UpdateColumnType(fieldNames, newDataType);
0174   }
0175 
0176   /**
0177    * Create a TableChange for updating the nullability of a field.
0178    * <p>
0179    * The name is used to find the field to update.
0180    * <p>
0181    * If the field does not exist, the change will result in an {@link IllegalArgumentException}.
0182    *
0183    * @param fieldNames field names of the column to update
0184    * @param nullable the nullability
0185    * @return a TableChange for the update
0186    */
0187   static TableChange updateColumnNullability(String[] fieldNames, boolean nullable) {
0188     return new UpdateColumnNullability(fieldNames, nullable);
0189   }
0190 
0191   /**
0192    * Create a TableChange for updating the comment of a field.
0193    * <p>
0194    * The name is used to find the field to update.
0195    * <p>
0196    * If the field does not exist, the change will result in an {@link IllegalArgumentException}.
0197    *
0198    * @param fieldNames field names of the column to update
0199    * @param newComment the new comment
0200    * @return a TableChange for the update
0201    */
0202   static TableChange updateColumnComment(String[] fieldNames, String newComment) {
0203     return new UpdateColumnComment(fieldNames, newComment);
0204   }
0205 
0206   /**
0207    * Create a TableChange for updating the position of a field.
0208    * <p>
0209    * The name is used to find the field to update.
0210    * <p>
0211    * If the field does not exist, the change will result in an {@link IllegalArgumentException}.
0212    *
0213    * @param fieldNames field names of the column to update
0214    * @param newPosition the new position
0215    * @return a TableChange for the update
0216    */
0217   static TableChange updateColumnPosition(String[] fieldNames, ColumnPosition newPosition) {
0218     return new UpdateColumnPosition(fieldNames, newPosition);
0219   }
0220 
0221   /**
0222    * Create a TableChange for deleting a field.
0223    * <p>
0224    * If the field does not exist, the change will result in an {@link IllegalArgumentException}.
0225    *
0226    * @param fieldNames field names of the column to delete
0227    * @return a TableChange for the delete
0228    */
0229   static TableChange deleteColumn(String[] fieldNames) {
0230     return new DeleteColumn(fieldNames);
0231   }
0232 
0233   /**
0234    * A TableChange to set a table property.
0235    * <p>
0236    * If the property already exists, it must be replaced with the new value.
0237    */
0238   final class SetProperty implements TableChange {
0239     private final String property;
0240     private final String value;
0241 
0242     private SetProperty(String property, String value) {
0243       this.property = property;
0244       this.value = value;
0245     }
0246 
0247     public String property() {
0248       return property;
0249     }
0250 
0251     public String value() {
0252       return value;
0253     }
0254 
0255     @Override
0256     public boolean equals(Object o) {
0257       if (this == o) return true;
0258       if (o == null || getClass() != o.getClass()) return false;
0259       SetProperty that = (SetProperty) o;
0260       return property.equals(that.property) &&
0261         value.equals(that.value);
0262     }
0263 
0264     @Override
0265     public int hashCode() {
0266       return Objects.hash(property, value);
0267     }
0268   }
0269 
0270   /**
0271    * A TableChange to remove a table property.
0272    * <p>
0273    * If the property does not exist, the change should succeed.
0274    */
0275   final class RemoveProperty implements TableChange {
0276     private final String property;
0277 
0278     private RemoveProperty(String property) {
0279       this.property = property;
0280     }
0281 
0282     public String property() {
0283       return property;
0284     }
0285 
0286     @Override
0287     public boolean equals(Object o) {
0288       if (this == o) return true;
0289       if (o == null || getClass() != o.getClass()) return false;
0290       RemoveProperty that = (RemoveProperty) o;
0291       return property.equals(that.property);
0292     }
0293 
0294     @Override
0295     public int hashCode() {
0296       return Objects.hash(property);
0297     }
0298   }
0299 
0300   interface ColumnPosition {
0301 
0302     static ColumnPosition first() {
0303       return First.INSTANCE;
0304     }
0305 
0306     static ColumnPosition after(String column) {
0307       return new After(column);
0308     }
0309   }
0310 
0311   /**
0312    * Column position FIRST means the specified column should be the first column.
0313    * Note that, the specified column may be a nested field, and then FIRST means this field should
0314    * be the first one within the struct.
0315    */
0316   final class First implements ColumnPosition {
0317     private static final First INSTANCE = new First();
0318 
0319     private First() {}
0320 
0321     @Override
0322     public String toString() {
0323       return "FIRST";
0324     }
0325   }
0326 
0327   /**
0328    * Column position AFTER means the specified column should be put after the given `column`.
0329    * Note that, the specified column may be a nested field, and then the given `column` refers to
0330    * a field in the same struct.
0331    */
0332   final class After implements ColumnPosition {
0333     private final String column;
0334 
0335     private After(String column) {
0336       assert column != null;
0337       this.column = column;
0338     }
0339 
0340     public String column() {
0341       return column;
0342     }
0343 
0344     @Override
0345     public String toString() {
0346       return "AFTER " + column;
0347     }
0348 
0349     @Override
0350     public boolean equals(Object o) {
0351       if (this == o) return true;
0352       if (o == null || getClass() != o.getClass()) return false;
0353       After after = (After) o;
0354       return column.equals(after.column);
0355     }
0356 
0357     @Override
0358     public int hashCode() {
0359       return Objects.hash(column);
0360     }
0361   }
0362 
0363   interface ColumnChange extends TableChange {
0364     String[] fieldNames();
0365   }
0366 
0367   /**
0368    * A TableChange to add a field.
0369    * <p>
0370    * If the field already exists, the change must result in an {@link IllegalArgumentException}.
0371    * If the new field is nested and its parent does not exist or is not a struct, the change must
0372    * result in an {@link IllegalArgumentException}.
0373    */
0374   final class AddColumn implements ColumnChange {
0375     private final String[] fieldNames;
0376     private final DataType dataType;
0377     private final boolean isNullable;
0378     private final String comment;
0379     private final ColumnPosition position;
0380 
0381     private AddColumn(
0382         String[] fieldNames,
0383         DataType dataType,
0384         boolean isNullable,
0385         String comment,
0386         ColumnPosition position) {
0387       this.fieldNames = fieldNames;
0388       this.dataType = dataType;
0389       this.isNullable = isNullable;
0390       this.comment = comment;
0391       this.position = position;
0392     }
0393 
0394     @Override
0395     public String[] fieldNames() {
0396       return fieldNames;
0397     }
0398 
0399     public DataType dataType() {
0400       return dataType;
0401     }
0402 
0403     public boolean isNullable() {
0404       return isNullable;
0405     }
0406 
0407     @Nullable
0408     public String comment() {
0409       return comment;
0410     }
0411 
0412     @Nullable
0413     public ColumnPosition position() {
0414       return position;
0415     }
0416 
0417     @Override
0418     public boolean equals(Object o) {
0419       if (this == o) return true;
0420       if (o == null || getClass() != o.getClass()) return false;
0421       AddColumn addColumn = (AddColumn) o;
0422       return isNullable == addColumn.isNullable &&
0423         Arrays.equals(fieldNames, addColumn.fieldNames) &&
0424         dataType.equals(addColumn.dataType) &&
0425         Objects.equals(comment, addColumn.comment) &&
0426         Objects.equals(position, addColumn.position);
0427     }
0428 
0429     @Override
0430     public int hashCode() {
0431       int result = Objects.hash(dataType, isNullable, comment, position);
0432       result = 31 * result + Arrays.hashCode(fieldNames);
0433       return result;
0434     }
0435   }
0436 
0437   /**
0438    * A TableChange to rename a field.
0439    * <p>
0440    * The name is used to find the field to rename. The new name will replace the leaf field name.
0441    * For example, renameColumn("a.b.c", "x") should produce column a.b.x.
0442    * <p>
0443    * If the field does not exist, the change must result in an {@link IllegalArgumentException}.
0444    */
0445   final class RenameColumn implements ColumnChange {
0446     private final String[] fieldNames;
0447     private final String newName;
0448 
0449     private RenameColumn(String[] fieldNames, String newName) {
0450       this.fieldNames = fieldNames;
0451       this.newName = newName;
0452     }
0453 
0454     @Override
0455     public String[] fieldNames() {
0456       return fieldNames;
0457     }
0458 
0459     public String newName() {
0460       return newName;
0461     }
0462 
0463     @Override
0464     public boolean equals(Object o) {
0465       if (this == o) return true;
0466       if (o == null || getClass() != o.getClass()) return false;
0467       RenameColumn that = (RenameColumn) o;
0468       return Arrays.equals(fieldNames, that.fieldNames) &&
0469         newName.equals(that.newName);
0470     }
0471 
0472     @Override
0473     public int hashCode() {
0474       int result = Objects.hash(newName);
0475       result = 31 * result + Arrays.hashCode(fieldNames);
0476       return result;
0477     }
0478   }
0479 
0480   /**
0481    * A TableChange to update the type of a field.
0482    * <p>
0483    * The field names are used to find the field to update.
0484    * <p>
0485    * If the field does not exist, the change must result in an {@link IllegalArgumentException}.
0486    */
0487   final class UpdateColumnType implements ColumnChange {
0488     private final String[] fieldNames;
0489     private final DataType newDataType;
0490 
0491     private UpdateColumnType(String[] fieldNames, DataType newDataType) {
0492       this.fieldNames = fieldNames;
0493       this.newDataType = newDataType;
0494     }
0495 
0496     @Override
0497     public String[] fieldNames() {
0498       return fieldNames;
0499     }
0500 
0501     public DataType newDataType() {
0502       return newDataType;
0503     }
0504 
0505     @Override
0506     public boolean equals(Object o) {
0507       if (this == o) return true;
0508       if (o == null || getClass() != o.getClass()) return false;
0509       UpdateColumnType that = (UpdateColumnType) o;
0510       return Arrays.equals(fieldNames, that.fieldNames) &&
0511         newDataType.equals(that.newDataType);
0512     }
0513 
0514     @Override
0515     public int hashCode() {
0516       int result = Objects.hash(newDataType);
0517       result = 31 * result + Arrays.hashCode(fieldNames);
0518       return result;
0519     }
0520   }
0521 
0522   /**
0523    * A TableChange to update the nullability of a field.
0524    * <p>
0525    * The field names are used to find the field to update.
0526    * <p>
0527    * If the field does not exist, the change must result in an {@link IllegalArgumentException}.
0528    */
0529   final class UpdateColumnNullability implements ColumnChange {
0530     private final String[] fieldNames;
0531     private final boolean nullable;
0532 
0533     private UpdateColumnNullability(String[] fieldNames, boolean nullable) {
0534       this.fieldNames = fieldNames;
0535       this.nullable = nullable;
0536     }
0537 
0538     public String[] fieldNames() {
0539       return fieldNames;
0540     }
0541 
0542     public boolean nullable() {
0543       return nullable;
0544     }
0545 
0546     @Override
0547     public boolean equals(Object o) {
0548       if (this == o) return true;
0549       if (o == null || getClass() != o.getClass()) return false;
0550       UpdateColumnNullability that = (UpdateColumnNullability) o;
0551       return nullable == that.nullable &&
0552         Arrays.equals(fieldNames, that.fieldNames);
0553     }
0554 
0555     @Override
0556     public int hashCode() {
0557       int result = Objects.hash(nullable);
0558       result = 31 * result + Arrays.hashCode(fieldNames);
0559       return result;
0560     }
0561   }
0562 
0563   /**
0564    * A TableChange to update the comment of a field.
0565    * <p>
0566    * The field names are used to find the field to update.
0567    * <p>
0568    * If the field does not exist, the change must result in an {@link IllegalArgumentException}.
0569    */
0570   final class UpdateColumnComment implements ColumnChange {
0571     private final String[] fieldNames;
0572     private final String newComment;
0573 
0574     private UpdateColumnComment(String[] fieldNames, String newComment) {
0575       this.fieldNames = fieldNames;
0576       this.newComment = newComment;
0577     }
0578 
0579     @Override
0580     public String[] fieldNames() {
0581       return fieldNames;
0582     }
0583 
0584     public String newComment() {
0585       return newComment;
0586     }
0587 
0588     @Override
0589     public boolean equals(Object o) {
0590       if (this == o) return true;
0591       if (o == null || getClass() != o.getClass()) return false;
0592       UpdateColumnComment that = (UpdateColumnComment) o;
0593       return Arrays.equals(fieldNames, that.fieldNames) &&
0594         newComment.equals(that.newComment);
0595     }
0596 
0597     @Override
0598     public int hashCode() {
0599       int result = Objects.hash(newComment);
0600       result = 31 * result + Arrays.hashCode(fieldNames);
0601       return result;
0602     }
0603   }
0604 
0605   /**
0606    * A TableChange to update the position of a field.
0607    * <p>
0608    * The field names are used to find the field to update.
0609    * <p>
0610    * If the field does not exist, the change must result in an {@link IllegalArgumentException}.
0611    */
0612   final class UpdateColumnPosition implements ColumnChange {
0613     private final String[] fieldNames;
0614     private final ColumnPosition position;
0615 
0616     private UpdateColumnPosition(String[] fieldNames, ColumnPosition position) {
0617       this.fieldNames = fieldNames;
0618       this.position = position;
0619     }
0620 
0621     @Override
0622     public String[] fieldNames() {
0623       return fieldNames;
0624     }
0625 
0626     public ColumnPosition position() {
0627       return position;
0628     }
0629 
0630     @Override
0631     public boolean equals(Object o) {
0632       if (this == o) return true;
0633       if (o == null || getClass() != o.getClass()) return false;
0634       UpdateColumnPosition that = (UpdateColumnPosition) o;
0635       return Arrays.equals(fieldNames, that.fieldNames) &&
0636         position.equals(that.position);
0637     }
0638 
0639     @Override
0640     public int hashCode() {
0641       int result = Objects.hash(position);
0642       result = 31 * result + Arrays.hashCode(fieldNames);
0643       return result;
0644     }
0645   }
0646 
0647   /**
0648    * A TableChange to delete a field.
0649    * <p>
0650    * If the field does not exist, the change must result in an {@link IllegalArgumentException}.
0651    */
0652   final class DeleteColumn implements ColumnChange {
0653     private final String[] fieldNames;
0654 
0655     private DeleteColumn(String[] fieldNames) {
0656       this.fieldNames = fieldNames;
0657     }
0658 
0659     @Override
0660     public String[] fieldNames() {
0661       return fieldNames;
0662     }
0663 
0664     @Override
0665     public boolean equals(Object o) {
0666       if (this == o) return true;
0667       if (o == null || getClass() != o.getClass()) return false;
0668       DeleteColumn that = (DeleteColumn) o;
0669       return Arrays.equals(fieldNames, that.fieldNames);
0670     }
0671 
0672     @Override
0673     public int hashCode() {
0674       return Arrays.hashCode(fieldNames);
0675     }
0676   }
0677 
0678 }