content: /*
   * 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.cassandra.cql3.functions.types;
  
  import org.apache.cassandra.cql3.ColumnIdentifier;
  
  import static org.apache.cassandra.utils.LocalizeString.toLowerCaseLocalized;
  
  /**
   * Keeps metadata on the connected cluster, including known nodes and schema definitions.
   */
  public class Metadata
  {
      /*
       * Deal with case sensitivity for a given element id (keyspace, table, column, etc.)
       *
       * This method is used to convert identifiers provided by the client (through methods such as getKeyspace(String)),
       * to the format used internally by the driver.
       *
       * We expect client-facing APIs to behave like cqlsh, that is:
       * - identifiers that are mixed-case or contain special characters should be quoted.
       * - unquoted identifiers will be lowercased: getKeyspace("Foo") will look for a keyspace named "foo"
       */
      static String handleId(String id)
      {
          // Shouldn't really happen for this method, but no reason to fail here
          if (id == null) return null;
  
          boolean isAlphanumericLowCase = true;
          boolean isAlphanumeric = true;
          for (int i = 0; i < id.length(); i++)
          {
              char c = id.charAt(i);
              if (c >= 65 && c <= 90)
              { // A-Z
                  isAlphanumericLowCase = false;
              }
              else if (!((c >= 48 && c <= 57) // 0-9
                         || (c == 95) // _ (underscore)
                         || (c >= 97 && c <= 122) // a-z
              ))
              {
                  isAlphanumeric = false;
                  isAlphanumericLowCase = false;
                  break;
              }
          }
  
          if (isAlphanumericLowCase)
          {
              return id;
          }
          if (isAlphanumeric)
          {
              return toLowerCaseLocalized(id);
          }
  
          // Check if it's enclosed in quotes. If it is, remove them and unescape internal double quotes
          return ParseUtils.unDoubleQuote(id);
      }
  
      /**
       * Quotes a CQL identifier if necessary.
       *
       * <p>This is similar to {@link #quote(String)}, except that it won't quote the input string if it
       * can safely be used as-is. For example:
       *
       * <ul>
       * <li>{@code quoteIfNecessary("foo").equals("foo")} (no need to quote).
       * <li>{@code quoteIfNecessary("Foo").equals("\"Foo\"")} (identifier is mixed case so case
       * sensitivity is required)
       * <li>{@code quoteIfNecessary("foo bar").equals("\"foo bar\"")} (identifier contains special
       * characters)
       * <li>{@code quoteIfNecessary("table").equals("\"table\"")} (identifier is a reserved CQL
       * keyword)
       * </ul>
       *
       * @param id the "internal" form of the identifier. That is, the identifier as it would appear in
       *           Cassandra system tables (such as {@code system_schema.tables}, {@code
       *           system_schema.columns}, etc.)
       * @return the identifier as it would appear in a CQL query string. This is also how you need to
       * pass it to public driver methods, such as {@code #getKeyspace(String)}.
       */
      static String quoteIfNecessary(String id)
      {
          return ColumnIdentifier.maybeQuote(id);
      }
  
      /**
       * Quote a keyspace, table or column identifier to make it case sensitive.
       *
       * <p>CQL identifiers, including keyspace, table and column ones, are case insensitive by default.
       * Case sensitive identifiers can however be provided by enclosing the identifier in double quotes
       * (see the <a href="http://cassandra.apache.org/doc/cql3/CQL.html#identifiers">CQL
       * documentation</a> for details). If you are using case sensitive identifiers, this method can be
       * used to enclose such identifiers in double quotes, making them case sensitive.
       *
       * <p>Note that <a
       * href="https://docs.datastax.com/en/cql/3.0/cql/cql_reference/keywords_r.html">reserved CQL
       * keywords</a> should also be quoted. You can check if a given identifier is a reserved keyword
       * by calling {@code #isReservedCqlKeyword(String)}.
       *
       * @param id the keyspace or table identifier.
       * @return {@code id} enclosed in double-quotes, for use in methods like {@code #getReplicas},
       * {@code #getKeyspace}, {@code KeyspaceMetadata#getTable} or even {@code
       * Cluster#connect(String)}.
       */
      public static String quote(String id)
      {
          return ParseUtils.doubleQuote(id);
      }
  }
  