Parses a SQL standard interval string. See the following links for examples: - http://www.postgresql.org/docs/9.1/static/datatype-datetime.html#DATATYPE-INTERVAL-INPUT-EXAMPLES - http://www.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.esqlc.doc/ids_esqlc_0190.htm
(s string, itm types.IntervalTypeMetadata)
| 187 | // - http://www.postgresql.org/docs/9.1/static/datatype-datetime.html#DATATYPE-INTERVAL-INPUT-EXAMPLES |
| 188 | // - http://www.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.esqlc.doc/ids_esqlc_0190.htm |
| 189 | func sqlStdToDuration(s string, itm types.IntervalTypeMetadata) (duration.Duration, error) { |
| 190 | var d duration.Duration |
| 191 | parts := strings.Fields(s) |
| 192 | if len(parts) > 3 || len(parts) == 0 { |
| 193 | return d, newInvalidSQLDurationError(s) |
| 194 | } |
| 195 | // Index of which part(s) have been parsed for detecting bad order such as `HH:MM:SS Year-Month`. |
| 196 | parsedIdx := nothingParsed |
| 197 | // Both 'Day' and 'Second' can be float, but 'Day Second'::interval is invalid. |
| 198 | floatParsed := false |
| 199 | // Parsing backward makes it easy to distinguish 'Day' and 'Second' when encountering a single value. |
| 200 | // `1-2 5 9:` and `1-2 5` |
| 201 | // | | |
| 202 | // day ---+ | |
| 203 | // second ---------------+ |
| 204 | for i := len(parts) - 1; i >= 0; i-- { |
| 205 | // Parses leading sign |
| 206 | part := parts[i] |
| 207 | |
| 208 | consumeNeg := func(str string) (newStr string, mult int64, ok bool) { |
| 209 | neg := false |
| 210 | // Consumes [-+] |
| 211 | if str != "" { |
| 212 | c := str[0] |
| 213 | if c == '-' || c == '+' { |
| 214 | neg = c == '-' |
| 215 | str = str[1:] |
| 216 | } |
| 217 | } |
| 218 | if len(str) == 0 { |
| 219 | return str, 0, false |
| 220 | } |
| 221 | if str[0] == '-' || str[0] == '+' { |
| 222 | return str, 0, false |
| 223 | } |
| 224 | |
| 225 | mult = 1 |
| 226 | if neg { |
| 227 | mult = -1 |
| 228 | } |
| 229 | return str, mult, true |
| 230 | } |
| 231 | |
| 232 | var mult int64 |
| 233 | var ok bool |
| 234 | if part, mult, ok = consumeNeg(part); !ok { |
| 235 | return d, newInvalidSQLDurationError(s) |
| 236 | } |
| 237 | |
| 238 | if strings.ContainsRune(part, ':') { |
| 239 | // Try to parse as HH:MM:SS |
| 240 | if parsedIdx != nothingParsed { |
| 241 | return d, newInvalidSQLDurationError(s) |
| 242 | } |
| 243 | parsedIdx = hmsParsed |
| 244 | // Colon-separated intervals in Postgres are odd. They have day, hour, |
| 245 | // minute, or second parts depending on number of fields and if the field |
| 246 | // is an int or float. |
no test coverage detected
searching dependent graphs…