| @@ -58,46 +58,7 @@ time_t ParseDateTimeLiteral(string time) · 57 unmodified lines |
| 58 | 58 | time.erase(time.size() - 1); |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | | − // Need a "generic" ParseTimestamp function... |
| 62 | | − // istringstream in { time }; |
| 63 | | − // sys_seconds timestamp; |
| 64 | | − // |
| 65 | | − // // Try parsing several date-time formats formatted timestamp string |
| 66 | | − // // using the Hinnant date library: https://github.com/HowardHinnant/date |
| 67 | | − // |
| 68 | | − // // Need to try several date/time format variations per: |
| 69 | | − // // https://howardhinnant.github.io/date/date.html#from_stream_formatting |
| 70 | | − // /* |
| 71 | | − // istringstream in { "2018-01-12 12:05:14" }; |
| 72 | | − // sys_seconds timestamp; |
| 73 | | − // |
| 74 | | − // in >> parse("%Y-%m-%dT%T%z", timestamp); |
| 75 | | − // |
| 76 | | − // if (bool(in)) |
| 77 | | − // { |
| 78 | | − // std::cout << "Parsed XML time: " << system_clock::to_time_t(timestamp) << "\n"; |
| 79 | | − // } |
| 80 | | − // else |
| 81 | | − // { |
| 82 | | − // in.clear(); |
| 83 | | − // in.str("2018-01-12 12:05:14"); |
| 84 | | − // in >> parse("%F%n %T", timestamp); |
| 85 | | − // |
| 86 | | − // if (bool(in)) |
| 87 | | − // { |
| 88 | | − // std::cout << "Parsed std time: " << system_clock::to_time_t(timestamp) << "\n"; |
| 89 | | − // } |
| 90 | | − // else |
| 91 | | − // { |
| 92 | | − // std::cout << "Failed to parse time...\n"; |
| 93 | | − // } |
| 94 | | − // } |
| 95 | | − // */ |
| 96 | | − // |
| 97 | | − // // Try XML format, e.g.: 2018-03-14T19:23:11.665-04:00: |
| 98 | | − // in >> parse("%Y-%m-%dT%T%z", timestamp); |
| 99 | | − |
| 100 | | − return ParseXMLTimestamp(time.c_str()); |
| 61 | + return ParseTimestamp(time.c_str()); |
| 101 | 62 | } |
| 102 | 63 | |
| 103 | 64 | FilterExpressionException::FilterExpressionException(string message) noexcept : |
| @@ -253,14 +214,26 @@ void FilterExpressionParser::Evaluate() · 149 unmodified lines |
| 253 | 214 | ValueExpressionPtr result = expressionTree->Evaluate(row); |
| 254 | 215 | |
| 255 | 216 | // If final result is Null (due to Null propagation), treat result as False |
| 256 | | − if (result->DataType == ExpressionDataType::Null) |
| 257 | | − result = ExpressionTree::False; |
| 217 | + if (result->IsNullable) |
| 218 | + { |
| 219 | + NullableType value = Cast<NullableType>(result->Value); |
| 220 | + |
| 221 | + if (!value.HasValue()) |
| 222 | + result = ExpressionTree::False; |
| 223 | + } |
| 258 | 224 | |
| 259 | 225 | // Final expression should have a boolean data type (it's part of a WHERE clause) |
| 260 | 226 | if (result->DataType != ExpressionDataType::Boolean) |
| 261 | 227 | throw FilterExpressionException("Final expression tree evaluation did not result in a boolean value, result data type is " + string(EnumName(result->DataType))); |
| 262 | 228 | |
| 263 | | − if (Cast<bool>(CastSharedPtr<ValueExpression>(result)->Value)) |
| 229 | + bool expressionValue; |
| 230 | + |
| 231 | + if (result->IsNullable) |
| 232 | + expressionValue = static_cast<bool>(Cast<Nullable<bool>>(result->Value).Value); |
| 233 | + else |
| 234 | + expressionValue = Cast<bool>(result->Value); |
| 235 | + |
| 236 | + if (expressionValue) |
| 264 | 237 | { |
| 265 | 238 | Nullable<guid> signalIDField = row->ValueAsGuid(signalIDColumnIndex); |
| 266 | 239 | |