@@ -1641,6 +1641,38 @@ describe("QuestDB Parser", () => {
16411641 } ) ;
16421642 } ) ;
16431643
1644+ describe ( "PIVOT multi-statement boundary" , ( ) => {
1645+ it ( "should parse two consecutive pivot statements as separate statements" , ( ) => {
1646+ const sql = `trades PIVOT (avg(price) FOR symbol IN ('ETH-USDT'))
1647+ trades PIVOT (sum(amount) FOR symbol IN ('BTC-USDT'))` ;
1648+ const result = parseToAst ( sql ) ;
1649+ expect ( result . ast ) . toHaveLength ( 2 ) ;
1650+ expect ( result . ast [ 0 ] . type ) . toBe ( "pivot" ) ;
1651+ expect ( result . ast [ 1 ] . type ) . toBe ( "pivot" ) ;
1652+ } ) ;
1653+
1654+ it ( "should not consume next table name as alias without AS" , ( ) => {
1655+ const sql = `trades PIVOT (avg(price) FOR symbol IN ('ETH-USDT'))
1656+ orders PIVOT (sum(amount) FOR status IN ('open'))` ;
1657+ const result = parseToAst ( sql ) ;
1658+ expect ( result . ast ) . toHaveLength ( 2 ) ;
1659+ if ( result . ast [ 0 ] . type === "pivot" ) {
1660+ expect ( result . ast [ 0 ] . alias ) . toBeUndefined ( ) ;
1661+ }
1662+ } ) ;
1663+
1664+ it ( "should still support PIVOT alias with AS keyword" , ( ) => {
1665+ const result = parseToAst (
1666+ "trades PIVOT (avg(price) FOR symbol IN ('ETH-USDT')) AS p"
1667+ ) ;
1668+ expect ( result . errors ) . toHaveLength ( 0 ) ;
1669+ expect ( result . ast ) . toHaveLength ( 1 ) ;
1670+ if ( result . ast [ 0 ] . type === "pivot" ) {
1671+ expect ( result . ast [ 0 ] . alias ) . toBe ( "p" ) ;
1672+ }
1673+ } ) ;
1674+ } ) ;
1675+
16441676 describe ( "PIVOT round-trip tests" , ( ) => {
16451677 const queries = [
16461678 "trades PIVOT (sum(amount) FOR category IN ('food', 'drinks'))" ,
@@ -3220,6 +3252,40 @@ describe("QuestDB Parser", () => {
32203252 } ) ;
32213253 } ) ;
32223254
3255+ describe ( "Incomplete implicit SELECT produces partial AST" , ( ) => {
3256+ it ( "should produce AST for incomplete 'table WHERE'" , ( ) => {
3257+ const result = parseToAst ( "core_price WHERE " ) ;
3258+ // Should produce a partial AST even though the query is incomplete
3259+ expect ( result . ast . length ) . toBeGreaterThan ( 0 ) ;
3260+ const stmt = result . ast [ 0 ] as any ;
3261+ expect ( stmt . type ) . toBe ( "select" ) ;
3262+ expect ( stmt . implicit ) . toBe ( true ) ;
3263+ } ) ;
3264+
3265+ it ( "should produce AST with table reference for incomplete implicit select" , ( ) => {
3266+ const result = parseToAst ( "trades WHERE price > " ) ;
3267+ expect ( result . ast . length ) . toBeGreaterThan ( 0 ) ;
3268+ const stmt = result . ast [ 0 ] as any ;
3269+ expect ( stmt . type ) . toBe ( "select" ) ;
3270+ expect ( stmt . implicit ) . toBe ( true ) ;
3271+ } ) ;
3272+
3273+ it ( "should produce AST for bare table name only" , ( ) => {
3274+ const result = parseToAst ( "trades" ) ;
3275+ expect ( result . ast . length ) . toBeGreaterThan ( 0 ) ;
3276+ const stmt = result . ast [ 0 ] as any ;
3277+ expect ( stmt . type ) . toBe ( "select" ) ;
3278+ expect ( stmt . implicit ) . toBe ( true ) ;
3279+ } ) ;
3280+
3281+ it ( "should produce AST for incomplete implicit select after semicolon" , ( ) => {
3282+ const result = parseToAst ( "SELECT 1; core_price WHERE " ) ;
3283+ expect ( result . ast . length ) . toBeGreaterThan ( 0 ) ;
3284+ // First statement is complete SELECT
3285+ expect ( result . ast [ 0 ] . type ) . toBe ( "select" ) ;
3286+ } ) ;
3287+ } ) ;
3288+
32233289 describe ( "Parenthesized SHOW as table source" , ( ) => {
32243290 it ( "should parse (SHOW PARAMETERS) WHERE ..." , ( ) => {
32253291 const result = parseToAst (
0 commit comments