@@ -1007,6 +1007,8 @@ absl::Status FromProtoMessage(
10071007 struct FieldVars {
10081008 const FieldDescriptor* absl_nonnull field_descriptor;
10091009 absl::string_view attr_name;
1010+ // Whether this is an extension field that is not on the requested schema.
1011+ bool is_non_schema_extension = false ;
10101012 std::optional<DataSlice> value;
10111013 };
10121014
@@ -1033,7 +1035,11 @@ absl::Status FromProtoMessage(
10331035 // For explicit entity schemas, use the schema attr names as the list of
10341036 // fields and extensions to convert.
10351037 ASSIGN_OR_RETURN (vars->schema_attr_names , schema->GetAttrNames ());
1036- vars->fields .reserve (vars->schema_attr_names .size ());
1038+ const int64_t max_num_fields =
1039+ vars->schema_attr_names .size () +
1040+ ((extension_map != nullptr ) ? extension_map->extension_fields .size ()
1041+ : 0 );
1042+ vars->fields .reserve (max_num_fields);
10371043 for (const auto & attr_name : vars->schema_attr_names ) {
10381044 if (attr_name.starts_with (' (' ) && attr_name.ends_with (' )' )) {
10391045 // Interpret attrs with parentheses as fully-qualified extension paths.
@@ -1053,11 +1059,11 @@ absl::Status FromProtoMessage(
10531059 field->full_name (), message_descriptor.full_name (),
10541060 field->containing_type ()->full_name ()));
10551061 }
1056- vars->fields .emplace_back (field, attr_name);
1062+ vars->fields .emplace_back (field, attr_name, false );
10571063 } else {
10581064 const auto * field = message_descriptor.FindFieldByName (attr_name);
10591065 if (field != nullptr ) {
1060- vars->fields .emplace_back (field, attr_name);
1066+ vars->fields .emplace_back (field, attr_name, false );
10611067 }
10621068 }
10631069 }
@@ -1071,19 +1077,23 @@ absl::Status FromProtoMessage(
10711077 for (int i_field = 0 ; i_field < message_descriptor.field_count ();
10721078 ++i_field) {
10731079 const auto * field = message_descriptor.field (i_field);
1074- vars->fields .emplace_back (field, field->name ());
1080+ vars->fields .emplace_back (field, field->name (), false );
10751081 }
1076- if (extension_map != nullptr ) {
1077- for (const auto & [attr_name, field] : extension_map->extension_fields ) {
1078- if (field->containing_type () != &message_descriptor) {
1079- return absl::InvalidArgumentError (absl::StrFormat (
1080- " extension \" %s\" exists, but isn't an extension "
1081- " on target message type \" %s\" , expected \" %s\" " ,
1082- field->full_name (), message_descriptor.full_name (),
1083- field->containing_type ()->full_name ()));
1084- }
1085- vars->fields .emplace_back (field, attr_name);
1082+ }
1083+ if (extension_map != nullptr ) {
1084+ for (const auto & [attr_name, field] : extension_map->extension_fields ) {
1085+ if (vars->schema_attr_names .contains (attr_name)) {
1086+ // Already handled by the schema.
1087+ continue ;
1088+ }
1089+ if (field->containing_type () != &message_descriptor) {
1090+ return absl::InvalidArgumentError (absl::StrFormat (
1091+ " extension \" %s\" exists, but isn't an extension "
1092+ " on target message type \" %s\" , expected \" %s\" " ,
1093+ field->full_name (), message_descriptor.full_name (),
1094+ field->containing_type ()->full_name ()));
10861095 }
1096+ vars->fields .emplace_back (field, attr_name, true );
10871097 }
10881098 }
10891099
@@ -1098,7 +1108,8 @@ absl::Status FromProtoMessage(
10981108 for (auto & field_vars : vars->fields ) {
10991109 RETURN_IF_ERROR (FromProtoField (
11001110 db, field_vars.attr_name , field_vars.attr_name ,
1101- *field_vars.field_descriptor , messages, itemid, schema,
1111+ *field_vars.field_descriptor , messages, itemid,
1112+ field_vars.is_non_schema_extension ? std::nullopt : schema,
11021113 allocated_schema_metadata, extension_map,
11031114 /* ignore_field_presence=*/ false , executor, field_vars.value ));
11041115 }
@@ -1107,10 +1118,12 @@ absl::Status FromProtoMessage(
11071118 &result]() -> absl::Status {
11081119 std::vector<absl::string_view> value_attr_names;
11091120 std::vector<DataSlice> values;
1121+ bool has_non_schema_extensions = false ;
11101122 for (auto & field_vars : vars->fields ) {
11111123 if (field_vars.value .has_value ()) {
11121124 values.push_back (*std::move (field_vars.value ));
11131125 value_attr_names.push_back (field_vars.attr_name );
1126+ has_non_schema_extensions |= field_vars.is_non_schema_extension ;
11141127 }
11151128 }
11161129
@@ -1126,13 +1139,13 @@ absl::Status FromProtoMessage(
11261139 /* itemid=*/ vars->itemid ));
11271140 } else { // schema != OBJECT
11281141 ASSIGN_OR_RETURN (
1129- result,
1130- EntityCreator::Shaped ( db, std::move (result_shape),
1131- /* attr_names=*/ std::move (value_attr_names),
1132- /* values=*/ std::move (values),
1133- /* schema=*/ std::move (vars->requested_schema ),
1134- /* overwrite_schema=*/ false ,
1135- /* itemid=*/ vars->itemid ));
1142+ result, EntityCreator::Shaped (
1143+ db, std::move (result_shape),
1144+ /* attr_names=*/ std::move (value_attr_names),
1145+ /* values=*/ std::move (values),
1146+ /* schema=*/ std::move (vars->requested_schema ),
1147+ /* overwrite_schema=*/ has_non_schema_extensions ,
1148+ /* itemid=*/ vars->itemid ));
11361149 }
11371150 } else { // schema == nullopt
11381151 ASSIGN_OR_RETURN (result, EntityCreator::Shaped (
0 commit comments