Skip to content

Commit

Permalink
[core] Introduce View Support to HiveCatalog
Browse files Browse the repository at this point in the history
  • Loading branch information
JingsongLi committed Oct 28, 2024
1 parent 347ae21 commit 9fd50c7
Show file tree
Hide file tree
Showing 10 changed files with 629 additions and 28 deletions.
106 changes: 106 additions & 0 deletions paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.paimon.schema.Schema;
import org.apache.paimon.schema.SchemaChange;
import org.apache.paimon.table.Table;
import org.apache.paimon.view.View;

import java.io.Serializable;
import java.util.Arrays;
Expand Down Expand Up @@ -299,6 +300,69 @@ default void alterTable(Identifier identifier, SchemaChange change, boolean igno
alterTable(identifier, Collections.singletonList(change), ignoreIfNotExists);
}

/**
* Check if a view exists in this catalog.
*
* @param identifier Path of the view
* @return true if the given view exists in the catalog false otherwise
*/
default boolean viewExists(Identifier identifier) {
try {
return getView(identifier) != null;
} catch (ViewNotExistException e) {
return false;
}
}

/**
* Return a {@link View} identified by the given {@link Identifier}.
*
* @param identifier Path of the view
* @return The requested view
* @throws ViewNotExistException if the target does not exist
*/
default View getView(Identifier identifier) throws ViewNotExistException {
throw new ViewNotExistException(identifier);
}

/**
* Drop a view.
*
* @param identifier Path of the view to be dropped
* @param ignoreIfNotExists Flag to specify behavior when the view does not exist: if set to
* false, throw an exception, if set to true, do nothing.
* @throws ViewNotExistException if the view does not exist
*/
default void dropView(Identifier identifier, boolean ignoreIfNotExists)
throws ViewNotExistException {
throw new UnsupportedOperationException();
}

/**
* Create a new view.
*
* @param identifier path of the view to be created
* @param view the view definition
* @param ignoreIfExists flag to specify behavior when a view already exists at the given path:
* if set to false, it throws a ViewAlreadyExistException, if set to true, do nothing.
* @throws ViewAlreadyExistException if view already exists and ignoreIfExists is false
* @throws DatabaseNotExistException if the database in identifier doesn't exist
*/
default void createView(Identifier identifier, View view, boolean ignoreIfExists)
throws ViewAlreadyExistException, DatabaseNotExistException {
throw new UnsupportedOperationException();
}

/**
* Get names of all views under this database. An empty list is returned if none exists.
*
* @return a list of the names of all views in this database
* @throws DatabaseNotExistException if the database does not exist
*/
default List<String> listViews(String databaseName) throws DatabaseNotExistException {
return Collections.emptyList();
}

/** Return a boolean that indicates whether this catalog allow upper case. */
boolean allowUpperCase();

Expand Down Expand Up @@ -532,6 +596,48 @@ public String column() {
}
}

/** Exception for trying to create a view that already exists. */
class ViewAlreadyExistException extends Exception {

private static final String MSG = "View %s already exists.";

private final Identifier identifier;

public ViewAlreadyExistException(Identifier identifier) {
this(identifier, null);
}

public ViewAlreadyExistException(Identifier identifier, Throwable cause) {
super(String.format(MSG, identifier.getFullName()), cause);
this.identifier = identifier;
}

public Identifier identifier() {
return identifier;
}
}

/** Exception for trying to operate on a view that doesn't exist. */
class ViewNotExistException extends Exception {

private static final String MSG = "View %s does not exist.";

private final Identifier identifier;

public ViewNotExistException(Identifier identifier) {
this(identifier, null);
}

public ViewNotExistException(Identifier identifier, Throwable cause) {
super(String.format(MSG, identifier.getFullName()), cause);
this.identifier = identifier;
}

public Identifier identifier() {
return identifier;
}
}

/** Loader of {@link Catalog}. */
@FunctionalInterface
interface Loader extends Serializable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.paimon.schema.Schema;
import org.apache.paimon.schema.SchemaChange;
import org.apache.paimon.table.Table;
import org.apache.paimon.view.View;

import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -135,6 +136,38 @@ public Table getTable(Identifier identifier) throws TableNotExistException {
return wrapped.getTable(identifier);
}

@Override
public boolean tableExists(Identifier identifier) {
return wrapped.tableExists(identifier);
}

@Override
public boolean viewExists(Identifier identifier) {
return wrapped.viewExists(identifier);
}

@Override
public View getView(Identifier identifier) throws ViewNotExistException {
return wrapped.getView(identifier);
}

@Override
public void dropView(Identifier identifier, boolean ignoreIfNotExists)
throws ViewNotExistException {
wrapped.dropView(identifier, ignoreIfNotExists);
}

@Override
public void createView(Identifier identifier, View view, boolean ignoreIfExists)
throws ViewAlreadyExistException, DatabaseNotExistException {
wrapped.createView(identifier, view, ignoreIfExists);
}

@Override
public List<String> listViews(String databaseName) throws DatabaseNotExistException {
return wrapped.listViews(databaseName);
}

@Override
public Path getTableLocation(Identifier identifier) {
return wrapped.getTableLocation(identifier);
Expand Down
49 changes: 49 additions & 0 deletions paimon-core/src/main/java/org/apache/paimon/view/View.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.paimon.view;

import org.apache.paimon.types.RowType;

import java.util.Map;
import java.util.Optional;

/** Interface for view definition. */
public interface View {

/** A name to identify this view. */
String name();

/** Full name (including database) to identify this view. */
String fullName();

/** Returns the row type of this view. */
RowType rowType();

/** Returns the view representation. */
String query();

/** Optional comment of this view. */
Optional<String> comment();

/** Options of this view. */
Map<String, String> options();

/** Copy this view with adding dynamic options. */
View copy(Map<String, String> dynamicOptions);
}
110 changes: 110 additions & 0 deletions paimon-core/src/main/java/org/apache/paimon/view/ViewImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.paimon.view;

import org.apache.paimon.catalog.Identifier;
import org.apache.paimon.types.RowType;

import javax.annotation.Nullable;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/** Implementation of {@link View}. */
public class ViewImpl implements View {

private final Identifier identifier;
private final RowType rowType;
private final String query;
@Nullable private final String comment;
private final Map<String, String> options;

public ViewImpl(
Identifier identifier,
RowType rowType,
String query,
@Nullable String comment,
Map<String, String> options) {
this.identifier = identifier;
this.rowType = rowType;
this.query = query;
this.comment = comment;
this.options = options;
}

@Override
public String name() {
return identifier.getObjectName();
}

@Override
public String fullName() {
return identifier.getFullName();
}

@Override
public RowType rowType() {
return rowType;
}

@Override
public String query() {
return query;
}

@Override
public Optional<String> comment() {
return Optional.ofNullable(comment);
}

@Override
public Map<String, String> options() {
return options;
}

@Override
public View copy(Map<String, String> dynamicOptions) {
Map<String, String> newOptions = new HashMap<>(options);
newOptions.putAll(dynamicOptions);
return new ViewImpl(identifier, rowType, query, comment, newOptions);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ViewImpl view = (ViewImpl) o;
return Objects.equals(identifier, view.identifier)
&& Objects.equals(rowType, view.rowType)
&& Objects.equals(query, view.query)
&& Objects.equals(comment, view.comment)
&& Objects.equals(options, view.options);
}

@Override
public int hashCode() {
return Objects.hash(identifier, rowType, query, comment, options);
}
}
Loading

0 comments on commit 9fd50c7

Please sign in to comment.