protected void validateSelect ( SqlSelect select , RelDataType targetRowType ) { assert targetRowType != null ; // Namespace is either a select namespace or a wrapper around one. final SelectNamespace ns = getNamespace ( select ) . unwrap ( SelectNamespace . class ) ; // Its rowtype is null, meaning it hasn't been validated yet. // This is important, because we need to take the targetRowType into // account. assert ns . rowType == null ; if ( select . isDistinct ( ) ) { validateFeature ( RESOURCE . sQLFeature_E051_01 ( ) , select . getModifierNode ( SqlSelectKeyword . DISTINCT ) . getParserPosition ( ) ) ; } final SqlNodeList selectItems = select . getSelectList ( ) ; RelDataType fromType = unknownType ; if ( selectItems . size ( ) == 1 ) { final SqlNode selectItem = selectItems . get ( 0 ) ; if ( selectItem instanceof SqlIdentifier ) { SqlIdentifier id = ( SqlIdentifier ) selectItem ; if ( id . isStar ( ) && ( id . names . size ( ) == 1 ) ) { // Special case: for INSERT ... VALUES(?,?), the SQL // standard says we're supposed to propagate the target // types down. So iff the select list is an unqualified // star (as it will be after an INSERT ... VALUES has been // expanded), then propagate. fromType = targetRowType ; } } } // Make sure that items in FROM clause have distinct aliases. final SelectScope fromScope = ( SelectScope ) getFromScope ( select ) ; List < String > names = fromScope . getChildNames ( ) ; if ( ! catalogReader . nameMatcher ( ) . isCaseSensitive ( ) ) { names = Lists . transform ( names , s -> s . toUpperCase ( Locale . ROOT ) ) ; } final int duplicateAliasOrdinal = Util . firstDuplicate ( names ) ; if ( duplicateAliasOrdinal >= 0 ) { final ScopeChild child = fromScope . children . get ( duplicateAliasOrdinal ) ; throw newValidationError ( child . namespace . getEnclosingNode ( ) , RESOURCE . fromAliasDuplicate ( child . name ) ) ; } if ( select . getFrom ( ) == null ) { if ( conformance . isFromRequired ( ) ) { throw newValidationError ( select , RESOURCE . selectMissingFrom ( ) ) ; } } else { validateFrom ( select . getFrom ( ) , fromType , fromScope ) ; } validateWhereClause ( select ) ; validateGroupClause ( select ) ; validateHavingClause ( select ) ; validateWindowClause ( select ) ; handleOffsetFetch ( select . getOffset ( ) , select . getFetch ( ) ) ; // Validate the SELECT clause late, because a select item might // depend on the GROUP BY list, or the window function might reference // window name in the WINDOW clause etc. final RelDataType rowType = validateSelectList ( selectItems , select , targetRowType ) ; ns . setType ( rowType ) ; // Validate ORDER BY after we have set ns.rowType because in some // dialects you can refer to columns of the select list, e.g. // "SELECT empno AS x FROM emp ORDER BY x" validateOrderList ( select ) ; if ( shouldCheckForRollUp ( select . getFrom ( ) ) ) { checkRollUpInSelectList ( select ) ; checkRollUp ( null , select , select . getWhere ( ) , getWhereScope ( select ) ) ; checkRollUp ( null , select , select . getHaving ( ) , getHavingScope ( select ) ) ; checkRollUpInWindowDecl ( select ) ; checkRollUpInGroupBy ( select ) ; checkRollUpInOrderBy ( select ) ; } }
Validates a SELECT statement .