public class PivotNamespace extends AbstractNamespace
A PIVOT transforms rows into columns using an aggregate function:
SELECT ... FROM source_table PIVOT (aggregate_function(value_column) FOR pivot_column IN (val1, val2, ...)) AS alias
The PIVOT produces:
For column resolution purposes:
| Modifier and Type | Field and Description |
|---|---|
static String |
PIVOT_TABLE_SUFFIX
Display name format for PIVOT table
|
static String |
UNPIVOT_TABLE_SUFFIX
Display name format for UNPIVOT table
|
columnSources, columnSourcesWithRefs, guessColumnStrategy, nameMatcher, node, referenceTraceabilityEnabled, validated| Constructor and Description |
|---|
PivotNamespace(TTable pivotTable,
TPivotClause pivotClause,
TTable sourceTable,
String alias,
INameMatcher nameMatcher) |
| Modifier and Type | Method and Description |
|---|---|
protected void |
doValidate()
Subclasses override this to perform actual validation logic.
|
static List<String> |
generatedColumnNames(TPivotClause pivotClause)
The names of
generatedColumns(gudusoft.gsqlparser.nodes.TPivotClause), in order, duplicates included. |
static List<String[]> |
generatedColumns(TPivotClause pivotClause)
The columns a PIVOT or UNPIVOT operator generates, in text order, each as {name, evidence, stored}, duplicates
included (this namespace keeps the first of names its matcher equates).
|
static List<Boolean> |
generatedColumnsStored(TPivotClause pivotClause)
Whether each name of
generatedColumnNames(gudusoft.gsqlparser.nodes.TPivotClause) is a stored name as written (see generatedColumns(gudusoft.gsqlparser.nodes.TPivotClause)). |
Map<String,ColumnSource> |
getAllColumnSources()
Get all column sources for this PIVOT namespace.
|
List<TTable> |
getAllFinalTables()
Get all final physical tables this namespace depends on.
|
String |
getDisplayName()
Get a display name for this namespace (for debugging/error messages)
|
TTable |
getFinalTable()
Get the final physical table this namespace represents.
|
TPivotClause |
getPivotClause()
Get the PIVOT clause.
|
Set<String> |
getPivotColumns()
Get the set of pivot column names (from IN clause).
|
TTable |
getPivotTable()
Get the pivot table.
|
INamespace |
getSourceNamespace()
Get the namespace representing the source table.
|
TTable |
getSourceTable()
Get the TTable that this namespace is associated with.
|
TTable |
getUnderlyingSourceTable()
Get the underlying table that PIVOT operates on.
|
ColumnLevel |
hasColumn(String columnName)
Check if a column exists in this namespace.
|
static String |
inListItemAlias(TResultColumn resultColumn)
The explicit alias of one PIVOT IN-list item, or null when it has none.
|
static String |
inListItemColumnName(TResultColumn resultColumn)
The name a PIVOT IN-list item gives its generated column: its alias (
inListItemAlias(gudusoft.gsqlparser.nodes.TResultColumn)), else the name
its value gives (inListValueColumnName(gudusoft.gsqlparser.EDbVendor, java.lang.String)). |
static boolean |
inListItemStored(TResultColumn resultColumn)
Whether the name of an IN-list item is its value's literal as written, a stored name (see generatedColumns).
|
static String |
inListValueColumnName(EDbVendor vendor,
String rawValue)
The name a PIVOT gives to the column generated by one unaliased IN-list value.
|
boolean |
isPivotColumn(String columnName)
Check if a column is a pivot column (from IN clause).
|
boolean |
isUnpivot()
Check if this is an UNPIVOT namespace.
|
ColumnSource |
resolveColumn(String columnName)
Resolve a column name to its source.
|
void |
setSourceNamespace(INamespace sourceNamespace)
Set the namespace representing the source table.
|
static String |
stripDelimitersFrom(String name)
Strip a leading+trailing quote pair.
|
String |
toString() |
addColumnSource, addColumnSource, containsColumnByMatcher, containsColumnNameByMatcher, enableReferenceTraceability, ensureValidated, findColumnKeyByMatcher, getAllUniqueColumns, getColumnReferences, getColumnSourceWithReferences, getGuessColumnStrategy, getNameMatcher, getNode, isReferenceTraceabilityEnabled, isValidated, noteColumnSourceAdded, setGuessColumnStrategy, validateclone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitaddInferredColumn, getInferredColumns, getMetadataState, getSelectStatement, getStarColumn, hasAuthoritativeOutputColumn, hasStarColumn, resolveColumnPath, supportsDynamicInferencepublic static final String PIVOT_TABLE_SUFFIX
public static final String UNPIVOT_TABLE_SUFFIX
public PivotNamespace(TTable pivotTable, TPivotClause pivotClause, TTable sourceTable, String alias, INameMatcher nameMatcher)
public boolean isUnpivot()
public void setSourceNamespace(INamespace sourceNamespace)
public INamespace getSourceNamespace()
public TTable getPivotTable()
public TTable getUnderlyingSourceTable()
public TTable getSourceTable()
public TPivotClause getPivotClause()
public Set<String> getPivotColumns()
public boolean isPivotColumn(String columnName)
public String getDisplayName()
INamespacepublic TTable getFinalTable()
INamespacepublic List<TTable> getAllFinalTables()
INamespacegetAllFinalTables in interface INamespacegetAllFinalTables in class AbstractNamespaceprotected void doValidate()
AbstractNamespacedoValidate in class AbstractNamespacepublic static List<String[]> generatedColumns(TPivotClause pivotClause)
stored is non-null when the
name is the column's stored name as written, an IN value of a vendor that names the column after the literal
(inListValueColumnName(gudusoft.gsqlparser.EDbVendor, java.lang.String)): it is looked up by its delimited spelling, never folded as an unquoted
identifier (IN ('direct') is referenced as "'direct'", not as "'DIRECT'").
UNPIVOT: its value columns, then its FOR columns. PIVOT: the names of an alias column list (AS p
(a, b)), which replace the generated names, else one name per IN item (inListItemAlias(gudusoft.gsqlparser.nodes.TResultColumn), else the
value: inListValueColumnName(gudusoft.gsqlparser.EDbVendor, java.lang.String)), the columns of an IN subquery, the values of an IN value list.
The one rule for the names a pivot generates: this namespace resolves by it, and the SQL-LR producer
publishes by it (TPivotClause.getGeneratedColumnNames(), plan 09 slice 10), so a name is never
published under one spelling and looked up under another.
public static List<String> generatedColumnNames(TPivotClause pivotClause)
generatedColumns(gudusoft.gsqlparser.nodes.TPivotClause), in order, duplicates included.public static List<Boolean> generatedColumnsStored(TPivotClause pivotClause)
generatedColumnNames(gudusoft.gsqlparser.nodes.TPivotClause) is a stored name as written (see generatedColumns(gudusoft.gsqlparser.nodes.TPivotClause)).public static String inListItemColumnName(TResultColumn resultColumn)
inListItemAlias(gudusoft.gsqlparser.nodes.TResultColumn)), else the name
its value gives (inListValueColumnName(gudusoft.gsqlparser.EDbVendor, java.lang.String)). The pre-resolver2 path (TPivotInClause.linkColumnToTable)
publishes by it too.public static boolean inListItemStored(TResultColumn resultColumn)
public static String inListItemAlias(TResultColumn resultColumn)
IN ('direct' AS Store) names the generated column Store.
Oracle, Snowflake, BigQuery and Teradata all accept this form and in every one
of them the alias — not the value — is the output column name, so it takes
precedence over any value-derived naming.
Shared with ScopeBuilder.addPivotInClauseColumns and matched by
TPivotInClause.linkColumnToTable on purpose. The name a pivot column
is published under and the name it can be resolved by have
to be produced by the same rule, or a reference to the real column reports
NOT_FOUND while a stale name still matches.
The alias is returned verbatim, quote state included. Stripping it
would be wrong in both directions for IN ('x' AS "Store"): bare
SELECT Store would become a false exact match, and the only valid
reference, SELECT "Store", would report NOT_FOUND. Retaining quote
state is what the identifier normalization guide requires; comparison is the
matcher's job, not this method's.
public static String inListValueColumnName(EDbVendor vendor, String rawValue)
Vendor-specific, and the difference is not cosmetic. Oracle, Snowflake and
Teradata name the column after the literal as written, quotes included, so
IN ('direct') yields a column really named 'direct' that must
be referenced as "'direct'" (Mantis 4662; that name is stored as written,
so it is looked up by its delimited spelling: generatedColumns(gudusoft.gsqlparser.nodes.TPivotClause)). BigQuery requires its
IN-list values to form valid identifiers and names the column direct,
so the quotes are still stripped there and for every other vendor.
Shared with ScopeBuilder for the same reason as
inListItemAlias(gudusoft.gsqlparser.nodes.TResultColumn).
public static String stripDelimitersFrom(String name)
public ColumnLevel hasColumn(String columnName)
INamespacehasColumn in interface INamespacehasColumn in class AbstractNamespacecolumnName - Column name to checkpublic ColumnSource resolveColumn(String columnName)
INamespaceresolveColumn in interface INamespaceresolveColumn in class AbstractNamespacecolumnName - Column name to resolvepublic Map<String,ColumnSource> getAllColumnSources()
For PIVOT, the output columns are:
This method is critical for star column expansion: when outer query uses SELECT * from a PIVOT table, we need to return ALL columns the pivot table exposes.
getAllColumnSources in interface INamespacegetAllColumnSources in class AbstractNamespacepublic String toString()
toString in class AbstractNamespace