absl::StatusOr ValueToProto()

in frontend/converters/values.cc [412:597]


absl::StatusOr<google::protobuf::Value> ValueToProto(
    const zetasql::Value& value) {
  if (!value.is_valid()) {
    return error::Internal(
        "Uninitialized ZetaSQL value passed to ValueToProto");
  }

  google::protobuf::Value value_pb;
  if (value.is_null()) {
    value_pb.set_null_value(google::protobuf::NullValue());
    return value_pb;
  }

  switch (value.type_kind()) {
    case zetasql::TypeKind::TYPE_BOOL: {
      value_pb.set_bool_value(value.bool_value());
      break;
    }

    case zetasql::TypeKind::TYPE_INT64: {
      value_pb.set_string_value(absl::StrCat(value.int64_value()));
      break;
    }

    case zetasql::TypeKind::TYPE_FLOAT: {
      float val = value.float_value();
      if (std::isfinite(val)) {
        value_pb.set_number_value(static_cast<double>(val));
      } else if (val == std::numeric_limits<float>::infinity()) {
        value_pb.set_string_value("Infinity");
      } else if (val == -std::numeric_limits<float>::infinity()) {
        value_pb.set_string_value("-Infinity");
      } else if (std::isnan(val)) {
        value_pb.set_string_value("NaN");
      } else {
        return error::Internal(absl::StrCat("Unsupported float value ",
                                            value.float_value(),
                                            " passed to ValueToProto"));
      }
      break;
    }

    case zetasql::TypeKind::TYPE_DOUBLE: {
      double val = value.double_value();
      if (std::isfinite(val)) {
        value_pb.set_number_value(val);
      } else if (val == std::numeric_limits<double>::infinity()) {
        value_pb.set_string_value("Infinity");
      } else if (val == -std::numeric_limits<double>::infinity()) {
        value_pb.set_string_value("-Infinity");
      } else if (std::isnan(val)) {
        value_pb.set_string_value("NaN");
      } else {
        return error::Internal(absl::StrCat("Unsupported double value ",
                                            value.double_value(),
                                            " passed to ValueToProto"));
      }
      break;
    }

    case zetasql::TypeKind::TYPE_EXTENDED: {
      auto type_code =
          static_cast<const SpannerExtendedType*>(value.type())->code();
      switch (type_code) {
        case TypeAnnotationCode::PG_JSONB: {
          value_pb.set_string_value(
              std::string(*GetPgJsonbNormalizedValue(value)));
          break;
        }
        case TypeAnnotationCode::PG_NUMERIC: {
          value_pb.set_string_value(
              std::string(*GetPgNumericNormalizedValue(value)));
          break;
        }
        case TypeAnnotationCode::PG_OID: {
          value_pb.set_string_value(absl::StrCat(*GetPgOidValue(value)));
          break;
        }
        default:
          return error::Internal(
              absl::StrCat("Cloud Spanner unsupported ZetaSQL value ",
                           value.DebugString(), " passed to ValueToProto"));
      }
      break;
    }

    case zetasql::TypeKind::TYPE_TIMESTAMP: {
      value_pb.set_string_value(
          absl::StrCat(absl::FormatTime(kRFC3339TimeFormatNoOffset,
                                        value.ToTime(), absl::UTCTimeZone()),
                       "Z"));
      break;
    }

    case zetasql::TypeKind::TYPE_DATE: {
      int32_t days_since_epoch = value.date_value();
      absl::CivilDay epoch_date(1970, 1, 1);
      absl::CivilDay date = epoch_date + days_since_epoch;
      if (date.year() > 9999 || date.year() < 1) {
        return error::Internal(absl::StrCat(
            "Unsupported date value ", value.DebugString(),
            " passed to ValueToProto. Year must be between 1 and 9999."));
      }
      absl::StrAppendFormat(value_pb.mutable_string_value(), "%04d-%02d-%02d",
                            date.year(), date.month(), date.day());
      break;
    }

    case zetasql::TypeKind::TYPE_STRING: {
      value_pb.set_string_value(value.string_value());
      break;
    }

    case zetasql::TypeKind::TYPE_NUMERIC: {
      value_pb.set_string_value(value.numeric_value().ToString());
      break;
    }

    case zetasql::TypeKind::TYPE_JSON: {
      value_pb.set_string_value(value.json_string());
      break;
    }

    case zetasql::TypeKind::TYPE_BYTES: {
      absl::Base64Escape(value.bytes_value(), value_pb.mutable_string_value());
      break;
    }

    case zetasql::TypeKind::TYPE_ENUM: {
      value_pb.set_string_value(std::to_string(value.enum_value()));
      break;
    }

    case zetasql::TypeKind::TYPE_PROTO: {
      std::string strvalue;
      absl::CopyCordToString(value.ToCord(), &strvalue);
      absl::Base64Escape(strvalue, value_pb.mutable_string_value());
      break;
    }

    case zetasql::TYPE_TOKENLIST: {
      absl::Base64Escape(value.tokenlist_value().GetBytes(),
                         value_pb.mutable_string_value());
      break;
    }

    case zetasql::TypeKind::TYPE_INTERVAL: {
      zetasql::IntervalValue interval_value = value.interval_value();
      value_pb.set_string_value(interval_value.ToISO8601());
      break;
    }

    case zetasql::TypeKind::TYPE_ARRAY: {
      google::protobuf::ListValue* list_value_pb =
          value_pb.mutable_list_value();
      for (int i = 0; i < value.num_elements(); ++i) {
        ZETASQL_ASSIGN_OR_RETURN(*list_value_pb->add_values(),
                         ValueToProto(value.element(i)),
                         _ << "\nWhen encoding array element #" << i << ": "
                           << value.element(i).DebugString() << " in "
                           << value.DebugString());
      }
      break;
    }

    case zetasql::TypeKind::TYPE_STRUCT: {
      google::protobuf::ListValue* list_value_pb =
          value_pb.mutable_list_value();
      for (int i = 0; i < value.num_fields(); ++i) {
        ZETASQL_ASSIGN_OR_RETURN(
            *list_value_pb->add_values(), ValueToProto(value.field(i)),
            _ << "\nWhen encoding struct element #" << i << ": "
              << value.field(i).DebugString() << " in " << value.DebugString());
      }
      break;
    }

    default: {
      return error::Internal(
          absl::StrCat("Cloud Spanner unsupported ZetaSQL value ",
                       value.DebugString(), " passed to ValueToProto"));
    }
  }

  return value_pb;
}