github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/ast/sql/astsql.go (about)

     1  /*
     2  Copyright 2023.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sql
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"regexp"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/siglens/siglens/pkg/ast"
    27  	query "github.com/siglens/siglens/pkg/es/query"
    28  	structs "github.com/siglens/siglens/pkg/segment/structs"
    29  	utils "github.com/siglens/siglens/pkg/segment/utils"
    30  	log "github.com/sirupsen/logrus"
    31  	"github.com/xwb1989/sqlparser"
    32  )
    33  
    34  const (
    35  	And = iota
    36  	Or
    37  )
    38  
    39  func ConvertToASTNodeSQL(exp string, qid uint64) (*structs.ASTNode, *structs.QueryAggregators, []string, error) {
    40  	exp = formatStringForSQL(exp)
    41  	aggNode := structs.InitDefaultQueryAggregations()
    42  	aggNode.BucketLimit = 100
    43  	astNode, err := query.GetMatchAllASTNode(qid)
    44  	columsArray := make([]string, 0)
    45  	if err != nil {
    46  		log.Errorf("qid=%v, ConvertToASTNodeSQL: match all ast node failed! %+v", qid, err)
    47  		return nil, nil, nil, err
    48  	}
    49  
    50  	stmt, err := sqlparser.Parse(exp)
    51  	if err != nil {
    52  		log.Errorf("qid=%v, ConvertToASTNodeSQL: sql parser failed! %+v", qid, err)
    53  		return nil, nil, columsArray, err
    54  	}
    55  
    56  	switch currStmt := stmt.(type) {
    57  	case *sqlparser.Select:
    58  		astNode, aggNode, columsArray, err = parseSelect(astNode, aggNode, currStmt, qid)
    59  		if err != nil {
    60  			log.Errorf("qid=%v, ConvertToASTNodeSQL: sql select parsing failed! %+v", qid, err)
    61  			return nil, nil, columsArray, fmt.Errorf("For query:%v, ConvertToASTNodeSQL: sql parser failed! %+v", exp, err)
    62  		}
    63  	case *sqlparser.Show:
    64  		aggNode.ShowRequest = &structs.ShowRequest{}
    65  		if currStmt.ShowTablesOpt != nil {
    66  			aggNode.ShowRequest.ShowTables = true
    67  			aggNode.ShowRequest.ShowFilter = &structs.ShowFilter{Like: ".*"}
    68  			if currStmt.ShowTablesOpt.Filter != nil {
    69  				aggNode.ShowRequest.ShowFilter.Like = currStmt.ShowTablesOpt.Filter.Like
    70  			}
    71  		} else if strings.ContainsAny(currStmt.Type, "COLUMNS") || strings.ContainsAny(currStmt.Type, "columns") {
    72  			inClause, err := getInTable(strings.ReplaceAll(exp, "`", ""))
    73  			if err != nil {
    74  				log.Errorf("qid=%v, ConvertToASTNodeSQL: sql show columns request parsing failed! %+v", qid, err)
    75  				return nil, nil, columsArray, err
    76  			}
    77  			aggNode.ShowRequest.ColumnsRequest = &structs.ShowColumns{}
    78  			aggNode.ShowRequest.ColumnsRequest.InTable = inClause
    79  		} else {
    80  			log.Errorf("qid=%v, ConvertToASTNodeSQL: only SHOW TABLES and SHOW COLUMNS are supported! %+v", qid, err)
    81  			return nil, nil, columsArray, err
    82  		}
    83  	case *sqlparser.OtherRead:
    84  		new_exp, err := parseOtherRead(exp, qid)
    85  		if err != nil {
    86  			log.Errorf("qid=%v, ConvertToASTNodeSQL: sql describe/explain request parsing failed! %+v", qid, err)
    87  			return nil, nil, columsArray, err
    88  		}
    89  		return ConvertToASTNodeSQL(new_exp, qid)
    90  	default:
    91  		err := fmt.Errorf("qid=%v, ConvertToASTNodeSQL: Only SELECT and SHOW commands are supported!", qid)
    92  		return nil, nil, columsArray, err
    93  	}
    94  
    95  	return astNode, aggNode, columsArray, err
    96  }
    97  
    98  func getInTable(exp string) (string, error) {
    99  	exp = strings.ReplaceAll(exp, " IN ", " in ")
   100  	exp = strings.ReplaceAll(exp, " FROM ", " in ")
   101  	exp = strings.ReplaceAll(exp, " from ", " in ")
   102  	if !strings.Contains(exp, " in ") {
   103  		return "", fmt.Errorf("getInTable: Invalid SHOW COLUMNS request, expected IN or FROM clause followed by argument!")
   104  	}
   105  	inClauses := strings.Split(exp, " in ")
   106  	if len(inClauses) < 2 {
   107  		return "", fmt.Errorf("getInTable: Expected table name after In/From clause!")
   108  	}
   109  	return inClauses[1], nil
   110  }
   111  
   112  func getAggregationSQL(agg string, qid uint64) utils.AggregateFunctions {
   113  	agg = strings.ToLower(agg)
   114  	switch agg {
   115  	case "count":
   116  		return utils.Count
   117  	case "avg":
   118  		return utils.Avg
   119  	case "min":
   120  		return utils.Min
   121  	case "max":
   122  		return utils.Max
   123  	case "sum":
   124  		return utils.Sum
   125  	case "cardinality":
   126  		return utils.Cardinality
   127  	default:
   128  		log.Errorf("qid=%v, getAggregationSQL: aggregation type not supported!", qid)
   129  		return 0
   130  	}
   131  }
   132  
   133  func getMathEvaluatorSQL(op string, qid uint64) (utils.MathFunctions, error) {
   134  	op = strings.ToLower(op)
   135  	switch op {
   136  	case "round":
   137  		return utils.Round, nil
   138  	case "ceil":
   139  		return utils.Ceil, nil
   140  	case "abs":
   141  		return utils.Abs, nil
   142  	case "sqrt":
   143  		return utils.Sqrt, nil
   144  	case "exp":
   145  		return utils.Exp, nil
   146  	default:
   147  		log.Errorf("qid=%v, getMathEvaluatorSQL: math evaluator type not supported!", qid)
   148  		return 0, fmt.Errorf("math evaluator type not supported")
   149  	}
   150  }
   151  
   152  func getMathFunctionSQL(funcName string, argExprs sqlparser.SelectExprs, qid uint64) (utils.MathFunctions, *structs.NumericExpr, error) {
   153  
   154  	mathFunc, err := getMathEvaluatorSQL(funcName, qid)
   155  	if err != nil {
   156  		log.Errorf("qid=%v, getMathFunctionSQL: getMathEvaluatorSQL failed! %+v", qid, err)
   157  		return mathFunc, nil, err
   158  	}
   159  
   160  	if len(argExprs) < 1 || len(argExprs) > 2 {
   161  		log.Errorf("qid=%v, getMathFunctionSQL: incorrect number of arguments for Math function", qid)
   162  		return mathFunc, nil, fmt.Errorf("incorrect number of arguments for Math function")
   163  	}
   164  
   165  	leftExpr, err := convertToNumericExpr(argExprs[0])
   166  	if err != nil {
   167  		log.Errorf("qid=%v, getMathFunctionSQL: error converting left expression of Math function to numeric expression! %+v", qid, err)
   168  		return mathFunc, nil, err
   169  	}
   170  
   171  	var rightExpr *structs.NumericExpr
   172  
   173  	// Check for 'round' function and handle arguments
   174  	if mathFunc == utils.Round {
   175  		if len(argExprs) == 2 {
   176  			rightExpr, err = convertToNumericExpr(argExprs[1])
   177  			if err != nil {
   178  				log.Errorf("qid=%v, getMathFunctionSQL: error converting right expression of round to numeric expression! %+v", qid, err)
   179  				return mathFunc, nil, err
   180  			}
   181  		}
   182  	}
   183  
   184  	numericExpr, err := createNumericExpr(funcName, leftExpr, rightExpr, structs.NEMNumericExpr)
   185  	return mathFunc, numericExpr, err
   186  }
   187  
   188  func convertToNumericExpr(expr any) (*structs.NumericExpr, error) {
   189  	switch e := expr.(type) {
   190  	case *sqlparser.AliasedExpr:
   191  
   192  		switch agg := e.Expr.(type) {
   193  
   194  		case *sqlparser.ColName:
   195  			return &structs.NumericExpr{
   196  				IsTerminal:      true,
   197  				ValueIsField:    true,
   198  				Value:           agg.Name.CompliantName(),
   199  				NumericExprMode: determineNumericExprMode(agg),
   200  			}, nil
   201  		case *sqlparser.FuncExpr:
   202  			return &structs.NumericExpr{
   203  				IsTerminal:      true,
   204  				Value:           agg.Name.CompliantName() + "(" + sqlparser.String(agg.Exprs) + ")",
   205  				ValueIsField:    true,
   206  				NumericExprMode: structs.NEMNumberField,
   207  				Val:             &structs.StringExpr{RawString: agg.Name.CompliantName(), FieldName: sqlparser.String(agg.Exprs)},
   208  			}, nil
   209  
   210  		case *sqlparser.SQLVal:
   211  			return &structs.NumericExpr{
   212  				IsTerminal:      true,
   213  				Value:           string(agg.Val),
   214  				NumericExprMode: determineNumericExprMode(agg),
   215  			}, nil
   216  		default:
   217  			return nil, fmt.Errorf("unsupported expression type: %T", expr)
   218  		}
   219  	default:
   220  		return nil, fmt.Errorf("unsupported expression type: %T", expr)
   221  	}
   222  }
   223  
   224  func determineNumericExprMode(e sqlparser.Expr) structs.NumericExprMode {
   225  	switch expr := e.(type) {
   226  	case *sqlparser.SQLVal:
   227  		// Determine if the value is a number or string
   228  		if expr.Type == sqlparser.IntVal || expr.Type == sqlparser.FloatVal {
   229  			return structs.NEMNumber
   230  		} else {
   231  			return structs.NEMLenString
   232  		}
   233  	case *sqlparser.ColName:
   234  		// If it's a column name, we might treat it as a field
   235  		return structs.NEMNumberField
   236  	default:
   237  		return structs.NEMNumber // Default or error handling
   238  	}
   239  }
   240  
   241  // Generate NumericExpr struct for eval functions
   242  func createNumericExpr(op string, leftExpr *structs.NumericExpr, rightExpr *structs.NumericExpr, numericExprMode structs.NumericExprMode) (*structs.NumericExpr, error) {
   243  	if leftExpr == nil {
   244  		return nil, fmt.Errorf("expr cannot be nil")
   245  	}
   246  
   247  	return &structs.NumericExpr{
   248  		IsTerminal:      false,
   249  		Op:              op,
   250  		Left:            leftExpr,
   251  		Right:           rightExpr,
   252  		NumericExprMode: numericExprMode,
   253  	}, nil
   254  }
   255  
   256  func parseSingleCondition(expr sqlparser.Expr, astNode *structs.ASTNode, qid uint64, condType int) (*structs.ASTNode, error) {
   257  	clause := strings.Split(sqlparser.String(expr), " ")
   258  	if len(clause) > 2 {
   259  		columnName := clause[0]
   260  		literal := strings.Join(clause[2:], " ")
   261  		var criteria []*structs.FilterCriteria
   262  		var err error
   263  		switch val := utils.GetLiteralFromString(literal).(type) {
   264  		case string:
   265  			val = strings.ReplaceAll(val, "'", "")
   266  			val = strings.ReplaceAll(val, "\"", "")
   267  			criteria, err = ast.ProcessSingleFilter(columnName, val, clause[1], false, qid)
   268  		default:
   269  			criteria, err = ast.ProcessSingleFilter(columnName, json.Number(literal), clause[1], false, qid)
   270  		}
   271  
   272  		if err != nil {
   273  			log.Errorf("qid=%v, parseSingleCondition: process pipe search failed! %+v", qid, err)
   274  			return nil, err
   275  		}
   276  
   277  		filtercond := &structs.Condition{
   278  			FilterCriteria: []*structs.FilterCriteria(criteria),
   279  		}
   280  
   281  		if condType == And {
   282  			astNode.AndFilterCondition = filtercond
   283  		} else if condType == Or {
   284  			astNode.OrFilterCondition = filtercond
   285  		}
   286  
   287  	}
   288  
   289  	return astNode, nil
   290  }
   291  
   292  func parseAndConditionSQL(astNode *structs.ASTNode, expr *sqlparser.AndExpr, qid uint64) {
   293  	subNode, err := parseSingleCondition(expr.Left, &structs.ASTNode{}, qid, And)
   294  	if err != nil {
   295  		log.Errorf("qid=%v, parseAndConditionSQL: parse single condition failed! %+v", qid, err)
   296  		return
   297  	}
   298  	if astNode.AndFilterCondition.NestedNodes == nil {
   299  		astNode.AndFilterCondition.NestedNodes = []*structs.ASTNode{subNode}
   300  	} else {
   301  		astNode.AndFilterCondition.NestedNodes = append(astNode.AndFilterCondition.NestedNodes, subNode)
   302  	}
   303  	switch next := expr.Right.(type) {
   304  	case *sqlparser.AndExpr:
   305  		parseAndConditionSQL(astNode, next, qid)
   306  	case *sqlparser.OrExpr:
   307  		parseOrConditionSQL(astNode, next, qid)
   308  	case *sqlparser.ComparisonExpr:
   309  		rightNode, err := parseSingleCondition(expr.Right, &structs.ASTNode{}, qid, And)
   310  		if err != nil {
   311  			log.Errorf("qid=%v, parseAndConditionSQL: parse single condition failed! %+v", qid, err)
   312  			return
   313  		}
   314  		astNode.AndFilterCondition.NestedNodes = append(astNode.AndFilterCondition.NestedNodes, rightNode)
   315  		return
   316  	case *sqlparser.ParenExpr:
   317  		switch child := next.Expr.(type) {
   318  		case *sqlparser.AndExpr:
   319  			parseAndConditionSQL(astNode, child, qid)
   320  		case *sqlparser.OrExpr:
   321  			parseOrConditionSQL(astNode, child, qid)
   322  		case *sqlparser.ComparisonExpr:
   323  			rightNode, err := parseSingleCondition(expr.Right, &structs.ASTNode{}, qid, And)
   324  			if err != nil {
   325  				log.Errorf("qid=%v, parseAndConditionSQL: parse single condition failed! %+v", qid, err)
   326  				return
   327  			}
   328  			astNode.AndFilterCondition.NestedNodes = append(astNode.AndFilterCondition.NestedNodes, rightNode)
   329  			return
   330  		}
   331  
   332  	}
   333  
   334  }
   335  
   336  func parseSelect(astNode *structs.ASTNode, aggNode *structs.QueryAggregators, currStmt *sqlparser.Select, qid uint64) (*structs.ASTNode, *structs.QueryAggregators, []string, error) {
   337  	newGroupByReq := &structs.GroupByRequest{GroupByColumns: make([]string, 0), MeasureOperations: make([]*structs.MeasureAggregator, 0)}
   338  	measureOps := make([]*structs.MeasureAggregator, 0)
   339  	columsArray := make([]string, 0)
   340  	hardcodedArray := make([]string, 0)
   341  	mathFunctionCols := make([]*structs.NumericExpr, 0)
   342  	mathOps := make([]*structs.MathEvaluator, 0)
   343  	renameCols := map[string]string{}
   344  	renameHardcodedCols := map[string]string{}
   345  	var err error
   346  	tableName := "*"
   347  	if len(currStmt.From) > 1 {
   348  		return astNode, aggNode, columsArray, fmt.Errorf("qid=%v, parseSelect: FROM clause has too many arguments! Only one table selection is supported", qid)
   349  	}
   350  	if currStmt.From != nil && len(currStmt.From) != 0 && sqlparser.String(currStmt.From[0]) != "dual" {
   351  		tableName = strings.ReplaceAll(sqlparser.String(currStmt.From[0]), "`", "")
   352  	}
   353  	aggNode.TableName = tableName
   354  	for index := range currStmt.SelectExprs {
   355  		switch alias := currStmt.SelectExprs[index].(type) {
   356  		case *sqlparser.AliasedExpr:
   357  			var label string
   358  			if len(alias.As.CompliantName()) > 0 {
   359  				if strings.Contains(sqlparser.String(alias.As), "`") {
   360  					label = strings.Trim(sqlparser.String(alias.As), "`")
   361  				} else {
   362  					label = alias.As.CompliantName()
   363  				}
   364  			}
   365  			switch agg := alias.Expr.(type) {
   366  			case *sqlparser.ColName:
   367  				columsArray = append(columsArray, agg.Name.CompliantName())
   368  				if len(label) != 0 {
   369  					renameCols[agg.Name.CompliantName()] = label
   370  				}
   371  			case *sqlparser.FuncExpr:
   372  
   373  				funcName := strings.ToLower(agg.Name.CompliantName())
   374  
   375  				mathFunc, numericExpr, err := getMathFunctionSQL(funcName, agg.Exprs, qid)
   376  
   377  				if mathFunc > 0 {
   378  					if err != nil {
   379  						log.Errorf("qid=%v, parseSelect: getMathFunctionSQL failed! %+v", qid, err)
   380  						return astNode, aggNode, columsArray, err
   381  					}
   382  
   383  					leftExpr := numericExpr.Left
   384  
   385  					var measureOp *structs.MeasureAggregator
   386  
   387  					if leftExpr.Val != nil {
   388  						val := leftExpr.Val
   389  						if val.RawString != "" {
   390  							measureFunc := val.RawString
   391  							measureCol := val.FieldName
   392  
   393  							leftExpr.Val = nil
   394  
   395  							measureOp = &structs.MeasureAggregator{MeasureCol: measureCol, MeasureFunc: getAggregationSQL(measureFunc, qid)}
   396  
   397  							measureOps = append(measureOps, measureOp)
   398  							newGroupByReq.MeasureOperations = append(newGroupByReq.MeasureOperations, measureOp)
   399  
   400  							mathFunctionCols = append(mathFunctionCols, numericExpr)
   401  						}
   402  					} else {
   403  
   404  						mathOp := &structs.MathEvaluator{MathCol: sqlparser.String(agg.Exprs[0]), MathFunc: mathFunc, ValueColRequest: &structs.ValueExpr{NumericExpr: numericExpr}}
   405  						mathOps = append(mathOps, mathOp)
   406  
   407  						columsArray = append(columsArray, sqlparser.String(agg.Exprs[0]))
   408  						if len(label) != 0 {
   409  							renameCols[sqlparser.String(agg.Exprs[0])] = label
   410  						} else {
   411  							renameCols[sqlparser.String(agg.Exprs[0])] = numericExpr.Op + "(" + sqlparser.String(agg.Exprs[0]) + ")"
   412  						}
   413  					}
   414  
   415  					if len(label) != 0 {
   416  						renameCols[strings.ToLower(sqlparser.String(agg))] = label
   417  						renameCols["mathOp_field_name"] = label
   418  					}
   419  
   420  				} else {
   421  
   422  					measureOp := &structs.MeasureAggregator{
   423  						MeasureCol: sqlparser.String(agg.Exprs), MeasureFunc: getAggregationSQL(agg.Name.CompliantName(), qid),
   424  					}
   425  					measureOps = append(measureOps, measureOp)
   426  					newGroupByReq.MeasureOperations = append(newGroupByReq.MeasureOperations, measureOp)
   427  					if len(label) != 0 {
   428  						renameCols[strings.ToLower(sqlparser.String(agg))] = label
   429  					}
   430  				}
   431  			case *sqlparser.SQLVal:
   432  				if len(label) != 0 {
   433  					renameHardcodedCols[sqlparser.String(agg)] = label
   434  				} else {
   435  					renameHardcodedCols[sqlparser.String(agg)] = sqlparser.String(agg)
   436  
   437  				}
   438  
   439  				hardcodedArray = append(hardcodedArray, sqlparser.String(agg))
   440  
   441  			default:
   442  				return astNode, aggNode, columsArray, fmt.Errorf("qid=%v, parseSelect: Unsupported Select expression type!", qid)
   443  			}
   444  
   445  		case *sqlparser.StarExpr:
   446  			break //astNode is defaulted to matchall, so no further action is needed
   447  		default:
   448  			return astNode, aggNode, columsArray, fmt.Errorf("only star expressions and regualar expressions are handled")
   449  
   450  		}
   451  
   452  	}
   453  
   454  	if len(columsArray) > 0 {
   455  
   456  		aggNode.OutputTransforms = &structs.OutputTransforms{OutputColumns: &structs.ColumnsRequest{IncludeColumns: columsArray}}
   457  		aggNode.OutputTransforms.OutputColumns.RenameColumns = renameCols
   458  
   459  	}
   460  	if len(hardcodedArray) > 0 {
   461  		if aggNode.OutputTransforms == nil {
   462  			aggNode.OutputTransforms = &structs.OutputTransforms{HarcodedCol: hardcodedArray}
   463  		}
   464  		aggNode.OutputTransforms.HarcodedCol = hardcodedArray
   465  		aggNode.OutputTransforms.RenameHardcodedColumns = renameHardcodedCols
   466  	}
   467  
   468  	if len(measureOps) > 0 {
   469  		aggNode.MeasureOperations = measureOps
   470  		if len(columsArray) == 0 && len(hardcodedArray) == 0 {
   471  			aggNode.OutputTransforms = &structs.OutputTransforms{OutputColumns: &structs.ColumnsRequest{}}
   472  		} else if len(columsArray) == 0 && len(hardcodedArray) > 0 {
   473  			aggNode.OutputTransforms.OutputColumns = &structs.ColumnsRequest{}
   474  		}
   475  		aggNode.OutputTransforms.OutputColumns.RenameAggregationColumns = renameCols
   476  	}
   477  
   478  	if len(mathFunctionCols) > 0 {
   479  		if len(columsArray) == 0 && len(hardcodedArray) == 0 && len(measureOps) == 0 {
   480  			aggNode.OutputTransforms = &structs.OutputTransforms{LetColumns: &structs.LetColumnsRequest{}}
   481  		} else {
   482  			aggNode.OutputTransforms.LetColumns = &structs.LetColumnsRequest{}
   483  		}
   484  
   485  		aggNode.OutputTransforms.LetColumns.ValueColRequest = &structs.ValueExpr{}
   486  		aggNode.OutputTransforms.LetColumns.ValueColRequest.NumericExpr = mathFunctionCols[0]
   487  
   488  		if renameCols["mathOp_field_name"] != "" {
   489  			aggNode.OutputTransforms.LetColumns.NewColName = renameCols["mathOp_field_name"]
   490  			delete(renameCols, "mathOp_field_name")
   491  		} else {
   492  			aggNode.OutputTransforms.LetColumns.NewColName = mathFunctionCols[0].Op + "(" + mathFunctionCols[0].Left.Value + ")"
   493  		}
   494  
   495  		aggNode.Next = &structs.QueryAggregators{OutputTransforms: &structs.OutputTransforms{}}
   496  		aggNode.Next.PipeCommandType = 1
   497  		aggNode.Next.OutputTransforms = &structs.OutputTransforms{LetColumns: &structs.LetColumnsRequest{}}
   498  		aggNode.Next.OutputTransforms.LetColumns = aggNode.OutputTransforms.LetColumns
   499  
   500  	}
   501  
   502  	if len(mathOps) > 0 {
   503  		aggNode.MathOperations = mathOps
   504  	}
   505  
   506  	if aggNode.OutputTransforms != nil && aggNode.OutputTransforms.OutputColumns != nil {
   507  		renameColumns := aggNode.OutputTransforms.OutputColumns.RenameColumns
   508  		renameAggregationColumns := aggNode.OutputTransforms.OutputColumns.RenameAggregationColumns
   509  
   510  		if (len(renameColumns) > 0) || (len(renameAggregationColumns) > 0) {
   511  			if aggNode.Next == nil || aggNode.Next.OutputTransforms == nil {
   512  				aggNode.Next = &structs.QueryAggregators{OutputTransforms: &structs.OutputTransforms{}}
   513  			}
   514  
   515  			if aggNode.Next.OutputTransforms.OutputColumns == nil {
   516  				aggNode.Next.OutputTransforms.OutputColumns = &structs.ColumnsRequest{}
   517  			}
   518  
   519  			aggNode.Next.OutputTransforms.OutputColumns.RenameColumns = renameColumns
   520  			aggNode.Next.OutputTransforms.OutputColumns.RenameAggregationColumns = renameAggregationColumns
   521  
   522  			aggNode.Next.PipeCommandType = 1
   523  		}
   524  	}
   525  
   526  	if currStmt.Where != nil {
   527  		switch stmt := (currStmt.Where).Expr.(type) {
   528  		case *sqlparser.OrExpr:
   529  			parseOrConditionSQL(astNode, stmt, qid)
   530  		case *sqlparser.AndExpr:
   531  			parseAndConditionSQL(astNode, stmt, qid)
   532  		case *sqlparser.ComparisonExpr:
   533  			astNode, err = parseSingleCondition(stmt, astNode, qid, And)
   534  			if err != nil {
   535  				log.Errorf("qid=%v, parseSingleCondition: statement failed to be parsed! %+v", qid, err)
   536  				return astNode, aggNode, columsArray, err
   537  			}
   538  		default:
   539  			return astNode, aggNode, columsArray, fmt.Errorf("qid=%v, ConvertToASTNodeSQL: only OR, AND, Comparison types are supported! %+v", qid, err)
   540  		}
   541  
   542  	}
   543  
   544  	if currStmt.Limit != nil {
   545  		rowLimit, err := strconv.ParseInt(sqlparser.String(currStmt.Limit.Rowcount), 10, 64)
   546  		if err != nil {
   547  			log.Errorf("qid=%v, parseSelect: Limit argument was not an integer!", qid)
   548  			return astNode, aggNode, columsArray, err
   549  		}
   550  		aggNode.Limit = int(rowLimit)
   551  	}
   552  
   553  	if currStmt.GroupBy != nil {
   554  		for _, val := range currStmt.GroupBy {
   555  			newGroupByReq.GroupByColumns = append(newGroupByReq.GroupByColumns, sqlparser.String(val))
   556  		}
   557  		aggNode.GroupByRequest = newGroupByReq
   558  		aggNode.GroupByRequest.BucketCount = aggNode.BucketLimit
   559  	}
   560  
   561  	if currStmt.OrderBy != nil {
   562  		if len(currStmt.OrderBy) != 1 {
   563  			return astNode, aggNode, columsArray, fmt.Errorf("qid=%v, ConvertToASTNodeSQL: Incorred Order By clause number! Only one clause is supported %+v", qid, err)
   564  		}
   565  		orderByClause := currStmt.OrderBy[0]
   566  		ascending := orderByClause.Direction == sqlparser.AscScr
   567  		aggNode.Sort = &structs.SortRequest{ColName: sqlparser.String(orderByClause.Expr), Ascending: ascending}
   568  
   569  	}
   570  	return astNode, aggNode, columsArray, nil
   571  }
   572  
   573  func parseOrConditionSQL(astNode *structs.ASTNode, expr *sqlparser.OrExpr, qid uint64) {
   574  	subNode, err := parseSingleCondition(expr.Left, &structs.ASTNode{}, qid, And)
   575  	if err != nil {
   576  		log.Errorf("qid=%v, parseOrConditionSQL: parse single condition failed! %+v", qid, err)
   577  		return
   578  	}
   579  	if astNode.OrFilterCondition == nil {
   580  		astNode.OrFilterCondition = &structs.Condition{}
   581  	}
   582  
   583  	if astNode.OrFilterCondition.NestedNodes == nil {
   584  		astNode.OrFilterCondition.NestedNodes = []*structs.ASTNode{subNode}
   585  	} else {
   586  		astNode.OrFilterCondition.NestedNodes = append(astNode.OrFilterCondition.NestedNodes, subNode)
   587  	}
   588  
   589  	switch next := expr.Right.(type) {
   590  	case *sqlparser.OrExpr:
   591  		parseOrConditionSQL(astNode, next, qid)
   592  	case *sqlparser.AndExpr:
   593  		parseAndConditionSQL(astNode, next, qid)
   594  	case *sqlparser.ComparisonExpr:
   595  		rightNode, err := parseSingleCondition(expr.Right, &structs.ASTNode{}, qid, Or)
   596  		if err != nil {
   597  			log.Errorf("qid=%v, parseOrConditionSQL: parse single condition failed! %+v", qid, err)
   598  			return
   599  		}
   600  		astNode.OrFilterCondition.NestedNodes = append(astNode.AndFilterCondition.NestedNodes, rightNode)
   601  		return
   602  	case *sqlparser.ParenExpr:
   603  		switch child := next.Expr.(type) {
   604  		case *sqlparser.AndExpr:
   605  			parseAndConditionSQL(astNode, child, qid)
   606  		case *sqlparser.OrExpr:
   607  			parseOrConditionSQL(astNode, child, qid)
   608  		case *sqlparser.ComparisonExpr:
   609  			rightNode, err := parseSingleCondition(child, &structs.ASTNode{}, qid, Or)
   610  			if err != nil {
   611  				log.Errorf("qid=%v, parseOrConditionSQL: parse single condition failed! %+v", qid, err)
   612  				return
   613  			}
   614  			astNode.OrFilterCondition.NestedNodes = append(astNode.AndFilterCondition.NestedNodes, rightNode)
   615  			return
   616  		}
   617  
   618  	}
   619  
   620  }
   621  
   622  func formatStringForSQL(querytext string) string {
   623  	//Add leading and trailing back ticks to words with hyphens
   624  	hyphenRegex := regexp.MustCompile(`[\w` + "`" + `]+-[\w` + "`" + `]+`)
   625  	hyphenWords := hyphenRegex.FindAllString(querytext, -1)
   626  	for _, word := range hyphenWords {
   627  		if !strings.Contains(word, "`") {
   628  			querytext = strings.ReplaceAll(querytext, " "+word, " `"+word+"`")
   629  		}
   630  	}
   631  
   632  	if strings.Contains(querytext, "LIKE ") {
   633  		likeClauses := strings.Split(querytext, "LIKE ")
   634  		if len(likeClauses) > 1 {
   635  			likeClauses[1] = "'" + strings.ReplaceAll(likeClauses[1], "`", "") + "'"
   636  			querytext = strings.Join(likeClauses, "LIKE ")
   637  		}
   638  
   639  	} else if strings.Contains(querytext, "like ") {
   640  		likeClauses := strings.Split(querytext, "like ")
   641  		if len(likeClauses) > 1 {
   642  			likeClauses[1] = "'" + strings.ReplaceAll(likeClauses[1], "`", "") + "'"
   643  			querytext = strings.Join(likeClauses, "like ")
   644  		}
   645  	}
   646  	return querytext
   647  
   648  }
   649  
   650  func parseOtherRead(exp string, qid uint64) (string, error) {
   651  	reg := regexp.MustCompile("DESCRIBE |DESC |describe |desc ")
   652  	if !reg.MatchString(exp) {
   653  		return exp, fmt.Errorf("qid=%v, parseOtherRead: Only DESCRIBE is supported!", qid)
   654  	}
   655  	new_exp := reg.ReplaceAllString(exp, "SHOW COLUMNS IN ")
   656  	return new_exp, nil
   657  
   658  }