Class SqlIdentifiers

java.lang.Object
dev.frostlake.executor.SqlIdentifiers

public final class SqlIdentifiers extends Object
Canonical form of a SQL identifier, matching Snowflake's identifier resolution:
  • an unquoted identifier folds to UPPERCASE (site → SITE, so it lands in the catalog, INFORMATION_SCHEMA, SHOW output and result-set column labels the same way Snowflake stores it);
  • a "double-quoted" identifier keeps its exact case (the surrounding quotes are stripped);
  • a $n positional parameter becomes COLUMNn.

Name resolution is already case-insensitive (storage keys are upper-cased and column lookups use equalsIgnoreCase), so folding changes only the canonical/display name, never whether a name resolves. Every identifier-name extraction point routes through here so the behaviour is uniform.

  • Method Details

    • verbatim

      public static String verbatim(FrostlakeParser.IdentifierContext ctx)
      The identifier EXACTLY as written — quotes stripped, but no case folding. Structured-type field names are the one place Snowflake does not fold: live-verified, CAST(OBJECT_CONSTRUCT('x','a') AS OBJECT(x VARCHAR)) yields {"x":"a"} while the same cast to OBJECT(X VARCHAR) FAILS "Typed object schema mismatch in conversion" — the unquoted X stayed upper case and did not match the key x.
    • canonical

      public static String canonical(FrostlakeParser.IdentifierContext ctx)
    • spellAsWritten

      public static String spellAsWritten(String rawToken)
      One name part spelled the way live ECHOES it in a refusal: a quoted token stays verbatim, quotes and case intact, and an unquoted one folds to upper case. "a" and a name different columns, so the two cannot be printed alike.
    • spellCanonical

      public static String spellCanonical(String name)
      A CANONICAL name spelled the way a refusal prints it: bare when it could have been written without quotes, quoted otherwise. The same rule spellAsWritten(java.lang.String) applies to a raw token, for callers that hold a name already resolved — an object's stored identity, a folded function name, the relation and column of the grouped sentence.
      Parameters:
      name - the canonical name
      Returns:
      the name as a refusal spells it
    • spellAlreadyCanonicalPath

      public static String spellAlreadyCanonicalPath(String path)
      An ALREADY-CANONICAL dotted name spelled back, part by part, without canonicalising it again.

      The distinction from spellCanonicalPath(java.lang.String) is the whole point: that one canonicalises first, which is right for text as the user WROTE it and wrong for a name that has already been through the mill. A canonical name has had its quotes removed and its case kept, so a second pass sees an unquoted test_schema, finds no quotes to protect it, and folds it — which is how TEST_DB."test_schema" came back as TEST_DB.TEST_SCHEMA.

      Parameters:
      path - the already-canonical name, parts separated by dots
      Returns:
      the name spelled with quotes only where a part needs them
    • spellCanonicalPath

      public static String spellCanonicalPath(String path)
    • isIdentifierReference

      public static boolean isIdentifierReference(String text)
      Whether a runtime string reads as an identifier reference, the way IDENTIFIER() reads its argument. Once trimmed, each dotted part is a closed double-quoted identifier or an unquoted one: a letter or an underscore, then letters, digits, underscores and dollars. An empty part stands for the default database or schema (a..b), but the empty string names nothing (live-verified).
      Parameters:
      text - the evaluated argument
      Returns:
      true when every part is an identifier
    • canonicalText

      public static String canonicalText(String text)
    • identifierReferenceParts

      public static String[] identifierReferenceParts(String text)
      The canonical parts of an IDENTIFIER(...) argument's value: canonicalTextParts(java.lang.String), with an empty middle part ('db..t') read as the PUBLIC schema, as the account reads it.
    • identifierReferenceText

      public static String identifierReferenceText(String text)
    • canonicalTextParts

      public static String[] canonicalTextParts(String text)
      The canonical PARTS of a runtime-string object name — canonicalText(java.lang.String) without the rejoin, for callers that resolve per level: a double-quoted part containing a dot survives as ONE part here, where the joined spelling can no longer show where its dots came from. The same not-already-canonicalised caveat as canonicalText(java.lang.String) applies.