Pavel Pereslegin created IGNITE-24560:
-----------------------------------------

             Summary: Sql. Result of script parsing with single statement is 
cached incorrectly
                 Key: IGNITE-24560
                 URL: https://issues.apache.org/jira/browse/IGNITE-24560
             Project: Ignite
          Issue Type: Bug
            Reporter: Pavel Pereslegin


Reproducer
{code;Java}
    @Test
    public void testScriptSingleStatement() {
        sql("create table test(id int primary key, val int)");
        igniteSql().executeScript("select * from test;");
        sql("alter table test drop column val");
        igniteSql().executeScript("select * from test;"); // Column 'VAL' not 
found in table 'TEST
    }
{code}

Error output
{noformat}
Caused by: org.apache.calcite.runtime.CalciteContextException: At line 1, 
column 8: Column 'VAL' not found in table 'TEST'
        at 
java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
        at 
org.apache.calcite.runtime.Resources$ExInstWithCause.ex(Resources.java:511)
        at org.apache.calcite.sql.SqlUtil.newContextException(SqlUtil.java:952)
        at org.apache.calcite.sql.SqlUtil.newContextException(SqlUtil.java:937)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.newValidationError(SqlValidatorImpl.java:5899)
        at 
org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator.newValidationError(IgniteSqlValidator.java:291)
        at 
org.apache.calcite.sql.validate.DelegatingScope.fullyQualify(DelegatingScope.java:473)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl$Expander.visit(SqlValidatorImpl.java:7105)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl$SelectExpander.visit(SqlValidatorImpl.java:7276)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl$SelectExpander.visit(SqlValidatorImpl.java:7261)
        at org.apache.calcite.sql.SqlIdentifier.accept(SqlIdentifier.java:324)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl$Expander.go(SqlValidatorImpl.java:7094)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.expandSelectExpr(SqlValidatorImpl.java:6665)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.expandSelectItem(SqlValidatorImpl.java:481)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.validateSelectList(SqlValidatorImpl.java:5015)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.validateSelect(SqlValidatorImpl.java:4096)
        at 
org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator.validateSelect(IgniteSqlValidator.java:684)
        at 
org.apache.calcite.sql.validate.SelectNamespace.validateImpl(SelectNamespace.java:62)
        at 
org.apache.calcite.sql.validate.AbstractNamespace.validate(AbstractNamespace.java:95)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.validateNamespace(SqlValidatorImpl.java:1206)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.validateQuery(SqlValidatorImpl.java:1177)
        at org.apache.calcite.sql.SqlSelect.validate(SqlSelect.java:282)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.validateScopedExpression(SqlValidatorImpl.java:1143)
        at 
org.apache.calcite.sql.validate.SqlValidatorImpl.validate(SqlValidatorImpl.java:849)
        at 
org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator.validate(IgniteSqlValidator.java:194)
        at 
org.apache.ignite.internal.sql.engine.prepare.IgnitePlanner.validateAndGetTypeMetadata(IgnitePlanner.java:303)
        at 
org.apache.ignite.internal.sql.engine.prepare.PrepareServiceImpl.lambda$prepareQuery$3(PrepareServiceImpl.java:389)
        at 
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1700)
{noformat}

This happened because we redirect the script execution workflow to normal 
execution (not multi-statement), but the AST tree in the cache remains a 
modified after validation.

E.g. 

for single statement execution we generating AST each time.

{code:Java}
ParsedResult result = new ParsedResultImpl(
                queryType,
                query,
                normalizedQuery,
                parsedStatement.dynamicParamsCount(),
                () -> {
                    // Descendants of SqlNode class are mutable, thus we must 
use every
                    // syntax node only once to avoid problem. But we already 
parsed the
                    // query once to get normalized result. An `unparse` 
operation is known
                    // to be safe, so let's reuse result of parsing for the 
first invocation
                    // of `parsedTree` method to avoid double-parsing for one 
time queries.
                    SqlNode ast = holder.getAndSet(null);

                    if (ast != null) {
                        return ast;
                    }

                    return IgniteSqlParser.parse(query, 
StatementParseResult.MODE).statement();
                }
{code}

but for multi-statement (currently) we using the same ast node

{code:Java}
            results.add(new ParsedResultImpl(
                    queryType,
                    normalizedQuery,
                    normalizedQuery,
                    result.dynamicParamsCount(),
                    () -> parsedTree
            ));
{code}

And this is ok, but not for the case when the parsing result is placed in the 
cache.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to