You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@ignite.apache.org by "Pavel Pereslegin (Jira)" <ji...@apache.org> on 2025/02/19 07:38:00 UTC

[jira] [Created] (IGNITE-24560) Sql. Result of script parsing with single statement is cached incorrectly

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)