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

com.hazelcast.org.apache.calcite.schema.impl.ModifiableViewTable Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * 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 com.hazelcast.org.apache.calcite.schema.impl;

import com.hazelcast.org.apache.calcite.plan.RelOptTable;
import com.hazelcast.org.apache.calcite.plan.RelOptUtil;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeFactory;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeField;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeImpl;
import com.hazelcast.org.apache.calcite.rel.type.RelProtoDataType;
import com.hazelcast.org.apache.calcite.rex.RexBuilder;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.schema.ColumnStrategy;
import com.hazelcast.org.apache.calcite.schema.ExtensibleTable;
import com.hazelcast.org.apache.calcite.schema.ModifiableView;
import com.hazelcast.org.apache.calcite.schema.Path;
import com.hazelcast.org.apache.calcite.schema.Table;
import com.hazelcast.org.apache.calcite.schema.Wrapper;
import com.hazelcast.org.apache.calcite.sql.SqlFunction;
import com.hazelcast.org.apache.calcite.sql2rel.InitializerContext;
import com.hazelcast.org.apache.calcite.sql2rel.InitializerExpressionFactory;
import com.hazelcast.org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
import com.hazelcast.org.apache.calcite.util.ImmutableIntList;

import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.com.google.common.collect.ImmutableMap;

import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.hazelcast.org.apache.calcite.sql.validate.SqlValidatorUtil.mapNameToIndex;

import static java.util.Objects.requireNonNull;

