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

org.apache.calcite.sql.SqlIdentifier Maven / Gradle / Ivy

There is a newer version: 1.21.0.265
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 org.apache.calcite.sql;

import org.apache.calcite.rel.type.DynamicRecordType;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.util.SqlVisitor;
import org.apache.calcite.sql.validate.SqlMonotonicity;
import org.apache.calcite.sql.validate.SqlQualified;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Util;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

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

/**
 * A SqlIdentifier is an identifier, possibly compound.
 */
public class SqlIdentifier extends SqlNode {

  //~ Instance fields --------------------------------------------------------

  /**
   * Array of the components of this compound identifier.
   *
   * 

The empty string represents the wildcard "*", * to distinguish it from a real "*" (presumably specified using quotes). * *

It's convenient to have this member public, and it's convenient to * have this member not-final, but it's a shame it's public and not-final. * If you assign to this member, please use * {@link #setNames(java.util.List, java.util.List)}. * And yes, we'd like to make identifiers immutable one day. */ public ImmutableList names; /** * This identifier's collation (if any). */ final SqlCollation collation; /** * A list of the positions of the components of compound identifiers. */ protected ImmutableList componentPositions; //~ Constructors ----------------------------------------------------------- /** * Creates a compound identifier, for example foo.bar. * * @param names Parts of the identifier, length ≥ 1 */ public SqlIdentifier( List names, SqlCollation collation, SqlParserPos pos, List componentPositions) { super(pos); this.names = ImmutableList.copyOf(names); this.collation = collation; this.componentPositions = componentPositions == null ? null : ImmutableList.copyOf(componentPositions); for (String name : names) { assert name != null; } } public SqlIdentifier(List names, SqlParserPos pos) { this(names, null, pos, null); } /** * Creates a simple identifier, for example foo, with a * collation. */ public SqlIdentifier( String name, SqlCollation collation, SqlParserPos pos) { this(ImmutableList.of(name), collation, pos, null); } /** * Creates a simple identifier, for example foo. */ public SqlIdentifier( String name, SqlParserPos pos) { this(ImmutableList.of(name), null, pos, null); } /** Creates an identifier that is a singleton wildcard star. */ public static SqlIdentifier star(SqlParserPos pos) { return star(ImmutableList.of(""), pos, ImmutableList.of(pos)); } /** Creates an identifier that ends in a wildcard star. */ public static SqlIdentifier star(List names, SqlParserPos pos, List componentPositions) { return new SqlIdentifier( Lists.transform(names, s -> s.equals("*") ? "" : s), null, pos, componentPositions); } //~ Methods ---------------------------------------------------------------- public SqlKind getKind() { return SqlKind.IDENTIFIER; } @Override public SqlNode clone(SqlParserPos pos) { return new SqlIdentifier(names, collation, pos, componentPositions); } @Override public String toString() { return getString(names); } /** Converts a list of strings to a qualified identifier. */ public static String getString(List names) { return Util.sepList(toStar(names), "."); } /** Converts empty strings in a list of names to stars. */ public static List toStar(List names) { return Lists.transform(names, s -> s.equals("") ? "*" : s.equals("*") ? "\"*\"" : s); } /** * Modifies the components of this identifier and their positions. * * @param names Names of components * @param poses Positions of components */ public void setNames(List names, List poses) { this.names = ImmutableList.copyOf(names); this.componentPositions = poses == null ? null : ImmutableList.copyOf(poses); } /** Returns an identifier that is the same as this except one modified name. * Does not modify this identifier. */ public SqlIdentifier setName(int i, String name) { if (!names.get(i).equals(name)) { String[] nameArray = names.toArray(new String[0]); nameArray[i] = name; return new SqlIdentifier(ImmutableList.copyOf(nameArray), collation, pos, componentPositions); } else { return this; } } /** Returns an identifier that is the same as this except with a component * added at a given position. Does not modify this identifier. */ public SqlIdentifier add(int i, String name, SqlParserPos pos) { final List names2 = new ArrayList<>(names); names2.add(i, name); final List pos2; if (componentPositions == null) { pos2 = null; } else { pos2 = new ArrayList<>(componentPositions); pos2.add(i, pos); } return new SqlIdentifier(names2, collation, pos, pos2); } /** * Returns the position of the ith component of a compound * identifier, or the position of the whole identifier if that information * is not present. * * @param i Ordinal of component. * @return Position of i'th component */ public SqlParserPos getComponentParserPosition(int i) { assert (i >= 0) && (i < names.size()); return (componentPositions == null) ? getParserPosition() : componentPositions.get(i); } /** * Copies names and components from another identifier. Does not modify the * cross-component parser position. * * @param other identifier from which to copy */ public void assignNamesFrom(SqlIdentifier other) { setNames(other.names, other.componentPositions); } /** * Creates an identifier which contains only the ordinalth * component of this compound identifier. It will have the correct * {@link SqlParserPos}, provided that detailed position information is * available. */ public SqlIdentifier getComponent(int ordinal) { return getComponent(ordinal, ordinal + 1); } public SqlIdentifier getComponent(int from, int to) { final SqlParserPos pos; final ImmutableList pos2; if (componentPositions == null) { pos2 = null; pos = this.pos; } else { pos2 = componentPositions.subList(from, to); pos = SqlParserPos.sum(pos2); } return new SqlIdentifier(names.subList(from, to), collation, pos, pos2); } /** * Creates an identifier that consists of this identifier plus a name segment. * Does not modify this identifier. */ public SqlIdentifier plus(String name, SqlParserPos pos) { final ImmutableList names = ImmutableList.builder().addAll(this.names).add(name).build(); final ImmutableList componentPositions; final SqlParserPos pos2; if (this.componentPositions != null) { final ImmutableList.Builder builder = ImmutableList.builder(); componentPositions = builder.addAll(this.componentPositions).add(pos).build(); pos2 = SqlParserPos.sum(builder.add(this.pos).build()); } else { componentPositions = null; pos2 = pos; } return new SqlIdentifier(names, collation, pos2, componentPositions); } /** * Creates an identifier that consists of this identifier plus a wildcard star. * Does not modify this identifier. */ public SqlIdentifier plusStar() { final SqlIdentifier id = this.plus("*", SqlParserPos.ZERO); return new SqlIdentifier( id.names.stream().map(s -> s.equals("*") ? "" : s) .collect(Util.toImmutableList()), null, id.pos, id.componentPositions); } /** Creates an identifier that consists of all but the last {@code n} * name segments of this one. */ public SqlIdentifier skipLast(int n) { return getComponent(0, names.size() - n); } public void unparse( SqlWriter writer, int leftPrec, int rightPrec) { writer.getDialect().unparseIdentifier(writer, this); } public void validate(SqlValidator validator, SqlValidatorScope scope) { validator.validateIdentifier(this, scope); } public void validateExpr(SqlValidator validator, SqlValidatorScope scope) { // First check for builtin functions which don't have parentheses, // like "LOCALTIME". final SqlCall call = validator.makeNullaryCall(this); if (call != null) { validator.validateCall(call, scope); return; } validator.validateIdentifier(this, scope); } public boolean equalsDeep(SqlNode node, Litmus litmus) { if (!(node instanceof SqlIdentifier)) { return litmus.fail("{} != {}", this, node); } SqlIdentifier that = (SqlIdentifier) node; if (this.names.size() != that.names.size()) { return litmus.fail("{} != {}", this, node); } for (int i = 0; i < names.size(); i++) { if (!this.names.get(i).equals(that.names.get(i))) { return litmus.fail("{} != {}", this, node); } } return litmus.succeed(); } public R accept(SqlVisitor visitor) { return visitor.visit(this); } public SqlCollation getCollation() { return collation; } public String getSimple() { assert names.size() == 1; return names.get(0); } /** * Returns whether this identifier is a star, such as "*" or "foo.bar.*". */ public boolean isStar() { return Util.last(names).equals(""); } /** * Returns whether this is a simple identifier. "FOO" is simple; "*", * "FOO.*" and "FOO.BAR" are not. */ public boolean isSimple() { return names.size() == 1 && !isStar(); } /** * Returns whether the {@code i}th component of a compound identifier is * quoted. * * @param i Ordinal of component * @return Whether i'th component is quoted */ public boolean isComponentQuoted(int i) { return componentPositions != null && componentPositions.get(i).isQuoted(); } public SqlMonotonicity getMonotonicity(SqlValidatorScope scope) { // for "star" column, whether it's static or dynamic return not_monotonic directly. if (Util.last(names).equals("") || DynamicRecordType.isDynamicStarColName(Util.last(names))) { return SqlMonotonicity.NOT_MONOTONIC; } // First check for builtin functions which don't have parentheses, // like "LOCALTIME". final SqlValidator validator = scope.getValidator(); final SqlCall call = validator.makeNullaryCall(this); if (call != null) { return call.getMonotonicity(scope); } final SqlQualified qualified = scope.fullyQualify(this); final SqlIdentifier fqId = qualified.identifier; return qualified.namespace.resolve().getMonotonicity(Util.last(fqId.names)); } } // End SqlIdentifier.java





© 2015 - 2024 Weber Informatics LLC | Privacy Policy