|
59 | 59 | import org.apache.iceberg.exceptions.NoSuchNamespaceException; |
60 | 60 | import org.apache.iceberg.exceptions.NoSuchTableException; |
61 | 61 | import org.apache.iceberg.exceptions.NoSuchViewException; |
| 62 | +import org.apache.iceberg.exceptions.RESTException; |
62 | 63 | import org.apache.iceberg.hadoop.Configurable; |
63 | 64 | import org.apache.iceberg.io.CloseableGroup; |
64 | 65 | import org.apache.iceberg.io.FileIO; |
@@ -678,8 +679,15 @@ public Transaction createTransaction() { |
678 | 679 |
|
679 | 680 | @Override |
680 | 681 | public Transaction replaceTransaction() { |
681 | | - if (viewExists(context, ident)) { |
682 | | - throw new AlreadyExistsException("View with same name already exists: %s", ident); |
| 682 | + try { |
| 683 | + if (viewExists(context, ident)) { |
| 684 | + throw new AlreadyExistsException("View with same name already exists: %s", ident); |
| 685 | + } |
| 686 | + } catch (RESTException | UnsupportedOperationException e) { |
| 687 | + // don't fail if the server doesn't support views, which could be due to: |
| 688 | + // 1. server or backing catalog doesn't support views |
| 689 | + // 2. newer client talks to an older server that doesn't support views |
| 690 | + LOG.debug("Failed to check whether view {} exists", ident, e); |
683 | 691 | } |
684 | 692 |
|
685 | 693 | LoadTableResponse response = loadInternal(context, ident, snapshotMode); |
@@ -974,12 +982,22 @@ public List<TableIdentifier> listViews(SessionContext context, Namespace namespa |
974 | 982 | public View loadView(SessionContext context, TableIdentifier identifier) { |
975 | 983 | checkViewIdentifierIsValid(identifier); |
976 | 984 |
|
977 | | - LoadViewResponse response = |
978 | | - client.get( |
979 | | - paths.view(identifier), |
980 | | - LoadViewResponse.class, |
981 | | - headers(context), |
982 | | - ErrorHandlers.viewErrorHandler()); |
| 985 | + LoadViewResponse response; |
| 986 | + try { |
| 987 | + response = |
| 988 | + client.get( |
| 989 | + paths.view(identifier), |
| 990 | + LoadViewResponse.class, |
| 991 | + headers(context), |
| 992 | + ErrorHandlers.viewErrorHandler()); |
| 993 | + } catch (UnsupportedOperationException | RESTException e) { |
| 994 | + // Normally, copying an exception message is a bad practice but engines may show just the |
| 995 | + // message and suppress the exception cause when the view does not exist. Since 401 and 403 |
| 996 | + // responses can trigger this case, including the message increases the chances that the "Not |
| 997 | + // authorized" or "Forbidden" message is preserved and shown. |
| 998 | + throw new NoSuchViewException( |
| 999 | + e, "Unable to load view %s.%s: %s", name(), identifier, e.getMessage()); |
| 1000 | + } |
983 | 1001 |
|
984 | 1002 | AuthSession session = tableSession(response.config(), session(context)); |
985 | 1003 | ViewMetadata metadata = response.metadata(); |
|
0 commit comments