deserializeArray serializes an array of given base type.
(ctx *sql.Context, vals []any, baseType *DoltgresType)
| 95 | |
| 96 | // deserializeArray serializes an array of given base type. |
| 97 | func serializeArray(ctx *sql.Context, vals []any, baseType *DoltgresType) ([]byte, error) { |
| 98 | bb := bytes.Buffer{} |
| 99 | // Write the element count to a buffer. We're using an array since it's stack-allocated, so no need for pooling. |
| 100 | var elementCount [4]byte |
| 101 | binary.LittleEndian.PutUint32(elementCount[:], uint32(len(vals))) |
| 102 | bb.Write(elementCount[:]) |
| 103 | // Create an array that contains the offsets for each value. Since we can't update the offset portion of the buffer |
| 104 | // as we determine the offsets, we have to track them outside the buffer. We'll overwrite the buffer later with the |
| 105 | // correct offsets. The last offset represents the end of the slice, which simplifies the logic for reading elements |
| 106 | // using the "current offset to next offset" strategy. We use a byte slice since the buffer only works with byte |
| 107 | // slices. |
| 108 | offsets := make([]byte, (len(vals)+1)*4) |
| 109 | bb.Write(offsets) |
| 110 | // The starting offset for the first element is Count(uint32) + (NumberOfElementOffsets * sizeof(uint32)) |
| 111 | currentOffset := uint32(4 + (len(vals)+1)*4) |
| 112 | for i := range vals { |
| 113 | // Write the current offset |
| 114 | binary.LittleEndian.PutUint32(offsets[i*4:], currentOffset) |
| 115 | // Handle serialization of the value |
| 116 | // TODO: ARRAYs may be multidimensional, such as ARRAY[[4,2],[6,3]], which isn't accounted for here |
| 117 | serializedVal, err := baseType.SerializeValue(ctx, vals[i]) |
| 118 | if err != nil { |
| 119 | return nil, err |
| 120 | } |
| 121 | // Handle the nil case and non-nil case |
| 122 | if serializedVal == nil { |
| 123 | bb.WriteByte(1) |
| 124 | currentOffset += 1 |
| 125 | } else { |
| 126 | bb.WriteByte(0) |
| 127 | bb.Write(serializedVal) |
| 128 | currentOffset += 1 + uint32(len(serializedVal)) |
| 129 | } |
| 130 | } |
| 131 | // Write the final offset, which will equal the length of the serialized slice |
| 132 | binary.LittleEndian.PutUint32(offsets[len(offsets)-4:], currentOffset) |
| 133 | // Get the final output, and write the updated offsets to it |
| 134 | outputBytes := bb.Bytes() |
| 135 | copy(outputBytes[4:], offsets) |
| 136 | return outputBytes, nil |
| 137 | } |
| 138 | |
| 139 | // deserializeArray deserializes an array of given base type. |
| 140 | func deserializeArray(ctx *sql.Context, data []byte, baseType *DoltgresType) ([]any, error) { |
no test coverage detected