Skip to content

[BUG] UnifiedQueryPlanner fails when planning join queries #4910

Description

@lostella

What is the bug?

When UnifiedQueryPlanner.plan is run against a PPL query that contain join commands, planning fails. From the stack trace, it seems related to a Settings property not being initialized.

java.lang.NullPointerException: Cannot invoke "org.opensearch.sql.common.setting.Settings.getSettingValue(org.opensearch.sql.common.setting.Settings$Key)" because "this.settings" is null
            at org.opensearch.sql.ppl.parser.AstBuilder.validateJoinType(AstBuilder.java:345)
            at org.opensearch.sql.ppl.parser.AstBuilder.visitJoinCommand(AstBuilder.java:277)
            at org.opensearch.sql.ppl.parser.AstBuilder.visitJoinCommand(AstBuilder.java:133)
            at org.opensearch.sql.ppl.antlr.parser.OpenSearchPPLParser$JoinCommandContext.accept(OpenSearchPPLParser.java:11128)
            at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visitChildren(AbstractParseTreeVisitor.java:46)
            at org.opensearch.sql.ppl.antlr.parser.OpenSearchPPLParserBaseVisitor.visitCommands(OpenSearchPPLParserBaseVisitor.java:76)
            at org.opensearch.sql.ppl.antlr.parser.OpenSearchPPLParser$CommandsContext.accept(OpenSearchPPLParser.java:1099)
            at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:18)
[...]

How can one reproduce the bug?

Save the following snippet into api/src/test/java/org/opensearch/sql/api/JoinTest.java

Run ./gradlew :api:test

package org.opensearch.sql.api;

import java.util.List;
import java.util.Map;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.schema.Table;
import org.apache.calcite.schema.impl.AbstractSchema;
import org.apache.calcite.schema.impl.AbstractTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.junit.Test;
import org.opensearch.sql.executor.QueryType;

public class JoinTest {

    static class TestSchema extends AbstractSchema {

        private Table newTableWithId() {
            return new AbstractTable() {
                @Override
                public RelDataType getRowType(RelDataTypeFactory typeFactory) {
                    return typeFactory.createStructType(
                        List.of(typeFactory.createSqlType(SqlTypeName.INTEGER)),
                        List.of("id")
                    );
                }
            };
        }

        @Override
        protected Map<String, Table> getTableMap() {
            return Map.of(
                "users",
                newTableWithId(),
                "transactions",
                newTableWithId()
            );
        }
    }

    static UnifiedQueryPlanner planner = UnifiedQueryPlanner.builder()
        .language(QueryType.PPL)
        .catalog("opensearch", new TestSchema())
        .defaultNamespace("opensearch")
        .cacheMetadata(true)
        .build();

    // This test PASSES
    @Test
    public void testSimpleQueries() {
        planner.plan("source=users | where id > 42");
        planner.plan("source=transactions | stats avg(id)");
    }

    // This test FAILS
    @Test
    public void testJoinQuery() {
        planner.plan(
            "source=users | join on users.id = transactions.id transactions"
        );
    }
}

What is the expected behavior?
I would expect all tests to pass.

What is your host/environment?

=======================================
OpenSearch Build Hamster says Hello!
  Gradle Version        : 9.2.0
  OS Info               : Mac OS X 15.6.1 (aarch64)
  JDK Version           : 25 (Homebrew JDK 25 (25.0.1))
  JAVA_HOME             : /opt/homebrew/Cellar/openjdk/25.0.1/libexec/openjdk.jdk/Contents/Home
  Random Testing Seed   : 22E77A93290BA004
  Crypto Standard       : any-supported
=======================================

Do you have any screenshots?
N/A

Do you have any additional context?
I am trying to use the UnifiedQueryPlanner class to validate correctness (to some degree) of auto-generated PPL queries.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions