Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
06d888c
Add SQL DDL support for CREATE/DROP TABLE and SHOW CREATE TABLE (Slic…
xiangfu0 Apr 18, 2026
c580bd0
Fix five DDL issues from adversarial + standard code reviews
xiangfu0 Apr 18, 2026
c7a4932
Fix three DDL issues from second code review + add missing tests
xiangfu0 Apr 18, 2026
15a99b3
Fix three more DDL issues from second code review pass
xiangfu0 Apr 18, 2026
e29e6a7
Fix five DDL issues from adversarial + standard code reviews
xiangfu0 Apr 18, 2026
5df5e63
Fix seven code-review issues: @Nullable, input length guard, schema J…
xiangfu0 Apr 18, 2026
2500ce7
Fix four second-pass review issues: DECIMAL precision condition, inli…
xiangfu0 Apr 18, 2026
439a9ab
Replace inline FQCNs with imports for SqlBasicTypeNameSpec and RelDat…
xiangfu0 Apr 18, 2026
a502f0b
Fix three MAJOR DDL review issues: schema comparison, DROP schema cle…
xiangfu0 Apr 24, 2026
63a8f39
Fix four CRITICAL and three MAJOR DDL review issues from orchestrator…
xiangfu0 Apr 25, 2026
03673ae
Address final review: stop double-logging in DROP catch, strengthen p…
xiangfu0 Apr 25, 2026
1db4dfe
Fix one CRITICAL and five MAJOR DDL review issues from third-pass review
xiangfu0 Apr 25, 2026
1b1c0ab
Address fingerprint regression in SHOW CREATE auth: revert to up-fron…
xiangfu0 Apr 25, 2026
bd9efb1
Fix CRITICAL parser bug + two MAJOR correctness issues from fourth re…
xiangfu0 Apr 25, 2026
973af1d
Fix CRITICAL BYTES default-null-value comparison regression
xiangfu0 Apr 25, 2026
2b8a64c
Fix CRITICAL BYTES emitter regression + 4 MAJOR DDL issues from fifth…
xiangfu0 Apr 25, 2026
c2d9fb6
Add regression tests for fifth-pass DDL fixes
xiangfu0 Apr 25, 2026
c5e36a6
Fix CRITICAL validation divergence + 3 MAJOR DDL issues from sixth re…
xiangfu0 Apr 25, 2026
65b8566
Refresh response tableConfig snapshot after tuner application
xiangfu0 Apr 25, 2026
d2f69db
Fix CRITICAL ComplexFieldSpec drop + 4 MAJOR DDL issues from seventh …
xiangfu0 Apr 25, 2026
cb318fc
Fix MAJOR TIMESTAMP timezone-dependence + add regression tests
xiangfu0 Apr 25, 2026
e3b8d09
Address 4 MAJOR documentation/diagnostics issues from eighth review pass
xiangfu0 Apr 25, 2026
a49c3a8
Address 5 MAJOR DDL issues from ninth review pass
xiangfu0 Apr 25, 2026
ca69abe
Fix tautological assertion in booleanDefaultEmittedAsSqlLiteral test
xiangfu0 Apr 25, 2026
9e7da7c
Fix CRITICAL BYTES default-value emit fallthrough
xiangfu0 Apr 25, 2026
7d890fc
Replace inline FQCNs in DDL test files with imports
xiangfu0 Apr 25, 2026
ed51cfb
Add DESIGN.md and module README for pinot-sql-ddl
xiangfu0 Apr 27, 2026
4bc6aaa
Prefer TIMESTAMP over LONG/EPOCH for DDL time-column examples
xiangfu0 May 15, 2026
89a899e
Address review feedback: BOOLEAN default round-trip test + Swagger 40…
xiangfu0 May 15, 2026
436f1a7
Polish DDL response shape and document control-plane races
xiangfu0 May 15, 2026
e59e49c
Add cluster-level integration test for TIMESTAMP DDL time column
xiangfu0 May 15, 2026
11dd972
Document BOOLEAN silent-coercion semantics in DDL DEFAULT validation
xiangfu0 May 15, 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
25 changes: 25 additions & 0 deletions pinot-common/src/main/codegen/config.fmpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ data: {
"BIG_DECIMAL"
"STRING"
"BYTES"
# Pinot DDL (CREATE/DROP/SHOW TABLE) keywords
"DIMENSION"
"METRIC"
"GRANULARITY"
"OFFLINE"
"REALTIME"
"PROPERTIES"
"TABLES"
"TABLE_TYPE"
# IF is not a SQL reserved word but Calcite core does not declare it as a token; we need it
# for DDL "IF [NOT] EXISTS" clauses.
"IF"
]

# List of non-reserved keywords to add;
Expand All @@ -70,6 +82,16 @@ data: {
"DATETIME"
"VARIANT"
"UUID"
# Pinot DDL keywords kept non-reserved so users can still use them as identifiers
"DIMENSION"
"METRIC"
"GRANULARITY"
"OFFLINE"
"REALTIME"
"PROPERTIES"
"TABLES"
"TABLE_TYPE"
"IF"

# The following keywords are reserved in core Calcite,
# are reserved in some version of SQL,
Expand Down Expand Up @@ -568,6 +590,9 @@ data: {
statementParserMethods: [
"SqlInsertFromFile()"
"SqlPhysicalExplain()"
"SqlPinotCreateTable()"
"SqlPinotDropTable()"
"SqlPinotShow()"
]

# List of methods for parsing custom literals.
Expand Down
207 changes: 203 additions & 4 deletions pinot-common/src/main/codegen/includes/parserImpls.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ SqlNodeList DataFileDefList() :
}
}

/**
* INSERT INTO [db_name.]table_name
* FROM [ FILE | ARCHIVE ] 'file_uri' [, [ FILE | ARCHIVE ] 'file_uri' ]
*/
/// INSERT INTO [db_name.]table_name
/// FROM [ FILE | ARCHIVE ] 'file_uri' [, [ FILE | ARCHIVE ] 'file_uri' ]
SqlInsertFromFile SqlInsertFromFile() :
{
SqlParserPos pos;
Expand Down Expand Up @@ -109,3 +107,204 @@ SqlNode SqlPhysicalExplain() :
nDynamicParams);
}
}

