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 }