[ 
https://issues.apache.org/jira/browse/CALCITE-7792?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Sean Broeder updated CALCITE-7792:
----------------------------------
    Summary: Failed namespace validation breaks SqlAdvisorValidator hints and 
can overflow the stack in getRowType()  (was: Failed namespace validation 
leaves rowType null and causes stack overflow in getRowType())

> Failed namespace validation breaks SqlAdvisorValidator hints and can overflow 
> the stack in getRowType()
> -------------------------------------------------------------------------------------------------------
>
>                 Key: CALCITE-7792
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7792
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.42.0
>            Reporter: Sean Broeder
>            Assignee: Sean Broeder
>            Priority: Major
>              Labels: pull-request-available
>
> The finally block in AbstractNamespace.validate() sets the status to VALID 
> even when validateImpl() throws. That leaves rowType null. A later 
> getRowType() on the same namespace calls validateNamespace(), which does 
> nothing because the status is already VALID. validateNamespace() then calls 
> getType(), which calls getRowType() again. The result is a StackOverflowError 
> in place of the original error.
> For example:
> {code:java}
> select * from (select bad_col from emp) as t
> {code}
> Validating this throws "Column 'BAD_COL' not found in any table" the first 
> time, as expected. But a second, independent getRowType() call on the inner 
> SELECT's namespace then throws StackOverflowError instead of re-surfacing 
> that error.
> Ordinary SQL through a single validate() call does not hit this. It needs a 
> caller that catches the exception and keeps going, such as a validator 
> extension that probes a namespace and treats failure as "no match", or code 
> that asks for a namespace's type after a failed validation. 
> SqlAdvisorValidator is such a caller, because it validates incomplete SQL and 
> must tolerate namespaces that fail.
> SqlAdvisorValidator catches CalciteException and continues, but it does not 
> overflow. Its activeNamespaces guard treats any repeat call to 
> validateNamespace() as a cycle and sets an empty struct type. That hides the 
> overflow, but it also gives wrong results. 
> For example:
> {code:java}
> select ename from (select ?, ename from emp) 
> {code}
> returns no completion hints, where COLUMN(ENAME) is expected.
> Setting the status back to UNVALIDATED on failure is not enough. 
> validateImpl() may already have changed shared validator state, so entering 
> it a second time is unsafe. Instead, store the exception and mark the 
> namespace VALID. A later getRowType() or getType() re-throws the original 
> error.
> In SqlAdvisorValidator:
>  - Remove the activeNamespaces guard. It treated any repeat call to 
> validateNamespace() as a cycle, but AbstractNamespace already handles repeat 
> calls through its own status field.
>  - validateNamespace() masks CalciteException and falls back to an empty 
> struct type.
>  - Override inferUnknownTypes() and checkRollUp() to swallow 
> CalciteException, so one unresolvable item doesn't abort validation of the 
> whole enclosing namespace. SqlValidatorImpl.checkRollUp() becomes protected 
> for this.
> The namespace's cycle check throws AssertionError, which the advisor does not 
> mask.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to