...

Source file src/cloud.google.com/go/bigquery/internal/query/order.go

Documentation: cloud.google.com/go/bigquery/internal/query

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package query
    16  
    17  import (
    18  	"strings"
    19  )
    20  
    21  type qnode struct {
    22  	query    string
    23  	children []*qnode
    24  }
    25  
    26  // HasOrderedResults checks if a given SQL query returns ordered results.
    27  // This function uses a naive approach of checking the root level query
    28  // ( ignoring subqueries, functions calls, etc ) and checking
    29  // if it contains an ORDER BY clause.
    30  func HasOrderedResults(sql string) bool {
    31  	cleanedQuery := strings.TrimSpace(sql)
    32  	if !strings.HasPrefix(cleanedQuery, "(") {
    33  		cleanedQuery = "(" + cleanedQuery + ")"
    34  	}
    35  	root := &qnode{query: cleanedQuery, children: []*qnode{}}
    36  	curNode := root
    37  	indexStack := []int{}
    38  	nodeStack := []*qnode{}
    39  	for i, c := range cleanedQuery {
    40  		if c == '(' {
    41  			indexStack = append(indexStack, i)
    42  			nextNode := &qnode{children: []*qnode{}}
    43  			curNode.children = append(curNode.children, nextNode)
    44  			nodeStack = append(nodeStack, curNode)
    45  			curNode = nextNode
    46  		}
    47  		if c == ')' {
    48  			if len(indexStack) == 0 {
    49  				// unbalanced
    50  				return false
    51  			}
    52  			start := indexStack[len(indexStack)-1]
    53  			indexStack = indexStack[:len(indexStack)-1]
    54  
    55  			curNode.query = cleanedQuery[start+1 : i]
    56  
    57  			curNode = nodeStack[len(nodeStack)-1]
    58  			nodeStack = nodeStack[:len(nodeStack)-1]
    59  		}
    60  	}
    61  	curNode = root.children[0]
    62  	q := curNode.query
    63  	for _, c := range curNode.children {
    64  		q = strings.Replace(q, c.query, "", 1)
    65  	}
    66  	return strings.Contains(strings.ToUpper(q), "ORDER BY")
    67  }
    68  

View as plain text