MCPcopy Create free account
hub / github.com/apecloud/myduckserver / encodeJsonObject

Function encodeJsonObject

binlogreplication/binlog_json_serialization.go:148–229  ·  view source on GitHub ↗

encodeJsonObject encodes the specified |jsonObject| into MySQL's internal JSON encoding and returns the type ID indicating whether this is a small or large object, the encoded object data, and any error encountered. The |largeEncoding| param controls whether this function will use the small object e

(jsonObject map[string]any, largeEncoding bool)

Source from the content-addressed store, hash-verified

146// - Value Entries (variable): 1 per value; 1 byte for type ID, 2 bytes for offset or inlined literal value for jsonTypeSmallObject, otherwise 4
147// - Keys (variable): 1 per key; encoded string bytes
148// - Values (variable): 1 per value; encoded value bytes
149func encodeJsonObject(jsonObject map[string]any, largeEncoding bool) (typeId byte, encodedObject []byte, err error) {
150 var keyEntriesBuffer []byte
151 var keysBuffer []byte
152 nextKeysOffset := calculateInitialObjectKeysOffset(len(jsonObject), largeEncoding)
153
154 // Sort the keys so that we can process the keys and values in a consistent order. MySQL seems to sort
155 // json keys internally first by length, then alphabetically, but correct replication doesn't seem to
156 // rely on matching that behavior.
157 sortedKeys := make([]string, 0, len(jsonObject))
158 for key := range jsonObject {
159 sortedKeys = append(sortedKeys, key)
160 }
161 sort.Strings(sortedKeys)
162
163 // Process keys first, since value entry data depends on offsets that we don't know until we
164 // process all the keys.
165 for _, key := range sortedKeys {
166 // NOTE: Don't use encodeJsonValue for the key – its length gets encoded slightly differently
167 // for JSON objects.
168 encodedValue := []byte(key)
169
170 if !largeEncoding && nextKeysOffset > maxOffsetSize-uint32(len(encodedValue)) {
171 return 0, nil, fmt.Errorf("offset too large for small object encoding")
172 }
173
174 keyEntriesBuffer = appendForEncoding(keyEntriesBuffer, nextKeysOffset, largeEncoding)
175 keyEntriesBuffer = append(keyEntriesBuffer, byte(len(encodedValue)), byte(len(encodedValue)<<8))
176 keysBuffer = append(keysBuffer, encodedValue...)
177 nextKeysOffset += uint32(len(encodedValue))
178 }
179
180 // Process values – since the object values are written after the keys, and we need to store the
181 // offsets to those locations in the value entries that appear before the keys and the values, we
182 // have to make a second pass through the object to process the values once we know the final
183 // length of the keys section.
184 var valueEntriesBuffer []byte
185 var valuesBuffer []byte
186 nextValuesOffset := nextKeysOffset
187 for _, key := range sortedKeys {
188 value := jsonObject[key]
189 typeId, encodedValue, err := encodeJsonValue(value)
190 if err != nil {
191 return 0, nil, err
192 }
193
194 // Literals may be inlined in the value-entries section
195 if typeId == jsonTypeLiteral {
196 valueEntriesBuffer = append(valueEntriesBuffer, typeId)
197 if len(encodedValue) != 1 {
198 return 0, nil, fmt.Errorf("unexpected buffer length")
199 }
200 valueEntriesBuffer = appendForEncoding(valueEntriesBuffer, uint32(encodedValue[0]), largeEncoding)
201 } else {
202 if !largeEncoding && nextValuesOffset > maxOffsetSize-uint32(len(encodedValue)) {
203 return 0, nil, fmt.Errorf("offset too large for small object encoding")
204 }
205

Callers 1

encodeJsonValueFunction · 0.85

Calls 3

appendForEncodingFunction · 0.85
encodeJsonValueFunction · 0.85

Tested by

no test coverage detected