github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/order_binder.go (about)

     1  // Copyright 2022 Matrix Origin
     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 plan
    16  
    17  import (
    18  	"go/constant"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    21  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    22  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    23  )
    24  
    25  func NewOrderBinder(projectionBinder *ProjectionBinder, selectList tree.SelectExprs) *OrderBinder {
    26  	return &OrderBinder{
    27  		ProjectionBinder: projectionBinder,
    28  		selectList:       selectList,
    29  	}
    30  }
    31  
    32  func (b *OrderBinder) BindExpr(astExpr tree.Expr) (*plan.Expr, error) {
    33  	if colRef, ok := astExpr.(*tree.UnresolvedName); ok && colRef.NumParts == 1 {
    34  		if selectItem, ok := b.ctx.aliasMap[colRef.Parts[0]]; ok {
    35  			return &plan.Expr{
    36  				Typ: b.ctx.projects[selectItem.idx].Typ,
    37  				Expr: &plan.Expr_Col{
    38  					Col: &plan.ColRef{
    39  						RelPos: b.ctx.projectTag,
    40  						ColPos: selectItem.idx,
    41  					},
    42  				},
    43  			}, nil
    44  		}
    45  	}
    46  
    47  	if numVal, ok := astExpr.(*tree.NumVal); ok {
    48  		switch numVal.Value.Kind() {
    49  		case constant.Int:
    50  			colPos, _ := constant.Int64Val(numVal.Value)
    51  			if numVal.Negative() {
    52  				colPos = -colPos
    53  			}
    54  			if colPos < 1 || int(colPos) > len(b.ctx.projects) {
    55  				return nil, moerr.NewSyntaxError(b.GetContext(), "ORDER BY position %v is not in select list", colPos)
    56  			}
    57  
    58  			colPos = colPos - 1
    59  			return &plan.Expr{
    60  				Typ: b.ctx.projects[colPos].Typ,
    61  				Expr: &plan.Expr_Col{
    62  					Col: &plan.ColRef{
    63  						RelPos: b.ctx.projectTag,
    64  						ColPos: int32(colPos),
    65  					},
    66  				},
    67  			}, nil
    68  
    69  		default:
    70  			return nil, moerr.NewSyntaxError(b.GetContext(), "non-integer constant in ORDER BY")
    71  		}
    72  	}
    73  
    74  	astExpr, err := b.ctx.qualifyColumnNames(astExpr, AliasBeforeColumn)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	expr, err := b.ProjectionBinder.BindExpr(astExpr, 0, true)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	var colPos int32
    85  	var ok bool
    86  
    87  	exprStr := expr.String()
    88  	if colPos, ok = b.ctx.projectByExpr[exprStr]; !ok {
    89  		if b.ctx.isDistinct {
    90  			return nil, moerr.NewSyntaxError(b.GetContext(), "for SELECT DISTINCT, ORDER BY expressions must appear in select list")
    91  		}
    92  
    93  		colPos = int32(len(b.ctx.projects))
    94  		b.ctx.projectByExpr[exprStr] = colPos
    95  		b.ctx.projects = append(b.ctx.projects, expr)
    96  	}
    97  
    98  	expr = &plan.Expr{
    99  		Typ: b.ctx.projects[colPos].Typ,
   100  		Expr: &plan.Expr_Col{
   101  			Col: &plan.ColRef{
   102  				RelPos: b.ctx.projectTag,
   103  				ColPos: colPos,
   104  			},
   105  		},
   106  	}
   107  
   108  	return expr, err
   109  }