public final class QualifiedCanonKey extends Object
db.schema.table,
schema.table.column, t.c — for use as a map or set key
(stage S0 of docs/refactor/identifier_identity_display_separation_plan.md).
It is the qualified counterpart of CanonKey: one CanonKey per
hierarchy level, each computed under the rules of that level's object type, plus
the terminal object type itself so that a table named x and a schema named
x cannot collide in one index. CanonKey carries an
IdentifierProfile.ObjectGroup, which is the right granularity for comparing
identifiers but deliberately coarser than the entity kind — hence the explicit terminal
discriminator here.
There is no flattened identity string. The previous approach,
IdentifierService.buildCompositeKey(String, ESQLDataObjectType), joins
already-normalized segment text; it cannot represent quote state, and its guard
IdentifierService.canUseCompositeKey(String) refuses every name containing a
quote character — which is exactly the case that loses lineage (MantisBT 4728). Joining
canonical segments back into a String would reintroduce both problems, so this
type keeps the segment keys as a list and nothing renders them.
CanonKeys. Since CanonKey equality IS the canonical
single-segment equality relation (unification-plan stage P0d.1), each LEVEL compares correctly.
That does not make the whole key agree with
SQLUtil.compareIdentifier(gudusoft.gsqlparser.EDbVendor, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType, java.lang.String, java.lang.String), and it does not make it correct.
Two things are still decided outside the per-level comparison: how the name is split into
segments, and which object type each position is compared as. The S0 proof test measures the
agreement over every vendor, every mapped object type and every ordered pair of shapes, and
pins each divergence with its cause — but agreement with compareIdentifier is not
proof of correctness, because both can be wrong together.
They ARE wrong together in one known case, which this type cannot currently fix: the role of
each position is inferred from the vendor, the terminal type and the arity alone. For a
two-segment column name that guesses table.column, but BigQuery
customer.name is a STRUCT field access — base column customer plus field
name (see FieldPath and TestBigQueryNestedColumns) — and the two read
the first segment under different case rules. Fixing it needs an explicit semantic role per
component, taken from resolution rather than from syntax; that is scheduled before S2 and is
why compareIdentifier must NOT be made to delegate to the planner first.
IdentifierService.qualifiedCanonKeyFromLexical(String, ESQLDataObjectType) —
for a name as written in SQL — or
IdentifierService.qualifiedCanonKeyFromStored(java.util.List, ESQLDataObjectType) — for
a name already in the form a catalog stores, passed as one entry per level. The two are not interchangeable: keying a
Snowflake catalog object from an already-decoded foo is not the same as keying
the SQL lexical "foo". There is deliberately no factory that guesses.
In-process only, for the same reason as CanonKey: collation
payloads are stable only within one JVM and collator configuration. Use
PersistentIdentifierKey for anything persisted or exchanged.
| Modifier and Type | Method and Description |
|---|---|
boolean |
equals(Object o) |
CanonKey |
getLeafKey()
The key of the innermost level — the column of
t.c, the table of
s.t. |
List<CanonKey> |
getSegmentKeys()
The per-level canonical keys, outermost container first.
|
ESQLDataObjectType |
getTerminalType()
The kind of object the whole name denotes — the entity-kind discriminator.
|
EDbVendor |
getVendor()
The vendor rule domain; all levels share it.
|
int |
hashCode() |
int |
size()
Number of hierarchy levels this name resolved to.
|
String |
toString() |
public List<CanonKey> getSegmentKeys()
public ESQLDataObjectType getTerminalType()
public int size()
public CanonKey getLeafKey()
t.c, the table of
s.t. Useful for indexes that bucket by container and then by leaf name.