/// CREATE TABLE [IF NOT EXISTS] [db.]name (
/// col TYPE [NULL | NOT NULL] [DEFAULT literal]
/// [ DIMENSION | METRIC | DATETIME FORMAT 'fmt' GRANULARITY 'gran' ],
/// ...
/// )
/// TABLE_TYPE = OFFLINE | REALTIME
/// [ PROPERTIES ( 'k' = 'v', ... ) ]
SqlNode SqlPinotCreateTable() :
{
SqlParserPos pos;
SqlIdentifier name;
boolean ifNotExists = false;
SqlNodeList columns;
SqlNodeList primaryKeyColumns = null;
SqlLiteral tableType;
SqlNodeList properties = null;
}
{
<CREATE> { pos = getPos(); }
<TABLE>
[ LOOKAHEAD(3) <IF> <NOT> <EXISTS> { ifNotExists = true; } ]
name = CompoundIdentifier()
columns = PinotColumnList()
[ LOOKAHEAD(2) primaryKeyColumns = PinotPrimaryKeyList() ]
<TABLE_TYPE> <EQ>
tableType = PinotTableTypeLiteral()
[ <PROPERTIES> properties = PinotPropertyList() ]
{
return new SqlPinotCreateTable(pos, name, ifNotExists, columns, primaryKeyColumns,
tableType, properties);
}
}

SqlNodeList PinotColumnList() :
{
SqlParserPos pos;
SqlPinotColumnDeclaration col;
List<SqlNode> list = new ArrayList<SqlNode>();
}
{
<LPAREN> { pos = getPos(); }
col = PinotColumnDeclaration() { list.add(col); }
( <COMMA> col = PinotColumnDeclaration() { list.add(col); } )*
<RPAREN>
{
return new SqlNodeList(list, pos.plus(getPos()));
}
}

