Пример #1
0
        internal static void DoWrite(IPAddress ip, int mask, NpgsqlWriteBuffer buf, bool isCidrHandler)
        {
            switch (ip.AddressFamily)
            {
            case AddressFamily.InterNetwork:
                buf.WriteByte(IPv4);
                if (mask == -1)
                {
                    mask = 32;
                }
                break;

            case AddressFamily.InterNetworkV6:
                buf.WriteByte(IPv6);
                if (mask == -1)
                {
                    mask = 128;
                }
                break;

            default:
                throw new InvalidCastException($"Can't handle IPAddress with AddressFamily {ip.AddressFamily}, only InterNetwork or InterNetworkV6!");
            }

            buf.WriteByte((byte)mask);
            buf.WriteByte((byte)(isCidrHandler ? 1 : 0));  // Ignored on server side
            var bytes = ip.GetAddressBytes();

            buf.WriteByte((byte)bytes.Length);
            buf.WriteBytes(bytes, 0, bytes.Length);
        }
Пример #2
0
 internal PgServerMock WriteParseComplete()
 {
     CheckDisposed();
     _writeBuffer.WriteByte((byte)BackendMessageCode.ParseComplete);
     _writeBuffer.WriteInt32(4);
     return(this);
 }
Пример #3
0
 internal override void WriteFully(NpgsqlWriteBuffer buf)
 {
     buf.WriteByte(Code);
     buf.WriteInt32(Length - 1);
     // Error message not supported for now
     Debug.Assert(_errorMessage == null);
     buf.WriteByte(0);
 }
        internal override void WriteFully(NpgsqlWriteBuffer buf)
        {
            Debug.Assert(Name != null && Name.All(c => c < 128));

            buf.WriteByte(Code);
            buf.WriteInt32(Length - 1);
            buf.WriteByte((byte)StatementOrPortal);
            buf.WriteNullTerminatedString(Name);
        }
        public override async Task Write(NpgsqlTsQuery query, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            var numTokens = GetTokenCount(query);

            if (buf.WriteSpaceLeft < 4)
            {
                await buf.Flush(async);
            }
            buf.WriteInt32(numTokens);

            if (numTokens == 0)
            {
                return;
            }

            _stack.Push(query);

            while (_stack.Count > 0)
            {
                if (buf.WriteSpaceLeft < 2)
                {
                    await buf.Flush(async);
                }

                if (_stack.Peek().Kind == NpgsqlTsQuery.NodeKind.Lexeme && buf.WriteSpaceLeft < MaxSingleTokenBytes)
                {
                    await buf.Flush(async);
                }

                var node = _stack.Pop();
                buf.WriteByte(node.Kind == NpgsqlTsQuery.NodeKind.Lexeme ? (byte)1 : (byte)2);
                if (node.Kind != NpgsqlTsQuery.NodeKind.Lexeme)
                {
                    buf.WriteByte((byte)node.Kind);
                    if (node.Kind == NpgsqlTsQuery.NodeKind.Not)
                    {
                        _stack.Push(((NpgsqlTsQueryNot)node).Child);
                    }
                    else
                    {
                        _stack.Push(((NpgsqlTsQueryBinOp)node).Right);
                        _stack.Push(((NpgsqlTsQueryBinOp)node).Left);
                    }
                }
                else
                {
                    var lexemeNode = (NpgsqlTsQueryLexeme)node;
                    buf.WriteByte((byte)lexemeNode.Weights);
                    buf.WriteByte(lexemeNode.IsPrefixSearch ? (byte)1 : (byte)0);
                    buf.WriteString(lexemeNode.Text);
                    buf.WriteByte(0);
                }
            }

            _stack.Clear();
        }
Пример #6
0
        internal override void WriteFully(NpgsqlWriteBuffer buf)
        {
            Debug.Assert(Portal != null && Portal.All(c => c < 128));

            buf.WriteByte(Code);
            buf.WriteInt32(Length - 1);
            Debug.Assert(Portal == string.Empty);
            buf.WriteByte(0);   // Portal is always an empty string
            buf.WriteInt32(MaxRows);
        }
