|
| 1 | +/* |
| 2 | + * Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | + * contributor license agreements. See the NOTICE file distributed with |
| 4 | + * this work for additional information regarding copyright ownership. |
| 5 | + * The ASF licenses this file to you under the Apache License, Version 2.0 |
| 6 | + * (the "License"); you may not use this file except in compliance with |
| 7 | + * the License. You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + */ |
| 17 | +package org.apache.calcite.sql.validate; |
| 18 | + |
| 19 | +import org.apache.calcite.util.ImmutableBitSet; |
| 20 | + |
| 21 | +import com.google.common.collect.ImmutableSet; |
| 22 | + |
| 23 | +import java.util.Set; |
| 24 | + |
| 25 | +/** |
| 26 | + * Class that encapsulates filtering requirements when overloading SemanticTable. <br> |
| 27 | + * |
| 28 | + * <p>A few examples of the behavior:<br> |
| 29 | + * |
| 30 | + * <p>Table <code>t</code> has a must-filter field <code>f</code> and bypass-fields <code>b0</code> |
| 31 | + * and <code>b1</code>.<br> |
| 32 | + * SQL: <code>select f from t;</code><br> -> Errors because there's no filter on f. <br> |
| 33 | + * SQL: <code>select * from (select f from t);</code><br> -> Errors at the inner query because |
| 34 | + * there's no filter on f. <br> |
| 35 | + * SQL: <code>select f from t where f = 1;</code><br> -> Valid because there is a filter on f.<br> |
| 36 | + * SQL: <code>select * from (select f from t) where f = 1;</code><br> -> Valid because there is a |
| 37 | + * filter on f. <br> |
| 38 | + * SQL: <code>select f from t where b0 = 1;</code><br> -> Valid because there is a filter on |
| 39 | + * bypass-field b0.<br> |
| 40 | + * |
| 41 | + * <p>Some notes on remnantFilterFields.<br> |
| 42 | + * remnantFilterFields is used to identify whether the query should error |
| 43 | + * at the top level query. It is populated with the filter-field value when a filter-field is not |
| 44 | + * selected or filtered on, but a bypass-field for the table is selected. |
| 45 | + * The remnantFilterFields are no longer accessible by the enclosing query and hence can no |
| 46 | + * longer be defused by filtering on it; however, it can be defused if the bypass-field is |
| 47 | + * filtered on, hence we need to keep track of it. |
| 48 | +
|
| 49 | + * Example:<br> |
| 50 | + * Table <code>t</code> has a must-filter field <code>f</code> and bypass-fields <code>b0</code> |
| 51 | + * and <code>b1</code>.<br> |
| 52 | + * SQL: <code>select b0, b1 from t;</code><br> |
| 53 | + * |
| 54 | + * <p>This results in: <br> |
| 55 | + * filterFields:[]<br> |
| 56 | + * bypassFields:[b0, b1]<br> |
| 57 | + * remnantFilterFields: [f]<br> |
| 58 | + * -> Errors because it is a top level query and remnantFilterFields is not empty. <br> |
| 59 | + * |
| 60 | + * <p>SQL: <code>select * from (select b0, b1 from t) where b0 = 1;</code><br> |
| 61 | + * When unwrapping the inner query we get the same FilterRequirement as the previous example:<br> |
| 62 | + * filterFields:[]<br> |
| 63 | + * bypassFields:[b0, b1]<br> |
| 64 | + * remnantFilterFields: [f]<br> |
| 65 | + * When unwrapping the top level query, the filter on b0 defuses the remnantFilterField requirement |
| 66 | + * of [f] because it originated from the same table, resulting in the following: <br> |
| 67 | + * filterFields:[]<br> |
| 68 | + * bypassFields:[b0, b1]<br> |
| 69 | + * remnantFilterFields: []<br> |
| 70 | + * -> Valid because remnantFilterFields is empty now. |
| 71 | + */ |
| 72 | +final class FilterRequirement { |
| 73 | + |
| 74 | + /** The ordinals (in the row type) of the "must-filter" fields, |
| 75 | + * fields that must be filtered in a query.*/ |
| 76 | + private final ImmutableBitSet filterFields; |
| 77 | + /** The ordinals (in the row type) of the "bypass" fields, |
| 78 | + * fields that can defuse validation errors on filterFields if filtered on. */ |
| 79 | + private final ImmutableBitSet bypassFields; |
| 80 | + /** Set of filterField SqlQualifieds that have not been defused |
| 81 | + * in the current query, but can still be defused by filtering on a bypass field in the |
| 82 | + * enclosing query.*/ |
| 83 | + private final ImmutableSet<SqlQualified> remnantFilterFields; |
| 84 | + |
| 85 | + /** |
| 86 | + * Creates a <code>FilterRequirement</code>. |
| 87 | + * |
| 88 | + * @param filterFields Ordinals of the "must-filter" fields. |
| 89 | + * @param bypassFields Ordinals of the "bypass" fields. |
| 90 | + * @param remnantFilterFields Filter fields that can no longer be filtered on, |
| 91 | + * but can only be defused if a bypass field is filtered on. |
| 92 | + */ |
| 93 | + FilterRequirement(ImmutableBitSet filterFields, |
| 94 | + ImmutableBitSet bypassFields, Set<SqlQualified> remnantFilterFields) { |
| 95 | + this.filterFields = ImmutableBitSet.of(filterFields); |
| 96 | + this.bypassFields = ImmutableBitSet.of(bypassFields); |
| 97 | + this.remnantFilterFields = ImmutableSet.copyOf(remnantFilterFields); |
| 98 | + } |
| 99 | + |
| 100 | + /** Creates an empty FilterRequirement. */ |
| 101 | + FilterRequirement() { |
| 102 | + this(ImmutableBitSet.of(), ImmutableBitSet.of(), ImmutableSet.of()); |
| 103 | + } |
| 104 | + /** Returns filterFields. */ |
| 105 | + public ImmutableBitSet getFilterFields() { |
| 106 | + return filterFields; |
| 107 | + } |
| 108 | + |
| 109 | + /** Returns bypassFields. */ |
| 110 | + public ImmutableBitSet getBypassFields() { |
| 111 | + return bypassFields; |
| 112 | + } |
| 113 | + |
| 114 | + /** Returns remnantFilterFields. */ |
| 115 | + public ImmutableSet<SqlQualified> getRemnantFilterFields() { |
| 116 | + return remnantFilterFields; |
| 117 | + } |
| 118 | +} |
0 commit comments