All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.jet.sql.impl.schema.HazelcastRelOptTable Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright 2021 Hazelcast Inc.
 *
 * Licensed under the Hazelcast Community License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://hazelcast.com/hazelcast-community-license
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hazelcast.jet.sql.impl.schema;

import com.hazelcast.jet.sql.impl.opt.common.CalcIntoScanRule;
import com.hazelcast.org.apache.calcite.linq4j.tree.Expression;
import com.hazelcast.org.apache.calcite.plan.RelOptSchema;
import com.hazelcast.org.apache.calcite.plan.RelOptTable;
import com.hazelcast.org.apache.calcite.prepare.Prepare;
import com.hazelcast.org.apache.calcite.rel.RelCollation;
import com.hazelcast.org.apache.calcite.rel.RelDistribution;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.RelReferentialConstraint;
import com.hazelcast.org.apache.calcite.rel.RelWriter;
import com.hazelcast.org.apache.calcite.rel.core.TableScan;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalTableScan;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeField;
import com.hazelcast.org.apache.calcite.schema.ColumnStrategy;
import com.hazelcast.org.apache.calcite.sql.SqlAccessType;
import com.hazelcast.org.apache.calcite.sql.validate.SqlModality;
import com.hazelcast.org.apache.calcite.sql.validate.SqlMonotonicity;
import com.hazelcast.org.apache.calcite.sql2rel.InitializerContext;
import com.hazelcast.org.apache.calcite.util.ImmutableBitSet;

import java.util.ArrayList;
import java.util.List;

/**
 * Custom implementation of Apache Calcite table.
 * 

* Tables are used inside {@link TableScan} operators. During logical planning we attempt to flatten the relational tree by * pushing down projects and filters into the table, see {@link CalcIntoScanRule}. *

* It is important to distinguish {@code TableScan} operators with and without pushdown. Otherwise scans that produce different * results will be merged into a single equivalence group, leading to incorrect query results. *

* To mitigate this we provide our own table implementation that overrides {@link #getQualifiedName()} method, used for scan * signature calculation (see {@link TableScan#explainTerms(RelWriter)}). The overridden version adds information about * pushed-down projections and scans to the table name, thus avoiding the problem. *

* For example, a table scan over table {@code p} without pushdowns may have a signature: *

 * ...table=[[hazelcast, p]]....
 * 
*

* A scan over the same table with project and filter will have a signature: *

 * ...table=[[hazelcast, p[projects=[0, 1], filter=>($2, 1)]]]...
 * 
*/ public class HazelcastRelOptTable implements Prepare.PreparingTable { private final Prepare.PreparingTable delegate; public HazelcastRelOptTable(Prepare.PreparingTable delegate) { this.delegate = delegate; } public Prepare.PreparingTable getDelegate() { return delegate; } @Override public List getQualifiedName() { // Get original names. List names = delegate.getQualifiedName(); assert names != null && !names.isEmpty(); List res = new ArrayList<>(names); // Extend the table name (the last element) with project/filter signature. int lastElement = res.size() - 1; res.set(lastElement, res.get(lastElement) + getTableSignature()); return res; } private String getTableSignature() { HazelcastTable table = delegate.unwrap(HazelcastTable.class); assert table != null; return table.getSignature(); } @Override public double getRowCount() { return delegate.getRowCount(); } @Override public RelDataType getRowType() { return delegate.getRowType(); } @Override public RelOptSchema getRelOptSchema() { return delegate.getRelOptSchema(); } @Override public RelNode toRel(ToRelContext context) { // Override this method to pass this table to the LogicalTableScan. // Otherwise the delegate would be used, which is incorrect. return LogicalTableScan.create(context.getCluster(), this, context.getTableHints()); } @Override public List getCollationList() { return delegate.getCollationList(); } @Override public RelDistribution getDistribution() { return delegate.getDistribution(); } @Override public boolean isKey(ImmutableBitSet columns) { return delegate.isKey(columns); } @Override public List getKeys() { return delegate.getKeys(); } @Override public List getReferentialConstraints() { return delegate.getReferentialConstraints(); } @Override public Expression getExpression(Class clazz) { return delegate.getExpression(clazz); } @Override public RelOptTable extend(List extendedFields) { return delegate.extend(extendedFields); } @Override public List getColumnStrategies() { return delegate.getColumnStrategies(); } @Override public SqlMonotonicity getMonotonicity(String columnName) { return delegate.getMonotonicity(columnName); } @Override public SqlAccessType getAllowedAccess() { return delegate.getAllowedAccess(); } @Override public boolean supportsModality(SqlModality modality) { return delegate.supportsModality(modality); } @Override public boolean isTemporal() { return delegate.isTemporal(); } @SuppressWarnings("deprecation") @Override public boolean columnHasDefaultValue(RelDataType rowType, int ordinal, InitializerContext initializerContext) { return delegate.columnHasDefaultValue(rowType, ordinal, initializerContext); } @Override public C unwrap(Class aClass) { return delegate.unwrap(aClass); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy