github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/function/builtin/multi/concat_ws.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 "github.com/matrixorigin/matrixone/pkg/common/mpool" 19 "github.com/matrixorigin/matrixone/pkg/container/nulls" 20 "github.com/matrixorigin/matrixone/pkg/container/types" 21 "github.com/matrixorigin/matrixone/pkg/container/vector" 22 "github.com/matrixorigin/matrixone/pkg/vm/process" 23 ) 24 25 // todo(broccoli): revise this, maybe rewrite this? at least clean up the logic 26 func Concat_ws(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) { 27 resultType := types.Type{Oid: types.T_varchar, Size: 24, Width: types.MaxVarcharLen} 28 if vectors[0].IsScalar() { 29 if vectors[0].ConstVectorIsNull() { 30 return proc.AllocScalarNullVector(resultType), nil 31 } 32 vectorIsConst := make([]bool, 0) 33 inputCleaned := make([]*vector.Vector, 0) // no NULL const vectors 34 AllConst := true 35 for i := 1; i < len(vectors); i++ { 36 if vectors[i].IsScalarNull() { 37 continue 38 } 39 if vectors[i].IsScalar() { 40 vectorIsConst = append(vectorIsConst, true) 41 } else { 42 vectorIsConst = append(vectorIsConst, false) 43 AllConst = false 44 } 45 inputCleaned = append(inputCleaned, vectors[i]) 46 } 47 separator := vectors[0].GetString(0) 48 if AllConst { 49 return concatWsWithConstSeparatorAllConst(inputCleaned, separator, proc.Mp()) 50 } 51 return concatWsWithConstSeparator(inputCleaned, separator, vectorIsConst, proc) 52 } else { 53 vectorIsConst := make([]bool, 0) 54 inputCleaned := make([]*vector.Vector, 0) // no NULL const vectors 55 AllConst := true 56 for i := 1; i < len(vectors); i++ { 57 if vectors[i].IsScalarNull() { 58 continue 59 } 60 if vectors[i].IsScalar() { 61 vectorIsConst = append(vectorIsConst, true) 62 } else { 63 vectorIsConst = append(vectorIsConst, false) 64 AllConst = false 65 } 66 inputCleaned = append(inputCleaned, vectors[i]) 67 } 68 separator := vectors[0] 69 if AllConst { 70 return concatWsAllConst(inputCleaned, separator, proc) 71 } else { 72 return concatWs(inputCleaned, separator, vectorIsConst, proc) 73 } 74 } 75 } 76 77 func concatWs(inputCleaned []*vector.Vector, separator *vector.Vector, vectorIsConst []bool, proc *process.Process) (*vector.Vector, error) { 78 separators := vector.MustStrCols(separator) 79 length := len(separators) 80 resultType := types.Type{Oid: types.T_varchar, Size: 24, Width: types.MaxVarcharLen} 81 resultNsp := new(nulls.Nulls) 82 resultValues := make([]string, length) 83 for i := 0; i < length; i++ { 84 allNull := true 85 for j := range inputCleaned { 86 if vectorIsConst[j] { 87 allNull = false 88 if len(resultValues[i]) > 0 { 89 resultValues[i] += separators[i] 90 } 91 resultValues[i] += inputCleaned[j].GetString(0) 92 } else { 93 if nulls.Contains(inputCleaned[j].Nsp, uint64(i)) { 94 continue 95 } 96 allNull = false 97 if len(resultValues[i]) > 0 { 98 resultValues[i] += separators[i] 99 } 100 resultValues[i] += inputCleaned[j].GetString(int64(i)) 101 } 102 } 103 if allNull { 104 nulls.Add(resultNsp, uint64(i)) 105 } 106 } 107 resultVector := vector.NewWithStrings(resultType, resultValues, resultNsp, proc.Mp()) 108 return resultVector, nil 109 } 110 111 func concatWsAllConst(inputCleaned []*vector.Vector, separator *vector.Vector, proc *process.Process) (*vector.Vector, error) { 112 separators := vector.MustStrCols(separator) 113 length := len(separators) 114 resultType := types.Type{Oid: types.T_varchar, Size: 24, Width: types.MaxVarcharLen} 115 resultNsp := new(nulls.Nulls) 116 resultValues := make([]string, length) 117 for i := 0; i < length; i++ { 118 allNull := true 119 for j := range inputCleaned { 120 if len(resultValues[i]) > 0 { 121 resultValues[i] += separators[i] 122 } 123 allNull = false 124 resultValues[i] += inputCleaned[j].GetString(0) 125 } 126 if allNull { // this check is redundant 127 nulls.Add(resultNsp, uint64(i)) 128 } 129 } 130 resultVector := vector.NewWithStrings(resultType, resultValues, resultNsp, proc.Mp()) 131 return resultVector, nil 132 } 133 134 // the inputs are guaranteed to be scalar non-NULL 135 func concatWsWithConstSeparatorAllConst(inputCleaned []*vector.Vector, separator string, mp *mpool.MPool) (*vector.Vector, error) { 136 resultType := types.Type{Oid: types.T_varchar, Size: 24, Width: types.MaxVarcharLen} 137 res := "" 138 for i := range inputCleaned { 139 res = res + inputCleaned[i].GetString(0) 140 if i+1 == len(inputCleaned) { 141 break 142 } else { 143 res += separator 144 } 145 } 146 return vector.NewConstString(resultType, 1, res, mp), nil 147 } 148 149 // inputCleaned does not have NULL const 150 func concatWsWithConstSeparator(inputCleaned []*vector.Vector, separator string, vectorIsConst []bool, proc *process.Process) (*vector.Vector, error) { 151 length := 0 152 for i := range inputCleaned { 153 inputI := vector.MustBytesCols(inputCleaned[i]) 154 lengthI := len(inputI) 155 if lengthI == 0 { 156 length = 0 // this means that one column that needs to be concatenated is empty 157 break 158 } 159 if lengthI > length { 160 length = lengthI 161 } 162 } 163 164 resultType := types.Type{Oid: types.T_varchar, Size: 24, Width: types.MaxVarcharLen} 165 resultNsp := new(nulls.Nulls) 166 resultValues := make([]string, length) 167 168 for i := 0; i < length; i++ { 169 allNull := true 170 for j := range inputCleaned { 171 if vectorIsConst[j] { 172 if j > 0 && !nulls.Contains(inputCleaned[j-1].Nsp, uint64(i)) { 173 resultValues[i] += separator 174 } 175 allNull = false 176 resultValues[i] += inputCleaned[j].GetString(0) 177 } else { 178 if nulls.Contains(inputCleaned[j].Nsp, uint64(i)) { 179 continue 180 } 181 if j > 0 && !nulls.Contains(inputCleaned[j-1].Nsp, uint64(i)) { 182 resultValues[i] += separator 183 } 184 allNull = false 185 resultValues[i] += inputCleaned[j].GetString(int64(i)) 186 } 187 } 188 if allNull { 189 nulls.Add(resultNsp, uint64(i)) 190 } 191 } 192 resultVector := vector.NewWithStrings(resultType, resultValues, resultNsp, proc.Mp()) 193 return resultVector, nil 194 }