github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/function/func_str_to_date.go (about) 1 // Copyright 2021 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 function 16 17 import ( 18 "context" 19 "github.com/matrixorigin/matrixone/pkg/common/moerr" 20 "github.com/matrixorigin/matrixone/pkg/container/types" 21 "github.com/matrixorigin/matrixone/pkg/container/vector" 22 "github.com/matrixorigin/matrixone/pkg/sql/plan/function/functionUtil" 23 "github.com/matrixorigin/matrixone/pkg/vm/process" 24 "unicode" 25 ) 26 27 func builtInStrToDate(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int) error { 28 p1 := vector.GenerateFunctionStrParameter(parameters[0]) 29 p2 := vector.GenerateFunctionStrParameter(parameters[1]) 30 31 rs := vector.MustFunctionResult[types.Date](result) 32 33 time := NewGeneralTime() 34 for i := uint64(0); i < uint64(length); i++ { 35 v1, null1 := p1.GetStrValue(i) 36 v2, null2 := p2.GetStrValue(i) 37 if null1 || null2 { 38 if err := rs.Append(0, true); err != nil { 39 return err 40 } 41 } else { 42 time.ResetTime() 43 44 success := coreStrToDate(proc.Ctx, time, functionUtil.QuickBytesToStr(v1), functionUtil.QuickBytesToStr(v2)) 45 if success { 46 if types.ValidDate(int32(time.year), time.month, time.day) { 47 value := types.DateFromCalendar(int32(time.year), time.month, time.day) 48 if err := rs.Append(value, false); err != nil { 49 return err 50 } 51 continue 52 } 53 } 54 if err := rs.Append(0, true); err != nil { 55 return err 56 } 57 } 58 } 59 60 return nil 61 } 62 63 func builtInStrToDatetime(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int) error { 64 p1 := vector.GenerateFunctionStrParameter(parameters[0]) 65 p2 := vector.GenerateFunctionStrParameter(parameters[1]) 66 67 rs := vector.MustFunctionResult[types.Datetime](result) 68 69 time := NewGeneralTime() 70 for i := uint64(0); i < uint64(length); i++ { 71 v1, null1 := p1.GetStrValue(i) 72 v2, null2 := p2.GetStrValue(i) 73 if null1 || null2 { 74 if err := rs.Append(0, true); err != nil { 75 return err 76 } 77 } else { 78 time.ResetTime() 79 80 success := coreStrToDate(proc.Ctx, time, functionUtil.QuickBytesToStr(v1), functionUtil.QuickBytesToStr(v2)) 81 if success { 82 if types.ValidDatetime(int32(time.year), time.month, time.day) && types.ValidTimeInDay(time.hour, time.minute, time.second) { 83 value := types.DatetimeFromClock(int32(time.year), time.month, time.day, time.hour, time.minute, time.second, time.microsecond) 84 if err := rs.Append(value, false); err != nil { 85 return err 86 } 87 continue 88 } 89 } 90 if err := rs.Append(0, true); err != nil { 91 return err 92 } 93 } 94 } 95 96 return nil 97 } 98 99 func builtInStrToTime(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int) error { 100 p1 := vector.GenerateFunctionStrParameter(parameters[0]) 101 p2 := vector.GenerateFunctionStrParameter(parameters[1]) 102 103 rs := vector.MustFunctionResult[types.Time](result) 104 105 time := NewGeneralTime() 106 for i := uint64(0); i < uint64(length); i++ { 107 v1, null1 := p1.GetStrValue(i) 108 v2, null2 := p2.GetStrValue(i) 109 if null1 || null2 { 110 if err := rs.Append(0, true); err != nil { 111 return err 112 } 113 } else { 114 time.ResetTime() 115 116 success := coreStrToDate(proc.Ctx, time, functionUtil.QuickBytesToStr(v1), functionUtil.QuickBytesToStr(v2)) 117 if success { 118 if types.ValidTime(uint64(time.hour), uint64(time.minute), uint64(time.second)) { 119 value := types.TimeFromClock(false, uint64(time.hour), time.minute, time.second, time.microsecond) 120 if err := rs.Append(value, false); err != nil { 121 return err 122 } 123 continue 124 } 125 } 126 if err := rs.Append(0, true); err != nil { 127 return err 128 } 129 } 130 } 131 132 return nil 133 } 134 135 func coreStrToDate(cctx context.Context, t *GeneralTime, date string, format string) bool { 136 ctx := make(map[string]int) 137 success := strToDate2(cctx, t, date, format, ctx) 138 if !success { 139 return false 140 } 141 if err := checkMysqlTime(cctx, t, ctx); err != nil { 142 return false 143 } 144 return true 145 } 146 147 // strToDate converts date string according to format, 148 // the value will be stored in argument ctx. the second return value is true when success 149 func strToDate2(cctx context.Context, t *GeneralTime, date string, format string, ctx map[string]int) (success bool) { 150 date = trimWhiteSpace(date) 151 format = trimWhiteSpace(format) 152 153 token, formatRemain, succ := nextFormatToken(format) 154 if !succ { 155 return false 156 } 157 158 if token == "" { 159 if len(date) != 0 { 160 // Extra characters at the end of date are ignored 161 return true 162 } 163 // Normal case. Both token and date are empty now. 164 return true 165 } 166 167 if len(date) == 0 { 168 ctx[token] = 0 169 return true 170 } 171 172 dateRemain, succ := matchDateWithToken(t, date, token, ctx) 173 if !succ { 174 return false 175 } 176 177 return strToDate2(cctx, t, dateRemain, formatRemain, ctx) 178 } 179 180 // checkMysqlTime fixes the Time use the values in the context. 181 func checkMysqlTime(cctx context.Context, t *GeneralTime, ctx map[string]int) error { 182 if valueAMorPm, ok := ctx["%p"]; ok { 183 if _, ok := ctx["%H"]; ok { 184 return moerr.NewInternalError(cctx, "Truncated incorrect %-.64s value: '%-.128s'", "time", t) 185 } 186 if t.getHour() == 0 { 187 return moerr.NewInternalError(cctx, "Truncated incorrect %-.64s value: '%-.128s'", "time", t) 188 } 189 if t.getHour() == 12 { 190 // 12 is a special hour. 191 switch valueAMorPm { 192 case timeOfAM: 193 t.setHour(0) 194 case timeOfPM: 195 t.setHour(12) 196 } 197 return nil 198 } 199 if valueAMorPm == timeOfPM { 200 t.setHour(t.getHour() + 12) 201 } 202 } else { 203 if _, ok := ctx["%h"]; ok && t.getHour() == 12 { 204 t.setHour(0) 205 } 206 } 207 return nil 208 } 209 210 // trim spaces in strings 211 func trimWhiteSpace(input string) string { 212 for i, c := range input { 213 if !unicode.IsSpace(c) { 214 return input[i:] 215 } 216 } 217 return "" 218 } 219 220 // nextFormatToken takes next one format control token from the string. 221 // such as: format "%d %H %m" will get token "%d" and the remain is " %H %m". 222 func nextFormatToken(format string) (token string, remain string, success bool) { 223 if len(format) == 0 { 224 return "", "", true 225 } 226 227 // Just one character. 228 if len(format) == 1 { 229 if format[0] == '%' { 230 return "", "", false 231 } 232 return format, "", true 233 } 234 235 // More than one character. 236 if format[0] == '%' { 237 return format[:2], format[2:], true 238 } 239 240 return format[:1], format[1:], true 241 }