Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
bc169b4
Revert "[Feature] Add PPL `rest` command" (#5635)
noCharger Jul 17, 2026
e5a0bc3
[Feature] Add PPL `makeresults` command (#5622)
noCharger Jul 20, 2026
29c7ecb
Fix foreach JSON array type coercion (#5637)
songkant-aws Jul 20, 2026
daf6afd
Support constant_keyword field type in PPL (#5639)
penghuo Jul 21, 2026
6d3c58d
Xyseries command implementation (#5343)
asifabashar Jul 21, 2026
7c430dd
Decouple Calcite PPL planning from ExprType (#5633)
penghuo Jul 22, 2026
2b329a7
Anonymize xyseries command and mark it experimental in docs (#5643)
penghuo Jul 22, 2026
fff8c42
Add release notes for 3.8.0 (#5644)
opensearch-ci-bot Jul 23, 2026
9368cb5
[BUG] PPL `LIKE` function: no way to escape the escape character (`\`…
AjimelecGonzalez Jul 23, 2026
47149f0
Surface PIT-context exhaustion with an actionable error message (#5631)
ahkcs Jul 24, 2026
f09ab9b
Overriding profile endpoint with analyze endpoint with operator tree …
Krish-Gandhi Jul 24, 2026
a54acb4
Remove reverted rest command from 3.8 release notes (#5654) (#5655)
opensearch-ci-bot Jul 24, 2026
e905aec
feat: complex query thread pool (#5628)
Swiddis Jul 28, 2026
de95ffb
Detect integral SUM overflow and fix BIGINT AVG (#5612)
ahkcs Jul 30, 2026
d5a182d
Push down aggregation on text field without .keyword sub-field (#5646)
penghuo Jul 31, 2026
2852724
Add ci.opensearch.org/m2/ mirror for plugin resolution (sql) (#5664) …
opensearch-ci-bot Jul 31, 2026
79d532d
Add ci.opensearch.org/m2/ mirror to buildscript and project repos (sq…
peterzhuamazon Aug 1, 2026
8ca47ac
Add a generic, extensible rest-endpoint provider SPI (#5656)
noCharger Aug 4, 2026
2d1256f
[Feature] `percentfield` and `showperc` with `top` and `rare` command…
AjimelecGonzalez Aug 4, 2026
f4ede11
Accept plain Calcite types against UDT operand signatures (#5675)
ahkcs Aug 4, 2026
33b703d
feat(ci): add PPL lint rule validation check (eventstats PoC)
Jul 19, 2026
8b5b3b1
style(ci): use $(...) instead of legacy backticks in ppl-lint workflow
Jul 20, 2026
4bc258e
ci: re-trigger PPL lint rule validation after Actions recovery
Jul 20, 2026
6dd18d0
fix(ci): split ppl-lint validation into frontend/backend jobs
Jul 20, 2026
71eb0e7
feat(ci): extend PPL lint contract to all reachable rules (schema v2)
Jul 20, 2026
930bfe5
feat(ci): reconnect PPL lint validation to candidate runtime grammar
Jul 20, 2026
5e93167
fix(ci): pipefail so detector runner failure is not masked by tee
Jul 20, 2026
d76c286
feat(ci): allow workflow_dispatch to validate against an OSD fork
Jul 21, 2026
5806d20
fix(ci): resolve OSD target via repo variables so PR check can valida…
Jul 22, 2026
49d27f5
ci(ppl-lint): document sibling-workflow reuse; harden detector job
Jul 22, 2026
b4f05c0
test(ppl-lint): add invalid-capture-group-name validation contract
Jul 25, 2026
c435267
feat(ci): validate default-error PPL lint rules across engine versions
Jul 25, 2026
f825f3f
fix(ci): stop the multi-version lint check from passing vacuously
Jul 25, 2026
809c031
fix(ci): forward ppl.lint.* system properties to the test JVM by prefix
Jul 26, 2026
935a8f1
test(ppl-lint): pin per-version rejection shapes observed on 3.6 and 3.7
Jul 26, 2026
458e8de
fix(ci): treat a missing version expectation as an observation, not a…
Jul 26, 2026
cbaf909
fix(ci): do not report an unsupported command as a too-narrow version…
Jul 26, 2026
6988ece
fix(ci): apply the unobserved-verdict rule to the out-of-scope path too
Jul 26, 2026
4f6cf24
test(ci): TEMPORARY drift probe — do not merge
Jul 27, 2026
91fa87d
Revert "test(ci): TEMPORARY drift probe — do not merge"
Jul 27, 2026
596398f
feat(ci): surface PPL lint drift as GitHub annotations
Jul 27, 2026
cfe378b
feat(ci): validate the compiled-simplified lint surface too
Jul 27, 2026
e0c8421
feat(ci): add compiled-surface legs for engines below the grammar floor
Jul 27, 2026
79bb36b
fix(ci): stop the index wipe racing plugin initialization
Jul 27, 2026
1dbeea4
test(ci): probe the framework's startup requests on a compiled leg
Jul 27, 2026
5780fda
test(ci): probe HTTP/2 negotiation on a pre-3.x engine
Jul 27, 2026
a6ccce5
fix(test): pin the REST test client to HTTP/1.1
Jul 27, 2026
7ea51cf
fix(ci): tell a partial engine fix from a full one before advising ve…
Jul 27, 2026
044c832
feat(ci): harvest a discovery corpus so trigger coverage can support …
Jul 27, 2026
84f551c
feat(ci): harvest each test file's lint context so context-gated rule…
Jul 27, 2026
d5900c8
fix(test): write the target manifest even without a grammar bundle
Jul 27, 2026
cf551e9
fix(ci): run discovery on the runtime-bundle surface, not only the co…
Jul 27, 2026
8437efa
test(ppl-lint): add a second trigger to every enforced contract that …
Jul 27, 2026
7fa1bdb
test(ci): probe REST client connectivity from a JVM
Jul 27, 2026
ca2aeb6
test(ppl-lint): run the whole contract corpus on every PR, not just t…
Jul 27, 2026
719cc46
fix(ci): make the connectivity probe actually run
Jul 27, 2026
cdf730f
fix(ppl-lint): scope the trigger differential to rules the engine act…
Jul 27, 2026
c3bee56
fix(test): make the connectivity probe discoverable
Jul 27, 2026
624933c
test(ci): validate the latest patch of each line, and probe client va…
Jul 27, 2026
b64d2f3
fix(test): tolerate a pre-Calcite engine in observe-only mode
Jul 27, 2026
d8a70b1
fix(test): skip the whole Calcite settings family on a pre-Calcite en…
Jul 27, 2026
e7ce252
revert(test): un-pin the REST client from HTTP/1.1
Jul 27, 2026
4bdd246
test(ppl-lint): pin dense_rank's 3.7 rejection wording
Jul 27, 2026
39a9c79
feat(ci): observe PPL lint contracts on analytics engine
Jul 28, 2026
0cd55a6
fix(ci): follow current analytics artifact names
Jul 28, 2026
0c8ae23
fix(ci): harden analytics lint observation
Jul 28, 2026
7126c6a
fix(ci): resolve analytics lint contracts
Jul 28, 2026
92dc0bb
fix(ci): support append-only analytics fixtures
Jul 28, 2026
946f19e
test(analytics): preserve bulk separators
Jul 28, 2026
d9739e8
feat(ci): validate approved 13-rule PPL lint catalog
Aug 4, 2026
c3af7ef
feat(ci): enforce exact PPL lint frontend contracts
Aug 4, 2026
72a8b9e
fix(ci): isolate PPL lint contract failures
Aug 4, 2026
e3fef68
test(ci): prove PPL lint fault isolation
Aug 4, 2026
1394b18
fix(ci): publish compatibility report before drift failure
Aug 4, 2026
f59c89d
fix(ci): verify compatibility matrix leg identities
Aug 4, 2026
f697b39
feat(ci): validate PPL lint across grammar surfaces
Aug 4, 2026
f09ce71
chore(ci): label PPL workflows as linter checks
Aug 5, 2026
4381c28
docs(ci): align PPL compatibility design with workflow
Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
491 changes: 491 additions & 0 deletions .github/workflows/ppl-lint-multiversion-validation.yml

Large diffs are not rendered by default.

385 changes: 385 additions & 0 deletions .github/workflows/ppl-lint-rule-validation.yml

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ src/site-server/node_modules
build/
gen/
*.tokens
.attach_pid*

# various IDE files
.vscode
Expand Down Expand Up @@ -59,4 +60,13 @@ http-client.env.json
!.claude/harness/
.claude/settings.local.json
.clinerules
memory-bank
memory-bank

# PPL lint rule validation contract run artifacts (uploaded in CI, not committed)
backend-report.json
backend-report-nightly.json
detector-report.json
detector-contract.log
ppl-grammar-bundle.json
target.json
run-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ SELECT department, SUM(age) AS total FROM catalog.employees GROUP BY department
.assertPlan(
"""
LogicalProject(department=[$0], total=[$1])
LogicalAggregate(group=[{0}], SUM(age)=[SUM($1)])
LogicalAggregate(group=[{0}], SUM(age)=[CHECKED_LONG_SUM($1)])
LogicalProject(department=[$3], age=[$2])
LogicalTableScan(table=[[catalog, employees]])
""");
Expand Down Expand Up @@ -366,7 +366,7 @@ SELECT department, SUM(age) FILTER(WHERE age > 30) FROM catalog.employees
""")
.assertPlan(
"""
LogicalAggregate(group=[{0}], SUM(age) FILTER(WHERE age > 30)=[SUM($1) FILTER $2])
LogicalAggregate(group=[{0}], SUM(age) FILTER(WHERE age > 30)=[CHECKED_LONG_SUM($1) FILTER $2])
LogicalProject(department=[$3], age=[$2], $f3=[>($2, 30)])
LogicalTableScan(table=[[catalog, employees]])
""");
Expand Down Expand Up @@ -487,7 +487,7 @@ SELECT name, SUM(age) OVER(PARTITION BY department ORDER BY age) FROM catalog.em
""")
.assertPlan(
"""
LogicalProject(name=[$1], SUM(age) OVER(PARTITION BY department ORDER BY age)=[SUM($2) OVER (PARTITION BY $3 ORDER BY $2 NULLS FIRST)])
LogicalProject(name=[$1], SUM(age) OVER(PARTITION BY department ORDER BY age)=[CHECKED_LONG_SUM($2) OVER (PARTITION BY $3 ORDER BY $2 NULLS FIRST)])
LogicalTableScan(table=[[catalog, employees]])
""");
}
Expand Down
11 changes: 7 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ buildscript {
repositories {
mavenLocal()
maven { url "https://ci.opensearch.org/maven2/" }
maven { url "https://ci.opensearch.org/m2/" }
mavenCentral()
maven { url "https://ci.opensearch.org/ci/dbc/snapshots/maven/" }
}
Expand All @@ -93,13 +94,14 @@ apply plugin: 'opensearch.java-agent'
// Repository on root level is for dependencies that project code depends on. And this block must be placed after plugins{}
repositories {
mavenLocal()
maven { url "https://ci.opensearch.org/maven2/" }
mavenCentral() // For Elastic Libs that you can use to get started coding until open OpenSearch libs are available
maven {
url 'https://jitpack.io'
content { includeGroup "com.github.babbel" }
}
maven { url "https://ci.opensearch.org/ci/dbc/snapshots/maven/" }
maven { url "https://ci.opensearch.org/maven2/" }
maven { url "https://ci.opensearch.org/m2/" }
mavenCentral()
}

spotless {
Expand Down Expand Up @@ -175,14 +177,15 @@ allprojects {
subprojects {
repositories {
mavenLocal()
maven { url "https://ci.opensearch.org/maven2/" }
mavenCentral()
maven {
url 'https://jitpack.io'
content { includeGroup "com.github.babbel" }
}
maven { url "https://ci.opensearch.org/ci/dbc/snapshots/maven/" }
maven { url "https://ci.opensearch.org/ci/dbc/snapshots/lucene/" }
maven { url "https://ci.opensearch.org/maven2/" }
maven { url "https://ci.opensearch.org/m2/" }
mavenCentral()
}

// Publish internal modules as Maven artifacts for external use, such as by opensearch-spark and opensearch-cli.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.common.error;

/**
* Raised when a query cannot proceed because it would exceed a node or cluster resource budget --
* e.g. the per-node Point-In-Time (PIT) context limit ({@code search.max_open_pit_context}). Pairs
* with {@link ErrorCode#RESOURCE_LIMIT_EXCEEDED}: the code is the machine-readable classifier while
* this type gives clients a stable, semantic name to match on. The message is the customer-facing
* {@code reason}; put the explanation and remedy in the {@link ErrorReport} details.
*/
public class ResourceLimitExceededException extends RuntimeException {

public ResourceLimitExceededException(String message) {
super(message);
}

public ResourceLimitExceededException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public enum Key {
PPL_SYNTAX_LEGACY_PREFERRED("plugins.ppl.syntax.legacy.preferred"),
PPL_SUBSEARCH_MAXOUT("plugins.ppl.subsearch.maxout"),
PPL_JOIN_SUBSEARCH_MAXOUT("plugins.ppl.join.subsearch_maxout"),
PPL_REST_REDACTION_ENABLED("plugins.ppl.rest.redaction.enabled"),
PPL_REST_ALLOWED_ENDPOINTS("plugins.ppl.rest.allowed_endpoints"),

/** Enable Calcite as execution engine */
Expand Down Expand Up @@ -81,7 +80,10 @@ public enum Key {
ASYNC_QUERY_EXTERNAL_SCHEDULER_INTERVAL(
"plugins.query.executionengine.async_query.external_scheduler.interval"),
STREAMING_JOB_HOUSEKEEPER_INTERVAL(
"plugins.query.executionengine.spark.streamingjobs.housekeeper.interval");
"plugins.query.executionengine.spark.streamingjobs.housekeeper.interval"),

/** Thread Pool Settings. */
SQL_COMPLEX_WORKER_POOL_ENABLED("plugins.sql.complex_worker_pool.enabled");

@Getter private final String keyValue;

Expand Down
12 changes: 12 additions & 0 deletions core/src/main/java/org/opensearch/sql/analysis/Analyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.opensearch.sql.ast.tree.Limit;
import org.opensearch.sql.ast.tree.Lookup;
import org.opensearch.sql.ast.tree.ML;
import org.opensearch.sql.ast.tree.MakeResults;
import org.opensearch.sql.ast.tree.Multisearch;
import org.opensearch.sql.ast.tree.MvCombine;
import org.opensearch.sql.ast.tree.MvExpand;
Expand Down Expand Up @@ -111,6 +112,7 @@
import org.opensearch.sql.ast.tree.UnresolvedPlan;
import org.opensearch.sql.ast.tree.Values;
import org.opensearch.sql.ast.tree.Window;
import org.opensearch.sql.ast.tree.Xyseries;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.data.model.ExprMissingValue;
import org.opensearch.sql.data.type.ExprCoreType;
Expand Down Expand Up @@ -562,6 +564,11 @@ public LogicalPlan visitNoMv(NoMv node, AnalysisContext context) {
throw getOnlyForCalciteException("nomv");
}

@Override
public LogicalPlan visitMakeResults(MakeResults node, AnalysisContext context) {
throw getOnlyForCalciteException("makeresults");
}

@Override
public LogicalPlan visitMvExpand(MvExpand node, AnalysisContext context) {
throw getOnlyForCalciteException("mvexpand");
Expand Down Expand Up @@ -836,6 +843,11 @@ public LogicalPlan visitChart(Chart node, AnalysisContext context) {
throw getOnlyForCalciteException("Chart");
}

@Override
public LogicalPlan visitXyseries(Xyseries node, AnalysisContext context) {
throw getOnlyForCalciteException("Xyseries");
}

@Override
public LogicalPlan visitWindow(Window node, AnalysisContext context) {
throw getOnlyForCalciteException("Window");
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/org/opensearch/sql/ast/AbstractNodeVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import org.opensearch.sql.ast.tree.Limit;
import org.opensearch.sql.ast.tree.Lookup;
import org.opensearch.sql.ast.tree.ML;
import org.opensearch.sql.ast.tree.MakeResults;
import org.opensearch.sql.ast.tree.Multisearch;
import org.opensearch.sql.ast.tree.MvCombine;
import org.opensearch.sql.ast.tree.MvExpand;
Expand Down Expand Up @@ -99,6 +100,7 @@
import org.opensearch.sql.ast.tree.Union;
import org.opensearch.sql.ast.tree.Values;
import org.opensearch.sql.ast.tree.Window;
import org.opensearch.sql.ast.tree.Xyseries;

/** AST nodes visitor Defines the traverse path. */
public abstract class AbstractNodeVisitor<T, C> {
Expand Down Expand Up @@ -344,6 +346,10 @@ public T visitValues(Values node, C context) {
return visitChildren(node, context);
}

public T visitMakeResults(MakeResults node, C context) {
return visitChildren(node, context);
}

public T visitAlias(Alias node, C context) {
return visitChildren(node, context);
}
Expand Down Expand Up @@ -515,4 +521,8 @@ public T visitMvExpand(MvExpand node, C context) {
public T visitGraphLookup(GraphLookup node, C context) {
return visitChildren(node, context);
}

public T visitXyseries(Xyseries node, C context) {
return visitChildren(node, context);
}
}
47 changes: 47 additions & 0 deletions core/src/main/java/org/opensearch/sql/ast/tree/MakeResults.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.ast.tree;

import com.google.common.collect.ImmutableList;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.opensearch.sql.ast.AbstractNodeVisitor;
import org.opensearch.sql.ast.Node;

/**
* AST node for the {@code makeresults} leading command (count path). Generates {@code count}
* in-memory rows, each carrying a single {@code @timestamp} column set to query time.
*
* <p>The {@code format=csv|json data="..."} form is parsed into a shared {@link Values} node
* instead (see {@code MakeResultsDataParser}), so inline literal rows flow through the common
* {@code visitValues} builder.
*/
@ToString
@Getter
@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class MakeResults extends UnresolvedPlan {

private final int count;

@Override
public UnresolvedPlan attach(UnresolvedPlan child) {
throw new UnsupportedOperationException("MakeResults node is supposed to have no child node");
}

@Override
public <T, C> T accept(AbstractNodeVisitor<T, C> nodeVisitor, C context) {
return nodeVisitor.visitMakeResults(this, context);
}

@Override
public List<? extends Node> getChild() {
return ImmutableList.of();
}
}
2 changes: 2 additions & 0 deletions core/src/main/java/org/opensearch/sql/ast/tree/RareTopN.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public enum CommandType {
public enum Option {
countField,
showCount,
percentField,
showPerc,
useNull,
}
}
37 changes: 35 additions & 2 deletions core/src/main/java/org/opensearch/sql/ast/tree/Values.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,54 @@
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.opensearch.sql.ast.AbstractNodeVisitor;
import org.opensearch.sql.ast.Node;
import org.opensearch.sql.ast.expression.Literal;
import org.opensearch.sql.data.type.ExprCoreType;

/** AST node class for a sequence of literal values. */
@ToString
@Getter
@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class Values extends UnresolvedPlan {

private final List<List<Literal>> values;

private final List<String> columnNames;

/**
* Optional explicit column types, authoritative for the schema. Required to type a zero-row
* relation (header-only CSV / empty JSON array) where there are no literals to infer from.
*/
private final List<ExprCoreType> columnTypes;

/**
* When {@code true}, prepend an implicit {@code @timestamp = NOW()} column (from {@code
* makeresults format=json data=}). CSV data= and subsearch callers leave it {@code false}.
*/
private final boolean withImplicitTimestamp;

public Values(List<List<Literal>> values) {
this(values, null, null);
}

public Values(
List<List<Literal>> values, List<String> columnNames, List<ExprCoreType> columnTypes) {
this(values, columnNames, columnTypes, false);
}

public Values(
List<List<Literal>> values,
List<String> columnNames,
List<ExprCoreType> columnTypes,
boolean withImplicitTimestamp) {
this.values = values;
this.columnNames = columnNames;
this.columnTypes = columnTypes;
this.withImplicitTimestamp = withImplicitTimestamp;
}

@Override
public UnresolvedPlan attach(UnresolvedPlan child) {
throw new UnsupportedOperationException("Values node is supposed to have no child node");
Expand Down
64 changes: 64 additions & 0 deletions core/src/main/java/org/opensearch/sql/ast/tree/Xyseries.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.ast.tree;

import com.google.common.collect.ImmutableList;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.opensearch.sql.ast.AbstractNodeVisitor;
import org.opensearch.sql.ast.expression.UnresolvedExpression;

/**
* AST node representing the xyseries command. Converts row-oriented grouped results into a wide
* table where one field is the X axis (row key), one field provides pivot values for column naming,
* and one or more data fields fill the pivoted cells.
*/
@Getter
@ToString
@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class Xyseries extends UnresolvedPlan {

/** The x-axis field (row key in output). */
private final UnresolvedExpression xField;

/** The y-name field whose values become part of the output column names. */
private final UnresolvedExpression yNameField;

/** Explicit pivot values from the IN (...) clause. */
private final List<String> pivotValues;

/** One or more y-data fields whose values fill the pivoted cells. */
private final List<UnresolvedExpression> yDataFields;

/** Separator between y-data-field name and pivot value in column names. Default ":". */
private final String separator;

/** Optional format template for output column names using $AGG$ and $VAL$ placeholders. */
private final String format;

@Setter private UnresolvedPlan child;

@Override
public Xyseries attach(UnresolvedPlan child) {
this.child = child;
return this;
}

@Override
public List<UnresolvedPlan> getChild() {
return this.child == null ? ImmutableList.of() : ImmutableList.of(this.child);
}

@Override
public <T, C> T accept(AbstractNodeVisitor<T, C> nodeVisitor, C context) {
return nodeVisitor.visitXyseries(this, context);
}
}
Loading
Loading