Class VariantAccessorFunction

java.lang.Object
dev.frostlake.functions.BuiltInFunction
dev.frostlake.functions.VariantAccessorFunction
Direct Known Subclasses:
ArrayAppend, ArraySize, ArrayToString, GetPath, ObjectInsert, ObjectKeys

public abstract class VariantAccessorFunction extends BuiltInFunction
A built-in that NAVIGATES a semi-structured value — reads a key, an index, a size, or splices a new element in — and therefore refuses a GEOSPATIAL one in EVERY argument position, while taking a plain OBJECT or ARRAY and a STRUCTURED one alike.

This family is the reason BuiltInFunction.geoRejection(int) exists as a question of its own. The accessors are precisely the surface both semi-structured declarations leave alone — they read a structured value quite happily, so they are not StructuredArgumentFunctions, and they read a plain OBJECT, so they declare no semiStructuredRejection either — which makes the inherited union default answer NONE for them. Live disagrees, and only for geo. Measured over one table carrying an OBJECT column and a GEOGRAPHY column: GET(o, 'k') returns "v" while GET(g, 'type') is "Invalid argument types for function 'GET': (GEOGRAPHY, VARCHAR(4))" (SQLSTATE 42P13), and GET_PATH, OBJECT_KEYS, OBJECT_INSERT, ARRAY_SIZE, ARRAY_APPEND and ARRAY_TO_STRING each split the same way.

Every position, not merely the semi-structured-shaped one: live refuses OBJECT_INSERT(o, 'a', g) and ARRAY_APPEND(ARRAY_CONSTRUCT(1), g) — a geo value in the VALUE slot of an otherwise valid call — with the same sentence, naming the offending position in the argument-type list.

A geo value is not reachable by any of them at all: it is not a VARIANT and does not become one (TO_VARIANT(g) and g::VARIANT are both compile errors live), so unlike the structured types there is no explicit conversion that opts back in. ST_ASGEOJSON(g) returns an OBJECT that these functions then read.

Membership is by measurement, so close neighbours stay out. GET_IGNORE_CASE, ARRAY_SLICE, MAP_KEYS and FLATTEN have not been measured over a geo value. PARSE_JSON deliberately stays out for the opposite reason: live refuses a plain OBJECT there too, so it is not a geo DIVERGENCE — it belongs to the semi-structured rule whenever that is declared for it.

  • Constructor Details

    • VariantAccessorFunction

      protected VariantAccessorFunction(String name, DataType returnType)
  • Method Details

    • geoRejection

      public SemiStructuredRejection geoRejection(int position)
      Description copied from class: BuiltInFunction
      How argument position refuses a statically GEOGRAPHY- or GEOMETRY-typed value. A geo value is a DOMAIN type that coerces to nothing: not to the VARCHAR or NUMBER a text or numeric function reads, and not to the VARIANT the semi-structured surface reads — so live refuses it in both families at COMPILE time. Measured over a populated GEOGRAPHY column and a GEOMETRY column in the same table: UPPER(g) is "Invalid argument types for function 'UPPER': (GEOGRAPHY)", SUM(g) names 'SUM', MEDIAN(g) is "incompatible types: [GEOGRAPHY] and [NUMBER(9,0)]", STDDEV(g) reports its internal "'*': (GEOGRAPHY, GEOGRAPHY)", ARRAY_CONSTRUCT(g) is "does not support GEOGRAPHY argument type" and TO_VARCHAR(g) is the conversion sentence. Frostlake used to accept every one of them and answer from the GeoJSON text, so UPPER(g) upper-cased the JSON KEYS and SUM(g) returned a number.

      The DEFAULT is the UNION of the two semi-structured answers — BuiltInFunction.semiStructuredRejection(int) when it says anything, BuiltInFunction.structuredRejection(int) otherwise — because that is what the account says: a geo value is refused wherever EITHER a plain OBJECT or a merely STRUCTURED one is refused, with the same sentence and the same SQLSTATE. It reaches the right answer for the text family, the numeric family, SUM / AVG / LISTAGG / MEDIAN / the moment aggregates (through the first), and for TYPEOF, TO_JSON, IS_OBJECT, AS_VARCHAR, ARRAY_AGG, OBJECT_AGG, the constructors and TO_VARCHAR / TO_CHAR (through the second).

      It is nevertheless a FOURTH question rather than a reuse, because geo REFUSES a surface both semi-structured kinds accept, and the overriding classes say so one at a time: live, HASH_AGG(o), MAX_BY(o, n), APPROX_COUNT_DISTINCT(o), GET(o, 'k'), OBJECT_KEYS(o), ARRAY_SIZE(o), OBJECT_INSERT(o, 'a', 1), PARSE_JSON, GREATEST(o, o), LEAST(o, o) and EQUAL_NULL(o, o) all return a value over an OBJECT and are argument-type errors over a GEOGRAPHY.

      What a geo value does NOT get is a rejection where it is carried rather than read: live, SELECT DISTINCT g, COUNT(g), COUNT(DISTINCT g), ANY_VALUE(g), HASH(g), FIRST_VALUE / LAST_VALUE, IFF / COALESCE / NVL / IFNULL / NVL2 / DECODE / CASE, the set operators and TO_GEOGRAPHY / TO_GEOMETRY all take one.

      The default is NONE for an unmeasured function, for the same reason as the other three: undeclared means unconstrained.

      Overrides:
      geoRejection in class BuiltInFunction
      Parameters:
      position - the zero-based argument position being asked about
      Returns:
      the refusal this position gives a GEOGRAPHY or GEOMETRY value; by default, the union of the two semi-structured answers