Пример #7
0
        /// <inheritdoc />
        public async Task Write(string value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
        {
            // Initial bitlength byte
            if (buf.WriteSpaceLeft < 4)
            {
                await buf.Flush(async, cancellationToken);
            }
            buf.WriteInt32(value.Length);

            var pos     = 0;
            var byteLen = (value.Length + 7) / 8;
            var bytePos = 0;

            while (true)
            {
                var endBytePos = bytePos + Math.Min(byteLen - bytePos - 1, buf.WriteSpaceLeft);

                for (; bytePos < endBytePos; bytePos++)
                {
                    var b = 0;
                    b += (value[pos++] - '0') << 7;
                    b += (value[pos++] - '0') << 6;
                    b += (value[pos++] - '0') << 5;
                    b += (value[pos++] - '0') << 4;
                    b += (value[pos++] - '0') << 3;
                    b += (value[pos++] - '0') << 2;
                    b += (value[pos++] - '0') << 1;
                    b += (value[pos++] - '0');
                    buf.WriteByte((byte)b);
                }

                if (bytePos >= byteLen - 1)
                {
                    break;
                }
                await buf.Flush(async, cancellationToken);
            }

            if (pos < value.Length)
            {
                if (buf.WriteSpaceLeft < 1)
                {
                    await buf.Flush(async, cancellationToken);
                }

                var remainder = value.Length - pos;
                var lastChunk = 0;
                for (var i = 7; i >= 8 - remainder; i--)
                {
                    lastChunk += (value[pos++] - '0') << i;
                }
                buf.WriteByte((byte)lastChunk);
            }
        }
Пример #8
0
        public async Task Write(GeometryCollection value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            var type = EwkbGeometryType.GeometryCollection;
            var size = SizeOfHeader;
            var srid = GetSrid(value.CRS);

            if (srid != 0)
            {
                size += sizeof(int);
                type |= EwkbGeometryType.HasSrid;
            }

            if (buf.WriteSpaceLeft < size)
            {
                await buf.Flush(async);
            }

            var geometries = value.Geometries;

            buf.WriteByte(0); // Most significant byte first
            buf.WriteInt32((int)type);
            buf.WriteInt32(geometries.Count);

            if (srid != 0)
            {
                buf.WriteInt32(srid);
            }

            for (var i = 0; i < geometries.Count; ++i)
            {
                await Write((GeoJSONObject)geometries[i], buf, lengthCache, parameter, async);
            }
        }
Пример #9
0
        public async Task Write(MultiLineString value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            var type = EwkbGeometryType.MultiLineString;
            var size = SizeOfHeader;
            var srid = GetSrid(value.CRS);

            if (srid != 0)
            {
                size += sizeof(int);
                type |= EwkbGeometryType.HasSrid;
            }

            if (buf.WriteSpaceLeft < size)
            {
                await buf.Flush(async);
            }

            var coordinates = value.Coordinates;

            buf.WriteByte(0); // Most significant byte first
            buf.WriteInt32((int)type);
            buf.WriteInt32(coordinates.Count);

            if (srid != 0)
            {
                buf.WriteInt32(srid);
            }

            for (var i = 0; i < coordinates.Count; ++i)
            {
                await Write(coordinates[i], buf, lengthCache, parameter, async);
            }
        }
Пример #10
0
        public async Task Write(Point value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            var type = EwkbGeometryType.Point;
            var size = SizeOfHeader;
            var srid = GetSrid(value.CRS);

            if (srid != 0)
            {
                size += sizeof(int);
                type |= EwkbGeometryType.HasSrid;
            }

            if (buf.WriteSpaceLeft < size)
            {
                await buf.Flush(async);
            }

            buf.WriteByte(0); // Most significant byte first
            buf.WriteInt32((int)type);

            if (srid != 0)
            {
                buf.WriteInt32(srid);
            }

            await WritePosition(value.Coordinates, buf, async);
        }
Пример #11
0
        /// <inheritdoc />
        public override async Task Write(BitArray value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
        {
            // Initial bitlength byte
            if (buf.WriteSpaceLeft < 4)
            {
                await buf.Flush(async, cancellationToken);
            }
            buf.WriteInt32(value.Length);

            var byteLen = (value.Length + 7) / 8;
            var pos     = 0;

            while (true)
            {
                var endPos = pos + Math.Min(byteLen - pos, buf.WriteSpaceLeft);
                for (; pos < endPos; pos++)
                {
                    var bitPos = pos * 8;
                    var b      = 0;
                    for (var i = 0; i < Math.Min(8, value.Length - bitPos); i++)
                    {
                        b += (value[bitPos + i] ? 1 : 0) << (8 - i - 1);
                    }
                    buf.WriteByte((byte)b);
                }

                if (pos == byteLen)
                {
                    return;
                }
                await buf.Flush(async, cancellationToken);
            }
        }
Пример #12
0
        internal override void WriteFully(NpgsqlWriteBuffer buf)
        {
            buf.WriteByte(Code);
            buf.WriteInt32(Length - 1);

            buf.WriteString(_mechanism);
            buf.WriteByte(0);   // null terminator
            if (_initialResponse == null)
            {
                buf.WriteInt32(-1);
            }
            else
            {
                buf.WriteInt32(_initialResponse.Length);
                buf.WriteBytes(_initialResponse);
            }
        }
Пример #13
0
 public async Task Write(bool value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
 {
     if (buf.WriteSpaceLeft < 5)
     {
         await buf.Flush(async);
     }
     buf.WriteInt32(1);
     buf.WriteByte(value ? (byte)0x80 : (byte)0);
 }
Пример #14
0
 public override async Task Write(ArraySegment <char> value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
 {
     if (buf.WriteSpaceLeft < 1)
     {
         await buf.Flush(async);
     }
     buf.WriteByte(JsonbProtocolVersion);
     await base.Write(value, buf, lengthCache, parameter, async);
 }
Пример #15
0
 /// <inheritdoc />
 public async Task Write(bool value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
 {
     if (buf.WriteSpaceLeft < 5)
     {
         await buf.Flush(async, cancellationToken);
     }
     buf.WriteInt32(1);
     buf.WriteByte(value ? (byte)0x80 : (byte)0);
 }
Пример #16
0
        internal override async Task Write(NpgsqlWriteBuffer buf, bool async)
        {
            Debug.Assert(Statement != null && Statement.All(c => c < 128));

            var queryByteLen = _encoding.GetByteCount(Query);

            if (buf.WriteSpaceLeft < 1 + 4 + Statement.Length + 1)
            {
                await buf.Flush(async);
            }

            var messageLength =
                1 +                         // Message code
                4 +                         // Length
                Statement.Length +
                1 +                         // Null terminator
                queryByteLen +
                1 +                         // Null terminator
                2 +                         // Number of parameters
                ParameterTypeOIDs.Count * 4;

            buf.WriteByte(Code);
            buf.WriteInt32(messageLength - 1);
            buf.WriteNullTerminatedString(Statement);

            await buf.WriteString(Query, queryByteLen, async);

            if (buf.WriteSpaceLeft < 1 + 2)
            {
                await buf.Flush(async);
            }
            buf.WriteByte(0); // Null terminator for the query
            buf.WriteInt16((short)ParameterTypeOIDs.Count);

            foreach (var t in ParameterTypeOIDs)
            {
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32((int)t);
            }
        }
Пример #17
0
    internal static byte[] Generate(NpgsqlWriteBuffer buf, string query)
    {
        Debug.Assert(query.All(c => c < 128));

        var queryByteLen = Encoding.ASCII.GetByteCount(query);

        buf.WriteByte(FrontendMessageCode.Query);
        buf.WriteInt32(4 +            // Message length (including self excluding code)
                       queryByteLen + // Query byte length
                       1);            // Null terminator

        buf.WriteString(query, queryByteLen, false).Wait();
        buf.WriteByte(0);

        var bytes = buf.GetContents();

        buf.Clear();
        return(bytes);
    }
Пример #18
0
        public override async Task Write(ArraySegment <char> value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
        {
            if (buf.WriteSpaceLeft < 1)
            {
                await buf.Flush(async, cancellationToken);
            }

            buf.WriteByte(LTxtQueryProtocolVersion);
            await base.Write(value, buf, lengthCache, parameter, async, cancellationToken);
        }
Пример #19
0
    /// <inheritdoc />
    public override async Task Write(string value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
    {
        if (buf.WriteSpaceLeft < 1)
        {
            await buf.Flush(async, cancellationToken);
        }

        buf.WriteByte(JsonPathVersion);

        await _textHandler.Write(value, buf, lengthCache, parameter, async, cancellationToken);
    }
Пример #20
0
        internal override async Task Write(NpgsqlWriteBuffer buf, bool async)
        {
            if (buf.WriteSpaceLeft < 1 + 4)
            {
                await buf.Flush(async);
            }
            var queryByteLen = _encoding.GetByteCount(_query);

            buf.WriteByte(Code);
            buf.WriteInt32(4 +            // Message length (including self excluding code)
                           queryByteLen + // Query byte length
                           1);            // Null terminator

            await buf.WriteString(_query, queryByteLen, async);

            if (buf.WriteSpaceLeft < 1)
            {
                await buf.Flush(async);
            }
            buf.WriteByte(0);
        }
Пример #21
0
        /// <inheritdoc />
        public override async Task Write(string value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async)
        {
            if (_isJsonb)
            {
                if (buf.WriteSpaceLeft < 1)
                {
                    await buf.Flush(async);
                }
                buf.WriteByte(JsonbProtocolVersion);
            }

            await _textHandler.Write(value, buf, lengthCache, parameter, async);
        }
Пример #22
0
        /// <inheritdoc />
        protected override async Task WriteWithLength <TAny>(TAny value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
        {
            buf.WriteInt32(ValidateAndGetLength(value, ref lengthCache, parameter));

            if (_isJsonb)
            {
                if (buf.WriteSpaceLeft < 1)
                {
                    await buf.Flush(async, cancellationToken);
                }
                buf.WriteByte(JsonbProtocolVersion);
            }

            if (typeof(TAny) == typeof(string))
            {
                await _textHandler.Write((string)(object)value !, buf, lengthCache, parameter, async, cancellationToken);
            }
            else if (typeof(TAny) == typeof(char[]))
            {
                await _textHandler.Write((char[])(object)value !, buf, lengthCache, parameter, async, cancellationToken);
            }
            else if (typeof(TAny) == typeof(ArraySegment <char>))
            {
                await _textHandler.Write((ArraySegment <char>)(object) value !, buf, lengthCache, parameter, async, cancellationToken);
            }
            else if (typeof(TAny) == typeof(char))
            {
                await _textHandler.Write((char)(object)value !, buf, lengthCache, parameter, async, cancellationToken);
            }
            else if (typeof(TAny) == typeof(byte[]))
            {
                await _textHandler.Write((byte[])(object)value !, buf, lengthCache, parameter, async, cancellationToken);
            }
            else if (typeof(TAny) == typeof(JsonDocument))
            {
                var data = parameter?.ConvertedValue != null
                    ? (byte[])parameter.ConvertedValue
                    : SerializeJsonDocument((JsonDocument)(object)value !);
                await buf.WriteBytesRaw(data, async, cancellationToken);
            }
            else
            {
                // User POCO, read serialized representation from the validation phase
                var s = parameter?.ConvertedValue != null
                    ? (string)parameter.ConvertedValue
                    : JsonSerializer.Serialize(value !, value !.GetType(), _serializerOptions);

                await _textHandler.Write(s, buf, lengthCache, parameter, async, cancellationToken);
            }
        }
Пример #23
0
        public override async Task Write(NpgsqlPath value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            if (buf.WriteSpaceLeft < 5)
            {
                await buf.Flush(async);
            }
            buf.WriteByte((byte)(value.Open ? 0 : 1));
            buf.WriteInt32(value.Count);

            foreach (var p in value)
            {
                if (buf.WriteSpaceLeft < 16)
                {
                    await buf.Flush(async);
                }
                buf.WriteDouble(p.X);
                buf.WriteDouble(p.Y);
            }
        }
Пример #24
0
        public async Task Write(Polygon value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            var type = EwkbGeometryType.Polygon;
            var size = SizeOfHeader;
            var srid = GetSrid(value.CRS);

            if (srid != 0)
            {
                size += sizeof(int);
                type |= EwkbGeometryType.HasSrid;
            }

            if (buf.WriteSpaceLeft < size)
            {
                await buf.Flush(async);
            }

            var lines = value.Coordinates;

            buf.WriteByte(0); // Most significant byte first
            buf.WriteInt32((int)type);
            buf.WriteInt32(lines.Count);

            if (srid != 0)
            {
                buf.WriteInt32(srid);
            }

            for (var i = 0; i < lines.Count; ++i)
            {
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                var coordinates = lines[i].Coordinates;
                buf.WriteInt32(coordinates.Count);
                for (var j = 0; j < coordinates.Count; ++j)
                {
                    await WritePosition(coordinates[j], buf, async);
                }
            }
        }
Пример #25
0
        internal override async Task Write(NpgsqlWriteBuffer buf, bool async)
        {
            if (buf.WriteSpaceLeft < 1 + 5)
            {
                await buf.Flush(async);
            }
            buf.WriteByte(Code);
            buf.WriteInt32(4 + PayloadLength);

            if (PayloadLength <= buf.WriteSpaceLeft)
            {
                // The entire array fits in our buffer, copy it into the buffer as usual.
                buf.WriteBytes(Payload, PayloadOffset, Payload.Length);
                return;
            }

            await buf.Flush(async);

            buf.DirectWrite(Payload, PayloadOffset, PayloadLength);
        }
Пример #26
0
 public override async Task Write(NpgsqlRange <TElement> value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
 {
     if (buf.WriteSpaceLeft < 1)
     {
         await buf.Flush(async);
     }
     buf.WriteByte((byte)value.Flags);
     if (value.IsEmpty)
     {
         return;
     }
     if (!value.LowerBoundInfinite)
     {
         await ElementHandler.WriteWithLengthInternal(value.LowerBound, buf, lengthCache, null, async);
     }
     if (!value.UpperBoundInfinite)
     {
         await ElementHandler.WriteWithLengthInternal(value.UpperBound, buf, lengthCache, null, async);
     }
 }
Пример #27
0
        private protected async Task Write <TAny>(NpgsqlRange <TAny> value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async)
        {
            if (buf.WriteSpaceLeft < 1)
            {
                await buf.Flush(async);
            }

            buf.WriteByte((byte)value.Flags);

            if (value.IsEmpty)
            {
                return;
            }

            if (!value.LowerBoundInfinite)
            {
                await _elementHandler.WriteWithLengthInternal(value.LowerBound, buf, lengthCache, null, async);
            }

            if (!value.UpperBoundInfinite)
            {
                await _elementHandler.WriteWithLengthInternal(value.UpperBound, buf, lengthCache, null, async);
            }
        }
Пример #28
0
        /// <inheritdoc />
        public override async Task Write(NpgsqlTsVector vector, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async)
        {
            if (buf.WriteSpaceLeft < 4)
            {
                await buf.Flush(async);
            }
            buf.WriteInt32(vector.Count);

            foreach (var lexeme in vector)
            {
                if (buf.WriteSpaceLeft < MaxSingleLexemeBytes)
                {
                    await buf.Flush(async);
                }

                buf.WriteString(lexeme.Text);
                buf.WriteByte(0);
                buf.WriteInt16(lexeme.Count);
                for (var i = 0; i < lexeme.Count; i++)
                {
                    buf.WriteInt16(lexeme[i].Value);
                }
            }
        }
Пример #29
0
        private protected async Task Write <TAny>(NpgsqlRange <TAny> value, NpgsqlWriteBuffer buf, NpgsqlLengthCache?lengthCache, NpgsqlParameter?parameter, bool async, CancellationToken cancellationToken = default)
        {
            if (buf.WriteSpaceLeft < 1)
            {
                await buf.Flush(async, cancellationToken);
            }

            buf.WriteByte((byte)value.Flags);

            if (value.IsEmpty)
            {
                return;
            }

            if (!value.LowerBoundInfinite)
            {
                await _subtypeHandler.WriteWithLength(value.LowerBound, buf, lengthCache, null, async, cancellationToken);
            }

            if (!value.UpperBoundInfinite)
            {
                await _subtypeHandler.WriteWithLength(value.UpperBound, buf, lengthCache, null, async, cancellationToken);
            }
        }
Пример #30
0
        public override async Task Write(PostgisGeometry value, NpgsqlWriteBuffer buf, NpgsqlLengthCache lengthCache, NpgsqlParameter parameter, bool async)
        {
            // Common header
            if (value.SRID == 0)
            {
                if (buf.WriteSpaceLeft < 5)
                {
                    await buf.Flush(async);
                }
                buf.WriteByte(0); // We choose to ouput only XDR structure
                buf.WriteInt32((int)value.Identifier);
            }
            else
            {
                if (buf.WriteSpaceLeft < 9)
                {
                    await buf.Flush(async);
                }
                buf.WriteByte(0);
                buf.WriteInt32((int)((uint)value.Identifier | (uint)EwkbModifiers.HasSRID));
                buf.WriteInt32((int)value.SRID);
            }

            switch (value.Identifier)
            {
            case WkbIdentifier.Point:
                if (buf.WriteSpaceLeft < 16)
                {
                    await buf.Flush(async);
                }
                var p = (PostgisPoint)value;
                buf.WriteDouble(p.X);
                buf.WriteDouble(p.Y);
                return;

            case WkbIdentifier.LineString:
                var l = (PostgisLineString)value;
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32(l.PointCount);
                for (var ipts = 0; ipts < l.PointCount; ipts++)
                {
                    if (buf.WriteSpaceLeft < 16)
                    {
                        await buf.Flush(async);
                    }
                    buf.WriteDouble(l[ipts].X);
                    buf.WriteDouble(l[ipts].Y);
                }
                return;

            case WkbIdentifier.Polygon:
                var pol = (PostgisPolygon)value;
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32(pol.RingCount);
                for (var irng = 0; irng < pol.RingCount; irng++)
                {
                    if (buf.WriteSpaceLeft < 4)
                    {
                        await buf.Flush(async);
                    }
                    buf.WriteInt32(pol[irng].Length);
                    for (var ipts = 0; ipts < pol[irng].Length; ipts++)
                    {
                        if (buf.WriteSpaceLeft < 16)
                        {
                            await buf.Flush(async);
                        }
                        buf.WriteDouble(pol[irng][ipts].X);
                        buf.WriteDouble(pol[irng][ipts].Y);
                    }
                }
                return;

            case WkbIdentifier.MultiPoint:
                var mp = (PostgisMultiPoint)value;
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32(mp.PointCount);
                for (var ipts = 0; ipts < mp.PointCount; ipts++)
                {
                    if (buf.WriteSpaceLeft < 21)
                    {
                        await buf.Flush(async);
                    }
                    buf.WriteByte(0);
                    buf.WriteInt32((int)WkbIdentifier.Point);
                    buf.WriteDouble(mp[ipts].X);
                    buf.WriteDouble(mp[ipts].Y);
                }
                return;

            case WkbIdentifier.MultiLineString:
                var ml = (PostgisMultiLineString)value;
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32(ml.LineCount);
                for (var irng = 0; irng < ml.LineCount; irng++)
                {
                    if (buf.WriteSpaceLeft < 9)
                    {
                        await buf.Flush(async);
                    }
                    buf.WriteByte(0);
                    buf.WriteInt32((int)WkbIdentifier.LineString);
                    buf.WriteInt32(ml[irng].PointCount);
                    for (var ipts = 0; ipts < ml[irng].PointCount; ipts++)
                    {
                        if (buf.WriteSpaceLeft < 16)
                        {
                            await buf.Flush(async);
                        }
                        buf.WriteDouble(ml[irng][ipts].X);
                        buf.WriteDouble(ml[irng][ipts].Y);
                    }
                }
                return;

            case WkbIdentifier.MultiPolygon:
                var mpl = (PostgisMultiPolygon)value;
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32(mpl.PolygonCount);
                for (var ipol = 0; ipol < mpl.PolygonCount; ipol++)
                {
                    if (buf.WriteSpaceLeft < 9)
                    {
                        await buf.Flush(async);
                    }
                    buf.WriteByte(0);
                    buf.WriteInt32((int)WkbIdentifier.Polygon);
                    buf.WriteInt32(mpl[ipol].RingCount);
                    for (var irng = 0; irng < mpl[ipol].RingCount; irng++)
                    {
                        if (buf.WriteSpaceLeft < 4)
                        {
                            await buf.Flush(async);
                        }
                        buf.WriteInt32(mpl[ipol][irng].Length);
                        for (var ipts = 0; ipts < mpl[ipol][irng].Length; ipts++)
                        {
                            if (buf.WriteSpaceLeft < 16)
                            {
                                await buf.Flush(async);
                            }
                            buf.WriteDouble(mpl[ipol][irng][ipts].X);
                            buf.WriteDouble(mpl[ipol][irng][ipts].Y);
                        }
                    }
                }
                return;

            case WkbIdentifier.GeometryCollection:
                var coll = (PostgisGeometryCollection)value;
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async);
                }
                buf.WriteInt32(coll.GeometryCount);

                foreach (var x in coll)
                {
                    await Write(x, buf, lengthCache, null, async);
                }
                return;

            default:
                throw new InvalidOperationException("Unknown Postgis identifier.");
            }
        }