@@ -26,6 +26,7 @@ import (
26
26
"github.com/pingcap/parser/terror"
27
27
"github.com/pingcap/tidb/sessionctx"
28
28
"github.com/pingcap/tidb/types"
29
+ driver "github.com/pingcap/tidb/types/parser_driver"
29
30
"github.com/pingcap/tidb/util/chunk"
30
31
"github.com/pingcap/tidb/util/hack"
31
32
"golang.org/x/tools/container/intsets"
@@ -555,3 +556,74 @@ func DisableParseJSONFlag4Expr(expr Expression) {
555
556
}
556
557
expr .GetType ().Flag &= ^ mysql .ParseToJSONFlag
557
558
}
559
+
560
+ // DatumToConstant generates a Constant expression from a Datum.
561
+ func DatumToConstant (d types.Datum , tp byte ) * Constant {
562
+ return & Constant {Value : d , RetType : types .NewFieldType (tp )}
563
+ }
564
+
565
+ // GetParamExpression generate a getparam function expression.
566
+ func GetParamExpression (ctx sessionctx.Context , v * driver.ParamMarkerExpr ) (Expression , error ) {
567
+ useCache := ctx .GetSessionVars ().StmtCtx .UseCache
568
+ tp := types .NewFieldType (mysql .TypeUnspecified )
569
+ types .DefaultParamTypeForValue (v .GetValue (), tp )
570
+ value := & Constant {Value : v .Datum , RetType : tp }
571
+ if useCache {
572
+ f , err := NewFunctionBase (ctx , ast .GetParam , & v .Type ,
573
+ DatumToConstant (types .NewIntDatum (int64 (v .Order )), mysql .TypeLonglong ))
574
+ if err != nil {
575
+ return nil , errors .Trace (err )
576
+ }
577
+ f .GetType ().Tp = v .Type .Tp
578
+ value .DeferredExpr = f
579
+ }
580
+ return value , nil
581
+ }
582
+
583
+ // ConstructPositionExpr constructs PositionExpr with the given ParamMarkerExpr.
584
+ func ConstructPositionExpr (p * driver.ParamMarkerExpr ) * ast.PositionExpr {
585
+ return & ast.PositionExpr {P : p }
586
+ }
587
+
588
+ // PosFromPositionExpr generates a position value from PositionExpr.
589
+ func PosFromPositionExpr (ctx sessionctx.Context , v * ast.PositionExpr ) (int , bool , error ) {
590
+ if v .P == nil {
591
+ return v .N , false , nil
592
+ }
593
+ value , err := GetParamExpression (ctx , v .P .(* driver.ParamMarkerExpr ))
594
+ if err != nil {
595
+ return 0 , true , err
596
+ }
597
+ pos , isNull , err := GetIntFromConstant (ctx , value )
598
+ if err != nil || isNull {
599
+ return 0 , true , errors .Trace (err )
600
+ }
601
+ return pos , false , nil
602
+ }
603
+
604
+ // GetStringFromConstant gets a string value from the Constant expression.
605
+ func GetStringFromConstant (ctx sessionctx.Context , value Expression ) (string , bool , error ) {
606
+ con , ok := value .(* Constant )
607
+ if ! ok {
608
+ err := errors .Errorf ("Not a Constant expression %+v" , value )
609
+ return "" , true , errors .Trace (err )
610
+ }
611
+ str , isNull , err := con .EvalString (ctx , chunk.Row {})
612
+ if err != nil || isNull {
613
+ return "" , true , errors .Trace (err )
614
+ }
615
+ return str , false , nil
616
+ }
617
+
618
+ // GetIntFromConstant gets an interger value from the Constant expression.
619
+ func GetIntFromConstant (ctx sessionctx.Context , value Expression ) (int , bool , error ) {
620
+ str , isNull , err := GetStringFromConstant (ctx , value )
621
+ if err != nil || isNull {
622
+ return 0 , true , errors .Trace (err )
623
+ }
624
+ intNum , err := strconv .Atoi (str )
625
+ if err != nil {
626
+ return 0 , true , nil
627
+ }
628
+ return intNum , false , nil
629
+ }
0 commit comments