/** Extension to {@link ViewTable} that is modifiable. */
public class ModifiableViewTable extends ViewTable
    implements ModifiableView, Wrapper {
  private final Table table;
  private final Path tablePath;
  private final RexNode constraint;
  private final ImmutableIntList columnMapping;
  private final InitializerExpressionFactory initializerExpressionFactory;

  /** Creates a ModifiableViewTable. */
  public ModifiableViewTable(Type elementType, RelProtoDataType rowType,
      String viewSql, List schemaPath, @Nullable List viewPath,
      Table table, Path tablePath, RexNode constraint,
      ImmutableIntList columnMapping) {
    super(elementType, rowType, viewSql, schemaPath, viewPath);
    this.table = table;
    this.tablePath = tablePath;
    this.constraint = constraint;
    this.columnMapping = columnMapping;
    this.initializerExpressionFactory = new ModifiableViewTableInitializerExpressionFactory();
  }

  @Override public RexNode getConstraint(RexBuilder rexBuilder,
      RelDataType tableRowType) {
    return rexBuilder.copy(constraint);
  }

  @Override public ImmutableIntList getColumnMapping() {
    return columnMapping;
  }

  @Override public Table getTable() {
    return table;
  }

  @Override public Path getTablePath() {
    return tablePath;
  }

  @Override public  @Nullable C unwrap(Class aClass) {
    if (aClass.isInstance(initializerExpressionFactory)) {
      return aClass.cast(initializerExpressionFactory);
    } else if (aClass.isInstance(table)) {
      return aClass.cast(table);
    }
    return super.unwrap(aClass);
  }

  /**
   * Extends the underlying table and returns a new view with updated row-type
   * and column-mapping.
   *
   * 

The type factory is used to perform some scratch calculations, viz the * type mapping, but the "real" row-type will be assigned later, when the * table has been bound to the statement's type factory. The is important, * because adding types to type factories that do not belong to a statement * could potentially leak memory. * * @param extendedColumns Extended fields * @param typeFactory Type factory */ public final ModifiableViewTable extend( List extendedColumns, RelDataTypeFactory typeFactory) { final ExtensibleTable underlying = unwrap(ExtensibleTable.class); assert underlying != null; final RelDataTypeFactory.Builder builder = typeFactory.builder(); final RelDataType rowType = getRowType(typeFactory); for (RelDataTypeField column : rowType.getFieldList()) { builder.add(column); } for (RelDataTypeField column : extendedColumns) { builder.add(column); } // The characteristics of the new view. final RelDataType newRowType = builder.build(); final ImmutableIntList newColumnMapping = getNewColumnMapping(underlying, getColumnMapping(), extendedColumns, typeFactory); // Extend the underlying table with only the fields that // duplicate column names in neither the view nor the base table. final List underlyingColumns = underlying.getRowType(typeFactory).getFieldList(); final List columnsOfExtendedBaseTable = RelOptUtil.deduplicateColumns(underlyingColumns, extendedColumns); final List extendColumnsOfBaseTable = columnsOfExtendedBaseTable.subList( underlyingColumns.size(), columnsOfExtendedBaseTable.size()); final Table extendedTable = underlying.extend(extendColumnsOfBaseTable); return extend(extendedTable, RelDataTypeImpl.proto(newRowType), newColumnMapping); } /** * Creates a mapping from the view index to the index in the underlying table. */ private static ImmutableIntList getNewColumnMapping(Table underlying, ImmutableIntList oldColumnMapping, List extendedColumns, RelDataTypeFactory typeFactory) { final List baseColumns = underlying.getRowType(typeFactory).getFieldList(); final Map nameToIndex = mapNameToIndex(baseColumns); final ImmutableList.Builder newMapping = ImmutableList.builder(); newMapping.addAll(oldColumnMapping); int newMappedIndex = baseColumns.size(); for (RelDataTypeField extendedColumn : extendedColumns) { String extendedColumnName = extendedColumn.getName(); if (nameToIndex.containsKey(extendedColumnName)) { // The extended column duplicates a column in the underlying table. // Map to the index in the underlying table. newMapping.add(nameToIndex.get(extendedColumnName)); } else { // The extended column is not in the underlying table. newMapping.add(newMappedIndex++); } } return ImmutableIntList.copyOf(newMapping.build()); } protected ModifiableViewTable extend(Table extendedTable, RelProtoDataType protoRowType, ImmutableIntList newColumnMapping) { return new ModifiableViewTable(getElementType(), protoRowType, getViewSql(), getSchemaPath(), getViewPath(), extendedTable, getTablePath(), constraint, newColumnMapping); } /** * Initializes columns based on the view constraint. */ private class ModifiableViewTableInitializerExpressionFactory extends NullInitializerExpressionFactory { private final ImmutableMap projectMap; private ModifiableViewTableInitializerExpressionFactory() { super(); final Map projectMap = new HashMap<>(); final List filters = new ArrayList<>(); RelOptUtil.inferViewPredicates(projectMap, filters, constraint); assert filters.isEmpty(); this.projectMap = ImmutableMap.copyOf(projectMap); } @Override public ColumnStrategy generationStrategy(RelOptTable table, int iColumn) { final ModifiableViewTable viewTable = requireNonNull( table.unwrap(ModifiableViewTable.class), () -> "unable to unwrap ModifiableViewTable from " + table); assert iColumn < viewTable.columnMapping.size(); // Use the view constraint to generate the default value if the column is // constrained. final int mappedOrdinal = viewTable.columnMapping.get(iColumn); final RexNode viewConstraint = projectMap.get(mappedOrdinal); if (viewConstraint != null) { return ColumnStrategy.DEFAULT; } // Otherwise use the default value of the underlying table. final Table schemaTable = viewTable.getTable(); if (schemaTable instanceof Wrapper) { final InitializerExpressionFactory initializerExpressionFactory = ((Wrapper) schemaTable).unwrap(InitializerExpressionFactory.class); if (initializerExpressionFactory != null) { return initializerExpressionFactory.generationStrategy(table, iColumn); } } return super.generationStrategy(table, iColumn); } @Override public RexNode newColumnDefaultValue(RelOptTable table, int iColumn, InitializerContext context) { final ModifiableViewTable viewTable = requireNonNull( table.unwrap(ModifiableViewTable.class), () -> "unable to unwrap ModifiableViewTable from " + table); assert iColumn < viewTable.columnMapping.size(); final RexBuilder rexBuilder = context.getRexBuilder(); final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory(); final RelDataType viewType = viewTable.getRowType(typeFactory); final RelDataType iType = viewType.getFieldList().get(iColumn).getType(); // Use the view constraint to generate the default value if the column is constrained. final int mappedOrdinal = viewTable.columnMapping.get(iColumn); final RexNode viewConstraint = projectMap.get(mappedOrdinal); if (viewConstraint != null) { return rexBuilder.ensureType(iType, viewConstraint, true); } // Otherwise use the default value of the underlying table. final Table schemaTable = viewTable.getTable(); if (schemaTable instanceof Wrapper) { final InitializerExpressionFactory initializerExpressionFactory = ((Wrapper) schemaTable).unwrap(InitializerExpressionFactory.class); if (initializerExpressionFactory != null) { final RexNode tableConstraint = initializerExpressionFactory.newColumnDefaultValue(table, iColumn, context); return rexBuilder.ensureType(iType, tableConstraint, true); } } // Otherwise Sql type of NULL. return super.newColumnDefaultValue(table, iColumn, context); } @Override public RexNode newAttributeInitializer(RelDataType type, SqlFunction constructor, int iAttribute, List constructorArgs, InitializerContext context) { throw new UnsupportedOperationException("Not implemented - unknown requirements"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy