@@ -386,6 +386,9 @@ func (p *prometheusReader) parseExtraFilters(filter *extraFilters, db string) (s
386386 if filter .label == "" || filter .operator == "" {
387387 return "" , ""
388388 }
389+ if filter .operator == "exist" || filter .operator == "not exist" {
390+ return filter .label , fmt .Sprintf ("%s(%s)" , filter .operator , filter .label )
391+ }
389392 return filter .label , fmt .Sprintf ("%s %s %s" , filter .label , filter .operator , escapeSingleQuote (filter .value ))
390393}
391394
@@ -424,26 +427,34 @@ func (p *prometheusReader) parseMatchers(matcher *prompb.LabelMatcher, prefixTyp
424427}
425428
426429// parse extra-filters to filters in `where` clause
427- func (p * prometheusReader ) parseExtraFiltersToWhereClause (extraLabelFilters [][]* extraFilters , prefixType prefix , db string , handleTags func (string , bool )) string {
428- outerFilters := make ([]string , 0 , len (extraLabelFilters ))
429- for i := 0 ; i < len (extraLabelFilters ); i ++ {
430- innerFilters := make ([]string , 0 , len (extraLabelFilters [i ]))
431- for j := 0 ; j < len (extraLabelFilters [i ]); j ++ {
432- matcher := extraLabelFilters [i ][j ]
433- tagName , newFilter := p .parseExtraFilters (matcher , db )
434- if newFilter == "" {
435- continue
436- }
437- innerFilters = append (innerFilters , newFilter )
438- handleTags (tagName , matcher .isTag )
430+ func (p * prometheusReader ) parseExtraFiltersToWhereClause (node * filterNode , prefixType prefix , db string , handleTags func (string , bool )) string {
431+ if node == nil {
432+ return ""
433+ }
434+ if node .filter != nil {
435+ // leaf node
436+ tagName , sql := p .parseExtraFilters (node .filter , db )
437+ if sql == "" {
438+ return ""
439439 }
440- // inside matchers use 'AND' for connected
441- if len (innerFilters ) > 0 {
442- outerFilters = append (outerFilters , fmt .Sprintf ("(%s)" , strings .Join (innerFilters , " AND " )))
440+ handleTags (tagName , node .filter .isTag )
441+ return sql
442+ }
443+ // internal AND/OR node: recurse into children
444+ parts := make ([]string , 0 , len (node .children ))
445+ for _ , child := range node .children {
446+ s := p .parseExtraFiltersToWhereClause (child , prefixType , db , handleTags )
447+ if s != "" {
448+ parts = append (parts , s )
443449 }
444450 }
445- // outside matchers use 'OR' for connected
446- return fmt .Sprintf ("(%s)" , strings .Join (outerFilters , " OR " ))
451+ if len (parts ) == 0 {
452+ return ""
453+ }
454+ if len (parts ) == 1 {
455+ return parts [0 ]
456+ }
457+ return fmt .Sprintf ("(%s)" , strings .Join (parts , " " + node .op + " " ))
447458}
448459
449460// return: prefixType, metricName, db, table, dataPrecision, metricAlias
@@ -1569,60 +1580,62 @@ type extraFilters struct {
15691580 isTag bool
15701581}
15711582
1572- func parseExtraFiltersToMatchers (filters string ) ([][]* extraFilters , error ) {
1583+ // filterNode is a boolean expression tree of extra filters.
1584+ // Leaf node: filter != nil. Internal node: op is "AND"/"OR", children non-empty.
1585+ type filterNode struct {
1586+ filter * extraFilters
1587+ op string
1588+ children []* filterNode
1589+ }
1590+
1591+ func parseExtraFiltersToMatchers (filters string ) (* filterNode , error ) {
15731592 fakeSQL := fmt .Sprintf ("select 1 from t where %s" , filters )
15741593 stmt , err := sqlparser .Parse (fakeSQL )
15751594 if err != nil {
15761595 return nil , err
15771596 }
15781597 selectStmt := stmt .(* sqlparser.Select )
1579- labelMatchers := make ([][]* extraFilters , 0 )
1580- _ , err = iterateExprs (selectStmt .Where .Expr , & labelMatchers )
1581- if err != nil {
1582- return nil , err
1583- }
1584- return labelMatchers , nil
1598+ return iterateExprs (selectStmt .Where .Expr )
15851599}
15861600
1587- func iterateExprs (node sqlparser.Expr , labelMatchers * [][]* extraFilters ) (sqlparser.Expr , error ) {
1601+ // iterateExprs builds a filterNode tree from a SQL expression.
1602+ // AND/OR structure is preserved as-is; no DNF flattening needed.
1603+ func iterateExprs (node sqlparser.Expr ) (* filterNode , error ) {
15881604 switch node := node .(type ) {
15891605 case * sqlparser.AndExpr :
1590- left , err := iterateExprs (node .Left , labelMatchers )
1606+ left , err := iterateExprs (node .Left )
15911607 if err != nil {
1592- return left , err
1608+ return nil , err
15931609 }
1594- right , err := iterateExprs (node .Right , labelMatchers )
1610+ right , err := iterateExprs (node .Right )
15951611 if err != nil {
1596- return right , err
1612+ return nil , err
15971613 }
15981614 if left == nil {
15991615 return right , nil
1600- } else if right == nil {
1616+ }
1617+ if right == nil {
16011618 return left , nil
16021619 }
1603- return node , nil
1620+ return & filterNode { op : "AND" , children : [] * filterNode { left , right }} , nil
16041621 case * sqlparser.OrExpr :
1605- left , err := iterateExprs (node .Left , labelMatchers )
1622+ left , err := iterateExprs (node .Left )
16061623 if err != nil {
1607- return left , err
1624+ return nil , err
16081625 }
1609- right , err := iterateExprs (node .Right , labelMatchers )
1626+ right , err := iterateExprs (node .Right )
16101627 if err != nil {
1611- return right , err
1628+ return nil , err
16121629 }
16131630 if left == nil {
16141631 return right , nil
1615- } else if right == nil {
1632+ }
1633+ if right == nil {
16161634 return left , nil
16171635 }
1618- return node , nil
1636+ return & filterNode { op : "OR" , children : [] * filterNode { left , right }} , nil
16191637 case * sqlparser.ParenExpr :
1620- (* labelMatchers ) = append ((* labelMatchers ), []* extraFilters {})
1621- expr , err := iterateExprs (node .Expr , labelMatchers )
1622- if err != nil {
1623- return expr , err
1624- }
1625- return expr , nil
1638+ return iterateExprs (node .Expr )
16261639 case * sqlparser.ComparisonExpr :
16271640 var comparExpr sqlparser.Expr
16281641 if parenExpr , ok := node .Left .(* sqlparser.ParenExpr ); ok {
@@ -1644,22 +1657,41 @@ func iterateExprs(node sqlparser.Expr, labelMatchers *[][]*extraFilters) (sqlpar
16441657 op = node .Operator
16451658 istag = true
16461659 }
1647- lastIndex := len (* labelMatchers ) - 1
1648- if lastIndex < 0 {
1649- (* labelMatchers ) = append ((* labelMatchers ), []* extraFilters {})
1650- lastIndex = len (* labelMatchers ) - 1
1651- }
1652-
1653- (* labelMatchers )[lastIndex ] = append ((* labelMatchers )[lastIndex ], & extraFilters {
1660+ return & filterNode {filter : & extraFilters {
16541661 operator : op ,
16551662 // some tag will escape by sqlparser
16561663 // https://github.com/xwb1989/sqlparser/blob/master/token.go#L85
16571664 label : removeEscapeQuote (colName , "`" ),
16581665 value : removeEscapeQuote (colValue , "'" ),
16591666 isTag : istag ,
1660- })
1661- return node , nil
1667+ }}, nil
1668+ case * sqlparser.NotExpr :
1669+ if funcExpr , ok := node .Expr .(* sqlparser.FuncExpr ); ok &&
1670+ strings .ToLower (funcExpr .Name .String ()) == "exist" &&
1671+ len (funcExpr .Exprs ) == 1 {
1672+ if aliasedExpr , ok := funcExpr .Exprs [0 ].(* sqlparser.AliasedExpr ); ok {
1673+ tagName := removeEscapeQuote (sqlparser .String (aliasedExpr .Expr ), "`" )
1674+ return & filterNode {filter : & extraFilters {
1675+ operator : "not exist" ,
1676+ label : tagName ,
1677+ isTag : true ,
1678+ }}, nil
1679+ }
1680+ }
1681+ return nil , nil
1682+ case * sqlparser.FuncExpr :
1683+ if strings .ToLower (node .Name .String ()) == "exist" && len (node .Exprs ) == 1 {
1684+ if aliasedExpr , ok := node .Exprs [0 ].(* sqlparser.AliasedExpr ); ok {
1685+ tagName := removeEscapeQuote (sqlparser .String (aliasedExpr .Expr ), "`" )
1686+ return & filterNode {filter : & extraFilters {
1687+ operator : "exist" ,
1688+ label : tagName ,
1689+ isTag : true ,
1690+ }}, nil
1691+ }
1692+ }
1693+ return nil , nil
16621694 default :
1663- return node , nil
1695+ return nil , nil
16641696 }
16651697}
0 commit comments