SqlNodeList PinotPrimaryKeyList() :
{
SqlParserPos pos;
SqlIdentifier col;
List<SqlNode> list = new ArrayList<SqlNode>();
}
{
<PRIMARY> { pos = getPos(); } <KEY>
<LPAREN>
col = SimpleIdentifier() { list.add(col); }
( <COMMA> col = SimpleIdentifier() { list.add(col); } )*
<RPAREN>
{
return new SqlNodeList(list, pos.plus(getPos()));
}
}

SqlPinotColumnDeclaration PinotColumnDeclaration() :
{
SqlParserPos pos;
SqlIdentifier name;
SqlDataTypeSpec type;
boolean nullable = true;
SqlNode defaultValue = null;
String role = null;
SqlNode fmtNode = null;
SqlNode granNode = null;
boolean multiValue = false;
}
{
name = SimpleIdentifier() { pos = getPos(); }
type = DataType()
[
LOOKAHEAD(2)
<NOT> <NULL> { nullable = false; }
|
<NULL> { nullable = true; }
]
[ <DEFAULT_> defaultValue = Literal() ]
[
<DIMENSION> { role = "DIMENSION"; } [ <ARRAY> { multiValue = true; } ]
|
<METRIC> { role = "METRIC"; }
|
<DATETIME> { role = "DATETIME"; }
<FORMAT> fmtNode = StringLiteral()
<GRANULARITY> granNode = StringLiteral()
]
{
return new SqlPinotColumnDeclaration(pos, name, type, nullable, defaultValue, role,
(SqlLiteral) fmtNode, (SqlLiteral) granNode, multiValue);
}
}

SqlLiteral PinotTableTypeLiteral() :
{
String value;
SqlParserPos pos;
}
{
(
<OFFLINE> { value = "OFFLINE"; pos = getPos(); }
|
<REALTIME> { value = "REALTIME"; pos = getPos(); }
)
{
return SqlLiteral.createCharString(value, pos);
}
}

SqlNodeList PinotPropertyList() :
{
SqlParserPos pos;
SqlPinotProperty prop;
List<SqlNode> list = new ArrayList<SqlNode>();
}
{
<LPAREN> { pos = getPos(); }
[
prop = PinotProperty() { list.add(prop); }
( <COMMA> prop = PinotProperty() { list.add(prop); } )*
]
<RPAREN>
{
return new SqlNodeList(list, pos.plus(getPos()));
}
}

SqlPinotProperty PinotProperty() :
{
SqlParserPos pos;
SqlNode keyNode;
SqlNode valueNode;
}
{
keyNode = StringLiteral() { pos = getPos(); }
<EQ> valueNode = StringLiteral()
{
return new SqlPinotProperty(pos, (SqlLiteral) keyNode, (SqlLiteral) valueNode);
}
}

/// DROP TABLE [IF EXISTS] [db.]name [TYPE OFFLINE | REALTIME]
SqlNode SqlPinotDropTable() :
{
SqlParserPos pos;
SqlIdentifier name;
boolean ifExists = false;
SqlLiteral tableType = null;
}
{
<DROP> { pos = getPos(); }
<TABLE>
[ LOOKAHEAD(2) <IF> <EXISTS> { ifExists = true; } ]
name = CompoundIdentifier()
[ <TYPE> tableType = PinotTableTypeLiteral() ]
{
return new SqlPinotDropTable(pos, name, ifExists, tableType);
}
}

/// SHOW TABLES [FROM db]
/// | SHOW CREATE TABLE [db.]name [TYPE OFFLINE | REALTIME]
///
/// Both grammar branches share a leading `SHOW` token; combining them into a single entry point
/// keeps the JavaCC choice unambiguous (no need for LOOKAHEAD across multiple statementParser
/// methods that all start with SHOW).
SqlNode SqlPinotShow() :
{
SqlParserPos pos;
SqlIdentifier name;
SqlIdentifier database = null;
SqlLiteral tableType = null;
}
{
<SHOW> { pos = getPos(); }
(
<TABLES>
[ <FROM> database = SimpleIdentifier() ]
{
return new SqlPinotShowTables(pos, database);
}
|
<CREATE> <TABLE>
name = CompoundIdentifier()
[ <TYPE> tableType = PinotTableTypeLiteral() ]
{
return new SqlPinotShowCreateTable(pos, name, tableType);
}
)
}
Loading
Loading