github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/function/builtin/multi/lpad.go (about) 1 // Copyright 2021 - 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 multi 16 17 import ( 18 "math" 19 20 "github.com/matrixorigin/matrixone/pkg/container/nulls" 21 "github.com/matrixorigin/matrixone/pkg/container/types" 22 "github.com/matrixorigin/matrixone/pkg/container/vector" 23 "github.com/matrixorigin/matrixone/pkg/vm/process" 24 ) 25 26 const ( 27 MaxSpacePerRowOfLpad = int64(16 * 1024 * 1024) 28 ParameterSourceString = int(0) 29 ParameterLengths = int(1) 30 ParameterPadString = int(2) 31 ) 32 33 /* 34 First Parameter: source string 35 Second Parameter: length 36 Third Parameter: pad string 37 */ 38 func Lpad(vecs []*vector.Vector, proc *process.Process) (*vector.Vector, error) { 39 if vecs[0].IsScalarNull() || vecs[1].IsScalarNull() || vecs[2].IsScalarNull() { 40 return proc.AllocScalarNullVector(vecs[0].Typ), nil 41 } 42 sourceStr := vector.MustStrCols(vecs[ParameterSourceString]) //Get the first arg 43 44 //characters length not bytes length 45 lengthsOfChars := getLensForLpad(vecs[ParameterLengths].Col) 46 47 //pad string 48 padStr := vector.MustStrCols(vecs[ParameterPadString]) 49 50 constVectors := []bool{vecs[ParameterSourceString].IsScalar(), vecs[ParameterLengths].IsScalar(), vecs[ParameterPadString].IsScalar()} 51 inputNulls := []*nulls.Nulls{vecs[ParameterSourceString].Nsp, vecs[ParameterLengths].Nsp, vecs[ParameterPadString].Nsp} 52 //evaluate bytes space for every row 53 rowCount := vector.Length(vecs[ParameterSourceString]) 54 55 var resultVec *vector.Vector = nil 56 resultValues := make([]string, rowCount) 57 resultNUll := nulls.NewWithSize(rowCount) 58 59 fillLpad(sourceStr, lengthsOfChars, padStr, rowCount, constVectors, resultValues, resultNUll, inputNulls) 60 61 resultVec = vector.NewWithStrings(types.T_varchar.ToType(), resultValues, resultNUll, proc.Mp()) 62 return resultVec, nil 63 } 64 65 func getLensForLpad(col interface{}) []int64 { 66 switch vs := col.(type) { 67 case []int64: 68 return vs 69 case []float64: 70 res := make([]int64, 0, len(vs)) 71 for _, v := range vs { 72 if v > float64(math.MaxInt64) { 73 res = append(res, math.MaxInt64) 74 } else if v < float64(math.MinInt64) { 75 res = append(res, math.MinInt64) 76 } else { 77 res = append(res, int64(v)) 78 } 79 } 80 return res 81 case []uint64: 82 res := make([]int64, 0, len(vs)) 83 for _, v := range vs { 84 if v > uint64(math.MaxInt64) { 85 res = append(res, math.MaxInt64) 86 } else { 87 res = append(res, int64(v)) 88 } 89 } 90 return res 91 } 92 panic("unexpected parameter types were received") 93 } 94 95 func fillLpad(sourceStr []string, lengths []int64, padStr []string, rowCount int, constVectors []bool, results []string, resultNUll *nulls.Nulls, inputNulls []*nulls.Nulls) { 96 for i := 0; i < rowCount; i++ { 97 if ui := uint64(i); nulls.Contains(inputNulls[ParameterSourceString], ui) || 98 nulls.Contains(inputNulls[ParameterLengths], ui) || 99 nulls.Contains(inputNulls[ParameterPadString], ui) { 100 //null 101 nulls.Add(resultNUll, ui) 102 continue 103 } 104 //1.count characters in source and pad 105 var source string 106 if constVectors[ParameterSourceString] { 107 source = sourceStr[0] 108 } else { 109 source = sourceStr[i] 110 } 111 sourceRune := []rune(string(source)) 112 sourceCharCnt := int64(len(sourceRune)) 113 var pad string 114 if constVectors[ParameterPadString] { 115 pad = padStr[0] 116 } else { 117 pad = padStr[i] 118 } 119 padLen := len(pad) 120 if padLen == 0 { 121 //empty string 122 continue 123 } 124 padRune := []rune(string(pad)) 125 padCharCnt := int64(len(padRune)) 126 var targetLength int64 127 if constVectors[ParameterLengths] { 128 targetLength = lengths[0] 129 } else { 130 targetLength = lengths[i] 131 } 132 133 if targetLength < 0 || targetLength > MaxSpacePerRowOfLpad { 134 //NULL 135 nulls.Add(resultNUll, uint64(i)) 136 } else if targetLength == 0 { 137 //empty string 138 } else if targetLength < sourceCharCnt { 139 //shorten source string 140 sourcePart := sourceRune[:targetLength] 141 sourcePartSlice := string(sourcePart) 142 results[i] = sourcePartSlice 143 } else if targetLength >= sourceCharCnt { 144 //calculate the space count 145 r := targetLength - sourceCharCnt 146 //complete pad count 147 p := r / padCharCnt 148 //partial pad count 149 m := r % padCharCnt 150 padPartSlice := string(padRune[:m]) 151 for j := int64(0); j < p; j++ { 152 results[i] += pad 153 } 154 if m != 0 { 155 results[i] += padPartSlice 156 } 157 results[i] += source 158 } 159 } 160 }