Class DeclaredTypeFold

java.lang.Object
dev.frostlake.types.DeclaredTypeFold

public final class DeclaredTypeFold extends Object
The type a set of BRANCHES agree on — the rule a UNION applies to its arms and a conditional applies to its results. The two surfaces share most of their answers, measured cell by cell on a live account, which is why the rule lives here rather than in either of them; where they DIVERGE the branch-only half sits in foldPair(dev.frostlake.types.DataType, dev.frostlake.types.DataType) and combine(dev.frostlake.types.DataType, dev.frostlake.types.DataType) names the cells that prove it:
   VARCHAR(4)     with VARCHAR(100)     TEXT(100)              the widest
   BINARY(4)      with BINARY(100)      BINARY(100)            and its fixed spelling, see BinaryType
   NUMBER(5,1)    with NUMBER(10,3)     NUMBER(10,3)
   NUMBER(5,4)    with NUMBER(10,0)     NUMBER(14,4)           NOT (10,4)
   TIMESTAMP_NTZ(3) with TIMESTAMP_NTZ(9)   scale 9            the wider precision
   DATE           with DATE             DATE
   VARCHAR(4)     with NUMBER(5,1)      NUMBER(18,5)           the string joins the other family
 

THE NUMERIC RULE IS THE ONE WORTH READING TWICE: the widest INTEGER PART meets the widest SCALE, so (5,4) with (10,0) needs ten integer digits and four decimals — fourteen — where a naive max-precision/max-scale would answer (10,4) and could not hold the value.

  • Field Details

    • UNKNOWN_LENGTH_VARCHAR

      public static final int UNKNOWN_LENGTH_VARCHAR
      The width a VARCHAR takes when it folds with a branch that carries no length of its own — the 128MB conversion width, not the 16MB one a declared column defaults to.
      See Also:
  • Method Details

    • sameDeclaredType

      public static boolean sameDeclaredType(DataType left, DataType right)
      Whether two declared types are the SAME type — the family and its parameters. A VECTOR's dimension and a structured OBJECT's fields are rendered into the name; the width of a string or binary, a number's precision and scale, and a temporal's precision are not, so those compare their parameters explicitly.
      Parameters:
      left - one type
      right - the other
      Returns:
      true when they are indistinguishable as declared types
    • combine

      public static DataType combine(DataType left, DataType right)
      The type two branches — or two set-operation ARMS — fold to, or null when they cannot be combined.

      The two surfaces share most of their rules and are measured together, but they are NOT the same function, which is why the branch-only rules stay in foldPair(dev.frostlake.types.DataType, dev.frostlake.types.DataType). Three cells prove the split, each measured on the account:

         NUMBER then BOOLEAN   COALESCE(n, bo) is BOOLEAN, while n UNION bo is a compile-time refusal
         STRING beside BOOLEAN COALESCE(v, bo) widens to VARCHAR(134217728), v UNION bo stays VARCHAR(5)
         STRING beside NULL    COALESCE(v, NULL) widens the same way, v UNION NULL stays VARCHAR(5)
       

      So the unknown-length widening is a BRANCH rule: an arm keeps the width it declares. What both surfaces do share is here — the numeric supertype, the common string and binary width, an approximate number swallowing an exact one, temporal widening, and a leading BOOLEAN winning over whatever follows it.

      Parameters:
      left - one branch's type
      right - the other's
      Returns:
      the combined type, or null when the pair has no measured answer
    • numericSupertype

      public static NumericType numericSupertype(NumericType left, NumericType right)
      Snowflake's numeric supertype: the widest INTEGER PART meets the widest SCALE.
      Parameters:
      left - one number
      right - the other
      Returns:
      the number that holds both
    • stringContribution

      public static DataType stringContribution(DataType nonString)
      What a VARCHAR branch contributes when it sits beside exactly one OTHER family: it joins that family rather than dragging everything to text.
      Parameters:
      nonString - the one other family present
      Returns:
      the type the string contributes, or null when the pairing is not a measured one
    • foldBranches

      public static DataType foldBranches(List<DataType> branchTypes)
    • foldBranches

      public static DataType foldBranches(List<DataType> branchTypes, List<DataType> literalMeasurements)
      The branch fold, told which branches were written as STRING LITERALS and what each measures as a number. A string literal beside a number contributes exactly what the same number written WITHOUT quotes would — measured on a real account, and the pair is identical either way:
         COALESCE(n2, '5.12345')        NUMBER(13,5)      n2 is NUMBER(10,2)
         COALESCE(n2,  5.12345 )        NUMBER(13,5)      the same, unquoted
         COALESCE(n2, '123456789012')   NUMBER(14,2)
         COALESCE(n2,  123456789012 )   NUMBER(14,2)      the same again
       

      A string COLUMN is different and keeps the flat NUMBER(18,5) — it has no literal text to measure, so live cannot narrow it. That column-versus-literal split is the whole reason this needs the branch EXPRESSION and not just its type.

      The old behaviour answered NUMBER(18,5) for every string branch. It happened to be right for a one-digit literal like '5', where the fold with NUMBER(10,2) lands on NUMBER(10,2) either way — which is exactly why measuring only that shape left the rule underdetermined.

      Parameters:
      branchTypes - each branch's declared type
      literalMeasurements - per branch, the numeric type a STRING LITERAL branch measures as, or null for a branch that is not one; null for the whole list when the caller has no expressions to read
      Returns:
      the folded type, or null when the branches do not fold