/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package io.crate.analyze; import io.crate.metadata.*; import io.crate.metadata.doc.DocTableInfo; import io.crate.sql.parser.SqlParser; import io.crate.sql.tree.*; import io.crate.types.*; import org.elasticsearch.common.Nullable; import java.util.*; public class MetaDataToASTNodeResolver { public static CreateTable resolveCreateTable(DocTableInfo info) { Extractor extractor = new Extractor(info); return extractor.extractCreateTable(); } private static class Extractor { private final DocTableInfo tableInfo; public Extractor(DocTableInfo tableInfo) { this.tableInfo = tableInfo; } private Table extractTable() { return new Table(QualifiedName.of(tableInfo.ident().fqn()), false); } private List<TableElement> extractTableElements() { List<TableElement> elements = new ArrayList<>(); // column definitions elements.addAll(extractColumnDefinitions(null)); // primary key constraint PrimaryKeyConstraint pk = extractPrimaryKeyConstraint(); if (pk != null) elements.add(pk); // index definitions elements.addAll(extractIndexDefinitions()); return elements; } private List<ColumnDefinition> extractColumnDefinitions(@Nullable ColumnIdent parent) { Iterator<Reference> referenceIterator = tableInfo.iterator(); List<ColumnDefinition> elements = new ArrayList<>(); while (referenceIterator.hasNext()) { Reference info = referenceIterator.next(); ColumnIdent ident = info.ident().columnIdent(); if (ident.isSystemColumn()) continue; if (parent != null && !ident.isChildOf(parent)) continue; if (parent == null && !ident.path().isEmpty()) continue; if (parent != null) { if (ident.getParent().compareTo(parent) > 0) continue; } ColumnType columnType = null; if (info.valueType().equals(DataTypes.OBJECT)) { columnType = new ObjectColumnType(info.columnPolicy().value(), extractColumnDefinitions(ident)); } else if (info.valueType().id() == ArrayType.ID) { DataType innerType = ((CollectionType) info.valueType()).innerType(); ColumnType innerColumnType = null; if (innerType.equals(DataTypes.OBJECT)) { innerColumnType = new ObjectColumnType(info.columnPolicy().value(), extractColumnDefinitions(ident)); } else { innerColumnType = new ColumnType(innerType.getName()); } columnType = CollectionColumnType.array(innerColumnType); } else if (info.valueType().id() == SetType.ID) { ColumnType innerColumnType = new ColumnType(((CollectionType) info.valueType()).innerType().getName()); columnType = CollectionColumnType.set(innerColumnType); } else { columnType = new ColumnType(info.valueType().getName()); } String columnName = ident.isColumn() ? ident.name() : ident.path().get(ident.path().size() - 1); List<ColumnConstraint> constraints = new ArrayList<>(); if (!info.isNullable()) { constraints.add(new NotNullColumnConstraint()); } if (info.indexType().equals(Reference.IndexType.NO) && !info.valueType().equals(DataTypes.OBJECT) && !(info.valueType().id() == ArrayType.ID && ((CollectionType) info.valueType()).innerType().equals(DataTypes.OBJECT))) { constraints.add(IndexColumnConstraint.OFF); } else if (info.indexType().equals(Reference.IndexType.ANALYZED)) { String analyzer = tableInfo.getAnalyzerForColumnIdent(ident); GenericProperties properties = new GenericProperties(); if (analyzer != null) { properties.add(new GenericProperty(FulltextAnalyzerResolver.CustomType.ANALYZER.getName(), new StringLiteral(analyzer))); } constraints.add(new IndexColumnConstraint("fulltext", properties)); } else if (info.valueType().equals(DataTypes.GEO_SHAPE)) { GeoReference geoReference = (GeoReference) info; GenericProperties properties = new GenericProperties(); if (geoReference.distanceErrorPct() != null) { properties.add(new GenericProperty("distance_error_pct", StringLiteral.fromObject(geoReference.distanceErrorPct()))); } if (geoReference.precision() != null) { properties.add(new GenericProperty("precision", StringLiteral.fromObject(geoReference.precision()))); } if (geoReference.treeLevels() != null) { properties.add(new GenericProperty("tree_levels", StringLiteral.fromObject(geoReference.treeLevels()))); } constraints.add(new IndexColumnConstraint(geoReference.geoTree(), properties)); } Expression expression = null; if (info instanceof GeneratedReference) { String formattedExpression = ((GeneratedReference) info).formattedGeneratedExpression(); expression = SqlParser.createExpression(formattedExpression); } ColumnDefinition column = new ColumnDefinition(columnName, expression, columnType, constraints); elements.add(column); } return elements; } private PrimaryKeyConstraint extractPrimaryKeyConstraint() { if (!tableInfo.primaryKey().isEmpty()) { if (tableInfo.primaryKey().size() == 1 && tableInfo.primaryKey().get(0).isSystemColumn()) { return null; } return new PrimaryKeyConstraint(expressionsFromColumns(tableInfo.primaryKey())); } return null; } private List<IndexDefinition> extractIndexDefinitions() { List<IndexDefinition> elements = new ArrayList<>(); Iterator indexColumns = tableInfo.indexColumns(); if (indexColumns != null) { while (indexColumns.hasNext()) { IndexReference indexRef = (IndexReference) indexColumns.next(); String name = indexRef.ident().columnIdent().name(); List<Expression> columns = expressionsFromReferences(indexRef.columns()); if (indexRef.indexType().equals(Reference.IndexType.ANALYZED)) { String analyzer = indexRef.analyzer(); GenericProperties properties = new GenericProperties(); if (analyzer != null) { properties.add(new GenericProperty(FulltextAnalyzerResolver.CustomType.ANALYZER.getName(), new StringLiteral(analyzer))); } elements.add(new IndexDefinition(name, "fulltext", columns, properties)); } else if (indexRef.indexType().equals(Reference.IndexType.NOT_ANALYZED)) { elements.add(new IndexDefinition(name, "plain", columns, null)); } } } return elements; } private List<CrateTableOption> extractTableOptions() { List<CrateTableOption> options = new ArrayList<>(); // CLUSTERED BY (...) INTO ... SHARDS Expression clusteredByExpression = null; ColumnIdent clusteredBy = tableInfo.clusteredBy(); if (clusteredBy != null && !clusteredBy.isSystemColumn()) { clusteredByExpression = expressionFromColumn(clusteredBy); } Expression numShards = new LongLiteral(Integer.toString(tableInfo.numberOfShards())); options.add(new ClusteredBy(Optional.ofNullable(clusteredByExpression), Optional.of(numShards))); // PARTITIONED BY (...) if (tableInfo.isPartitioned() && !tableInfo.partitionedBy().isEmpty()) { options.add(new PartitionedBy(expressionsFromColumns(tableInfo.partitionedBy()))); } return options; } private GenericProperties extractTableProperties() { // WITH ( key = value, ... ) GenericProperties properties = new GenericProperties(); Expression numReplicas = new StringLiteral(tableInfo.numberOfReplicas().utf8ToString()); properties.add(new GenericProperty( TablePropertiesAnalyzer.esToCrateSettingName(TableParameterInfo.NUMBER_OF_REPLICAS), numReplicas ) ); // we want a sorted map of table parameters TreeMap<String, Object> tableParameters = new TreeMap<>(); tableParameters.putAll(tableInfo.tableParameters()); for (Map.Entry<String, Object> entry : tableParameters.entrySet()) { properties.add(new GenericProperty( TablePropertiesAnalyzer.esToCrateSettingName(entry.getKey()), Literal.fromObject(entry.getValue()) ) ); } properties.add(new GenericProperty( "column_policy", new StringLiteral(tableInfo.columnPolicy().value()) )); return properties; } private CreateTable extractCreateTable() { Table table = extractTable(); List<TableElement> tableElements = extractTableElements(); List<CrateTableOption> tableOptions = extractTableOptions(); Optional<GenericProperties> tableProperties = Optional.of(extractTableProperties()); return new CreateTable(table, tableElements, tableOptions, tableProperties, true); } private Expression expressionFromColumn(ColumnIdent ident) { Expression fqn = new QualifiedNameReference(QualifiedName.of(ident.getRoot().fqn())); for (String child : ident.path()) { fqn = new SubscriptExpression(fqn, Literal.fromObject(child)); } return fqn; } private List<Expression> expressionsFromReferences(List<Reference> columns) { List<Expression> expressions = new ArrayList<>(columns.size()); for (Reference ident : columns) { expressions.add(expressionFromColumn(ident.ident().columnIdent())); } return expressions; } private List<Expression> expressionsFromColumns(List<ColumnIdent> columns) { List<Expression> expressions = new ArrayList<>(columns.size()); for (ColumnIdent ident : columns) { expressions.add(expressionFromColumn(ident)); } return expressions; } } }