in frontend/converters/values.cc [110:410]
absl::StatusOr<zetasql::Value> ValueFromProto(
const google::protobuf::Value& value_pb, const zetasql::Type* type) {
if (value_pb.kind_case() == google::protobuf::Value::kNullValue) {
return zetasql::values::Null(type);
}
switch (type->kind()) {
case zetasql::TypeKind::TYPE_BOOL: {
if (value_pb.kind_case() != google::protobuf::Value::kBoolValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
return zetasql::values::Bool(value_pb.bool_value());
}
case zetasql::TypeKind::TYPE_INT64: {
int64_t num = 0;
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
if (!absl::SimpleAtoi(value_pb.string_value(), &num)) {
return error::CouldNotParseStringAsInteger(value_pb.string_value());
}
return zetasql::values::Int64(num);
}
case zetasql::TypeKind::TYPE_FLOAT: {
double val = 0;
if (value_pb.kind_case() == google::protobuf::Value::kStringValue) {
if (value_pb.string_value() == "Infinity") {
val = std::numeric_limits<float>::infinity();
} else if (value_pb.string_value() == "-Infinity") {
val = -std::numeric_limits<float>::infinity();
} else if (value_pb.string_value() == "NaN") {
val = std::numeric_limits<float>::quiet_NaN();
} else {
return error::CouldNotParseStringAsFloat(value_pb.string_value());
}
} else if (ABSL_PREDICT_TRUE(IsValidFloat(value_pb.number_value()))) {
val = value_pb.number_value();
} else {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
return zetasql::values::Float(val);
}
case zetasql::TypeKind::TYPE_DOUBLE: {
double val = 0;
if (value_pb.kind_case() == google::protobuf::Value::kStringValue) {
if (value_pb.string_value() == "Infinity") {
val = std::numeric_limits<double>::infinity();
} else if (value_pb.string_value() == "-Infinity") {
val = -std::numeric_limits<double>::infinity();
} else if (value_pb.string_value() == "NaN") {
val = std::numeric_limits<double>::quiet_NaN();
} else {
return error::CouldNotParseStringAsDouble(value_pb.string_value());
}
} else if (value_pb.kind_case() ==
google::protobuf::Value::kNumberValue) {
val = value_pb.number_value();
} else {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
return zetasql::values::Double(val);
}
case zetasql::TypeKind::TYPE_EXTENDED: {
auto type_code = static_cast<const SpannerExtendedType*>(type)->code();
switch (type_code) {
case TypeAnnotationCode::PG_JSONB: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
auto pg_jsonb =
CreatePgJsonbValueWithMemoryContext(value_pb.string_value());
if (!pg_jsonb.ok()) {
return error::CouldNotParseStringAsPgJsonb(value_pb.string_value());
}
return *pg_jsonb;
}
case TypeAnnotationCode::PG_NUMERIC: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
auto pg_numeric =
CreatePgNumericValueWithMemoryContext(value_pb.string_value());
if (!pg_numeric.ok()) {
return error::CouldNotParseStringAsPgNumeric(
value_pb.string_value());
}
return *pg_numeric;
}
case TypeAnnotationCode::PG_OID: {
int64_t oid = 0;
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
if (!absl::SimpleAtoi(value_pb.string_value(), &oid)) {
return error::CouldNotParseStringAsPgOid(value_pb.string_value());
}
return CreatePgOidValue(oid);
}
default:
return error::Internal(absl::StrCat(
"Cloud Spanner unsupported type ", type->DebugString(),
" passed to ValueFromProto when parsing ",
value_pb.DebugString()));
}
break;
}
case zetasql::TypeKind::TYPE_TIMESTAMP: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
if (value_pb.string_value() == kCommitTimestampIdentifier) {
return zetasql::values::String(value_pb.string_value());
}
absl::string_view time_str(value_pb.string_value());
if (!absl::ConsumeSuffix(&time_str, "Z")) {
return error::TimestampMustBeInUTCTimeZone(value_pb.string_value());
}
absl::Time time;
std::string error;
if (!absl::ParseTime(kRFC3339TimeFormatNoOffset, time_str, &time,
&error)) {
return error::CouldNotParseStringAsTimestamp(value_pb.string_value(),
error);
}
if (!zetasql::functions::IsValidTime(time)) {
return error::TimestampOutOfRange(
absl::FormatTime(time, absl::UTCTimeZone()));
}
return zetasql::values::Timestamp(time);
}
case zetasql::TypeKind::TYPE_DATE: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
absl::CivilDay date;
if (!absl::ParseCivilTime(value_pb.string_value(), &date)) {
return error::CouldNotParseStringAsDate(value_pb.string_value());
}
if (date.year() < 1 || date.year() > 9999) {
return error::InvalidDate(value_pb.string_value());
}
absl::CivilDay epoch_date(1970, 1, 1);
return zetasql::values::Date(static_cast<int32_t>(date - epoch_date));
}
case zetasql::TypeKind::TYPE_STRING: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
return zetasql::values::String(value_pb.string_value());
}
case zetasql::TypeKind::TYPE_BYTES: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
std::string bytes;
if (!absl::Base64Unescape(value_pb.string_value(), &bytes)) {
return error::CouldNotParseStringAsBytes(value_pb.string_value());
}
return zetasql::values::Bytes(bytes);
}
case zetasql::TypeKind::TYPE_NUMERIC: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
auto status_or_numeric =
zetasql::NumericValue::FromStringStrict(value_pb.string_value());
if (!status_or_numeric.ok()) {
return error::CouldNotParseStringAsNumeric(value_pb.string_value());
}
return zetasql::values::Numeric(status_or_numeric.value());
}
case zetasql::TypeKind::TYPE_JSON: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
auto status_or_json =
zetasql::JSONValue::ParseJSONString(value_pb.string_value());
if (!status_or_json.ok()) {
return error::CouldNotParseStringAsJson(value_pb.string_value());
}
return zetasql::values::Json(std::move(status_or_json.value()));
}
case zetasql::TypeKind::TYPE_TOKENLIST: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
std::string bytes;
if (!absl::Base64Unescape(value_pb.string_value(), &bytes)) {
return error::CouldNotParseStringAsBytes(value_pb.string_value());
}
return TokenListFromBytes(bytes);
}
case zetasql::TypeKind::TYPE_INTERVAL: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
absl::StatusOr<zetasql::IntervalValue> interval_value =
zetasql::IntervalValue::Parse(value_pb.string_value(),
/*allow_nanos=*/true);
if (!interval_value.ok()) {
return error::CouldNotParseStringAsInterval(
value_pb.string_value(), interval_value.status().message());
}
return zetasql::values::Interval(interval_value.value());
}
case zetasql::TypeKind::TYPE_ARRAY: {
if (value_pb.kind_case() != google::protobuf::Value::kListValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
std::vector<zetasql::Value> values(value_pb.list_value().values_size());
for (int i = 0; i < value_pb.list_value().values_size(); ++i) {
const google::protobuf::Value& element_pb =
value_pb.list_value().values(i);
ZETASQL_ASSIGN_OR_RETURN(
values[i],
ValueFromProto(element_pb, type->AsArray()->element_type()),
_ << "\nWhen parsing array element #" << i << ": {"
<< element_pb.DebugString() << "} in " << value_pb.DebugString());
}
return zetasql::values::Array(type->AsArray(), values);
}
case zetasql::TypeKind::TYPE_STRUCT: {
if (value_pb.kind_case() != google::protobuf::Value::kListValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
std::vector<zetasql::Value> values(value_pb.list_value().values_size());
for (int i = 0; i < value_pb.list_value().values_size(); ++i) {
const google::protobuf::Value& field_pb =
value_pb.list_value().values(i);
ZETASQL_ASSIGN_OR_RETURN(
values[i],
ValueFromProto(field_pb, type->AsStruct()->field(i).type),
_ << "\nWhen parsing struct element #" << i << ": {"
<< field_pb.DebugString() << "} in " << value_pb.DebugString());
}
return zetasql::values::Struct(type->AsStruct(), values);
}
case zetasql::TypeKind::TYPE_PROTO: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
std::string bytes;
if (!absl::Base64Unescape(value_pb.string_value(), &bytes)) {
return error::CouldNotParseStringAsBytes(value_pb.string_value());
}
return zetasql::values::Proto(type->AsProto(), absl::Cord(bytes));
}
case zetasql::TypeKind::TYPE_ENUM: {
if (value_pb.kind_case() != google::protobuf::Value::kStringValue) {
return error::ValueProtoTypeMismatch(value_pb.DebugString(),
type->DebugString());
}
int num = 0;
if (!absl::SimpleAtoi(value_pb.string_value(), &num)) {
return error::CouldNotParseStringAsInteger(value_pb.string_value());
}
return zetasql::values::Enum(type->AsEnum(), num);
}
default: {
return error::Internal(absl::StrCat(
"Cloud Spanner unsupported type ", type->DebugString(),
" passed to ValueFromProto when parsing ", value_pb.DebugString()));
}
}
}