예제 #1
0
        internal async Task Startup()
        {
            // Read and skip the startup message
            await _readBuffer.EnsureAsync(4);

            var startupMessageLen = _readBuffer.ReadInt32();
            await _readBuffer.EnsureAsync(startupMessageLen - 4);

            _readBuffer.Skip(startupMessageLen - 4);

            WriteAuthenticateOk();
            WriteParameterStatuses(new Dictionary <string, string>
            {
                { "server_version", "13" },
                { "server_encoding", "UTF8" },
                { "client_encoding", "UTF8" },
                { "application_name", "Mock" },
                { "is_superuser", "on" },
                { "session_authorization", "foo" },
                { "DateStyle", "ISO, MDY" },
                { "IntervalStyle", "postgres" },
                { "TimeZone", "UTC" },
                { "integer_datetimes", "on" },
                { "standard_conforming_strings", "on" }
            });
            WriteBackendKeyData(ProcessId, BackendSecret);
            WriteReadyForQuery();

            await FlushAsync();
        }
예제 #2
0
        internal async Task SkipMessage()
        {
            await _readBuffer.EnsureAsync(4);

            var len = _readBuffer.ReadInt32();
            await _readBuffer.EnsureAsync(len - 4);

            _readBuffer.Skip(len - 4);
        }
예제 #3
0
        /// <summary>
        /// Reads a value of type <typeparamref name="TDefault"/> with the given length from the provided buffer,
        /// using either sync or async I/O. Type handlers typically don't need to override this -
        /// override <see cref="Read(NpgsqlReadBuffer, int, bool, FieldDescription)"/> - but may do
        /// so in exceptional cases where reading of arbitrary types is required.
        /// </summary>
        /// <param name="buf">The buffer from which to read.</param>
        /// <param name="len">The byte length of the value. The buffer might not contain the full length, requiring I/O to be performed.</param>
        /// <param name="async">If I/O is required to read the full length of the value, whether it should be performed synchronously or asynchronously.</param>
        /// <param name="fieldDescription">Additional PostgreSQL information about the type, such as the length in varchar(30).</param>
        /// <returns>The fully-read value.</returns>
        protected internal override Task <TAny> Read <TAny>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription = null)
        {
            var asTypedHandler = this as INpgsqlTypeHandler <TAny>;

            if (asTypedHandler == null)
            {
                buf.Skip(len);  // Perform this in sync for performance
                throw new NpgsqlSafeReadException(new InvalidCastException(fieldDescription == null
                    ? $"Can't cast database type to {typeof(TAny).Name}"
                    : $"Can't cast database type {fieldDescription.Handler.PgDisplayName} to {typeof(TAny).Name}"
                                                                           ));
            }

            return(asTypedHandler.Read(buf, len, async, fieldDescription));
        }
예제 #4
0
        async ValueTask <bool> INpgsqlTypeHandler <bool> .Read(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription)
        {
            await buf.Ensure(5, async);

            var bitLen = buf.ReadInt32();

            if (bitLen != 1)
            {
                // This isn't a single bit - error.
                // Consume the rest of the value first so the connection is left in a good state.
                buf.Skip(len - 4);
                throw new NpgsqlSafeReadException(new InvalidCastException("Can't convert a BIT(N) type to bool, only BIT(1)"));
            }
            var b = buf.ReadByte();

            return((b & 128) != 0);
        }
        /// <summary>
        /// Reads a value of type <typeparamref name="TDefault"/> with the given length from the provided buffer.
        /// with the assumption that it is entirely present in the provided memory buffer and no I/O will be
        /// required. Type handlers typically don't need to override this - override
        /// <see cref="Read(Npgsql.NpgsqlReadBuffer,int,Npgsql.BackendMessages.FieldDescription)"/> - but may do
        /// so in exceptional cases where reading of arbitrary types is required.
        /// </summary>
        /// <param name="buf">The buffer from which to read.</param>
        /// <param name="len">The byte length of the value. The buffer might not contain the full length, requiring I/O to be performed.</param>
        /// <param name="fieldDescription">Additional PostgreSQL information about the type, such as the length in varchar(30).</param>
        /// <returns>The fully-read value.</returns>
        internal override TAny Read <TAny>(NpgsqlReadBuffer buf, int len, FieldDescription fieldDescription = null)
        {
            Debug.Assert(len <= buf.ReadBytesLeft);

            var asTypedHandler = this as INpgsqlSimpleTypeHandler <TAny>;

            if (asTypedHandler == null)
            {
                buf.Skip(len);  // Perform this in sync for performance
                throw new NpgsqlSafeReadException(new InvalidCastException(fieldDescription == null
                    ? $"Can't cast database type to {typeof(TAny).Name}"
                    : $"Can't cast database type {fieldDescription.Handler.PgDisplayName} to {typeof(TAny).Name}"
                                                                           ));
            }

            return(asTypedHandler.Read(buf, len, fieldDescription));
        }
예제 #6
0
        async ValueTask <BitVector32> INpgsqlTypeHandler <BitVector32> .Read(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription)
        {
            if (len > 4 + 4)
            {
                buf.Skip(len);
                throw new NpgsqlSafeReadException(
                          new InvalidCastException("Can't read PostgreSQL bitstring with more than 32 bits into BitVector32")
                          );
            }

            await buf.Ensure(4 + 4, async);

            var numBits = buf.ReadInt32();

            return(numBits == 0
                ? new BitVector32(0)
                : new BitVector32(buf.ReadInt32()));
        }
예제 #7
0
        public override Task <string> Read(NpgsqlReadBuffer buf, int byteLen, bool async, FieldDescription fieldDescription = null)
        {
            if (fieldDescription == null)
            {
                throw new Exception($"Received an unknown field but {nameof(fieldDescription)} is null (i.e. COPY mode)");
            }

            if (fieldDescription.IsBinaryFormat)
            {
                // We can't do anything with a binary representation of an unknown type - the user should have
                // requested text. Skip the data and throw.
                buf.Skip(byteLen);
                // At least get the name of the PostgreSQL type for the exception
                throw new NpgsqlSafeReadException(new NotSupportedException(
                                                      _connector.TypeMapper.DatabaseInfo.ByOID.TryGetValue(fieldDescription.TypeOID, out var pgType)
                        ? $"The field '{fieldDescription.Name}' has type '{pgType.DisplayName}', which is currently unknown to Npgsql. You can retrieve it as a string by marking it as unknown, please see the FAQ."
                        : $"The field '{fieldDescription.Name}' has a type currently unknown to Npgsql (OID {fieldDescription.TypeOID}). You can retrieve it as a string by marking it as unknown, please see the FAQ."
                                                      ));
            }
            return(base.Read(buf, byteLen, async, fieldDescription));
        }
예제 #8
0
 ValueTask <ArraySegment <byte> > INpgsqlTypeHandler <ArraySegment <byte> > .Read(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription)
 {
     buf.Skip(len);
     throw new NpgsqlSafeReadException(new NotSupportedException("Only writing ArraySegment<byte> to PostgreSQL bytea is supported, no reading."));
 }
예제 #9
0
 ValueTask <string> INpgsqlTypeHandler <string> .Read(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription)
 {
     buf.Skip(len);
     throw new NpgsqlSafeReadException(new NotSupportedException("Only writing string to PostgreSQL bitstring is supported, no reading."));
 }
예제 #10
0
        async Task <PostgisGeometry> DoRead(NpgsqlReadBuffer buf, WkbIdentifier id, ByteOrder bo, bool async)
        {
            switch (id)
            {
            case WkbIdentifier.Point:
                await buf.Ensure(16, async);

                return(new PostgisPoint(buf.ReadDouble(bo), buf.ReadDouble(bo)));

            case WkbIdentifier.LineString:
            {
                await buf.Ensure(4, async);

                var points = new Coordinate2D[buf.ReadInt32(bo)];
                for (var ipts = 0; ipts < points.Length; ipts++)
                {
                    await buf.Ensure(16, async);

                    points[ipts] = new Coordinate2D(buf.ReadDouble(bo), buf.ReadDouble(bo));
                }
                return(new PostgisLineString(points));
            }

            case WkbIdentifier.Polygon:
            {
                await buf.Ensure(4, async);

                var rings = new Coordinate2D[buf.ReadInt32(bo)][];

                for (var irng = 0; irng < rings.Length; irng++)
                {
                    await buf.Ensure(4, async);

                    rings[irng] = new Coordinate2D[buf.ReadInt32(bo)];
                    for (var ipts = 0; ipts < rings[irng].Length; ipts++)
                    {
                        await buf.Ensure(16, async);

                        rings[irng][ipts] = new Coordinate2D(buf.ReadDouble(bo), buf.ReadDouble(bo));
                    }
                }
                return(new PostgisPolygon(rings));
            }

            case WkbIdentifier.MultiPoint:
            {
                await buf.Ensure(4, async);

                var points = new Coordinate2D[buf.ReadInt32(bo)];
                for (var ipts = 0; ipts < points.Length; ipts++)
                {
                    await buf.Ensure(21, async);

                    await buf.Skip(5, async);

                    points[ipts] = new Coordinate2D(buf.ReadDouble(bo), buf.ReadDouble(bo));
                }
                return(new PostgisMultiPoint(points));
            }

            case WkbIdentifier.MultiLineString:
            {
                await buf.Ensure(4, async);

                var rings = new Coordinate2D[buf.ReadInt32(bo)][];

                for (var irng = 0; irng < rings.Length; irng++)
                {
                    await buf.Ensure(9, async);

                    await buf.Skip(5, async);

                    rings[irng] = new Coordinate2D[buf.ReadInt32(bo)];
                    for (var ipts = 0; ipts < rings[irng].Length; ipts++)
                    {
                        await buf.Ensure(16, async);

                        rings[irng][ipts] = new Coordinate2D(buf.ReadDouble(bo), buf.ReadDouble(bo));
                    }
                }
                return(new PostgisMultiLineString(rings));
            }

            case WkbIdentifier.MultiPolygon:
            {
                await buf.Ensure(4, async);

                var pols = new Coordinate2D[buf.ReadInt32(bo)][][];

                for (var ipol = 0; ipol < pols.Length; ipol++)
                {
                    await buf.Ensure(9, async);

                    await buf.Skip(5, async);

                    pols[ipol] = new Coordinate2D[buf.ReadInt32(bo)][];
                    for (var irng = 0; irng < pols[ipol].Length; irng++)
                    {
                        await buf.Ensure(4, async);

                        pols[ipol][irng] = new Coordinate2D[buf.ReadInt32(bo)];
                        for (var ipts = 0; ipts < pols[ipol][irng].Length; ipts++)
                        {
                            await buf.Ensure(16, async);

                            pols[ipol][irng][ipts] = new Coordinate2D(buf.ReadDouble(bo), buf.ReadDouble(bo));
                        }
                    }
                }
                return(new PostgisMultiPolygon(pols));
            }

            case WkbIdentifier.GeometryCollection:
            {
                await buf.Ensure(4, async);

                var g = new PostgisGeometry[buf.ReadInt32(bo)];

                for (var i = 0; i < g.Length; i++)
                {
                    await buf.Ensure(5, async);

                    var elemBo = (ByteOrder)buf.ReadByte();
                    var elemId = (WkbIdentifier)(buf.ReadUInt32(bo) & 7);

                    g[i] = await DoRead(buf, elemId, elemBo, async);
                }
                return(new PostgisGeometryCollection(g));
            }

            default:
                throw new InvalidOperationException("Unknown Postgis identifier.");
            }
        }
예제 #11
0
        async ValueTask <GeoJSONObject> ReadGeometryCore(NpgsqlReadBuffer buf, bool async, BoundingBoxBuilder?boundingBox)
        {
            await buf.Ensure(SizeOfHeader, async);

            var littleEndian = buf.ReadByte() > 0;
            var type         = (EwkbGeometryType)buf.ReadUInt32(littleEndian);

            GeoJSONObject geometry;
            NamedCRS?     crs = null;

            if (HasSrid(type))
            {
                await buf.Ensure(4, async);

                crs = GetCrs(buf.ReadInt32(littleEndian));
            }

            switch (type & EwkbGeometryType.BaseType)
            {
            case EwkbGeometryType.Point:
            {
                await buf.Ensure(SizeOfPoint(type), async);

                var position = ReadPosition(buf, type, littleEndian);
                boundingBox?.Accumulate(position);
                geometry = new Point(position);
                break;
            }

            case EwkbGeometryType.LineString:
            {
                await buf.Ensure(SizeOfLength, async);

                var coordinates = new Position[buf.ReadInt32(littleEndian)];
                for (var i = 0; i < coordinates.Length; ++i)
                {
                    await buf.Ensure(SizeOfPoint(type), async);

                    var position = ReadPosition(buf, type, littleEndian);
                    boundingBox?.Accumulate(position);
                    coordinates[i] = position;
                }
                geometry = new LineString(coordinates);
                break;
            }

            case EwkbGeometryType.Polygon:
            {
                await buf.Ensure(SizeOfLength, async);

                var lines = new LineString[buf.ReadInt32(littleEndian)];
                for (var i = 0; i < lines.Length; ++i)
                {
                    var coordinates = new Position[buf.ReadInt32(littleEndian)];
                    for (var j = 0; j < coordinates.Length; ++j)
                    {
                        await buf.Ensure(SizeOfPoint(type), async);

                        var position = ReadPosition(buf, type, littleEndian);
                        boundingBox?.Accumulate(position);
                        coordinates[j] = position;
                    }
                    lines[i] = new LineString(coordinates);
                }
                geometry = new Polygon(lines);
                break;
            }

            case EwkbGeometryType.MultiPoint:
            {
                await buf.Ensure(SizeOfLength, async);

                var points = new Point[buf.ReadInt32(littleEndian)];
                for (var i = 0; i < points.Length; ++i)
                {
                    await buf.Ensure(SizeOfHeader + SizeOfPoint(type), async);

                    await buf.Skip(SizeOfHeader, async);

                    var position = ReadPosition(buf, type, littleEndian);
                    boundingBox?.Accumulate(position);
                    points[i] = new Point(position);
                }
                geometry = new MultiPoint(points);
                break;
            }

            case EwkbGeometryType.MultiLineString:
            {
                await buf.Ensure(SizeOfLength, async);

                var lines = new LineString[buf.ReadInt32(littleEndian)];
                for (var i = 0; i < lines.Length; ++i)
                {
                    await buf.Ensure(SizeOfHeaderWithLength, async);

                    await buf.Skip(SizeOfHeader, async);

                    var coordinates = new Position[buf.ReadInt32(littleEndian)];
                    for (var j = 0; j < coordinates.Length; ++j)
                    {
                        await buf.Ensure(SizeOfPoint(type), async);

                        var position = ReadPosition(buf, type, littleEndian);
                        boundingBox?.Accumulate(position);
                        coordinates[j] = position;
                    }
                    lines[i] = new LineString(coordinates);
                }
                geometry = new MultiLineString(lines);
                break;
            }

            case EwkbGeometryType.MultiPolygon:
            {
                await buf.Ensure(SizeOfLength, async);

                var polygons = new Polygon[buf.ReadInt32(littleEndian)];
                for (var i = 0; i < polygons.Length; ++i)
                {
                    await buf.Ensure(SizeOfHeaderWithLength, async);

                    await buf.Skip(SizeOfHeader, async);

                    var lines = new LineString[buf.ReadInt32(littleEndian)];
                    for (var j = 0; j < lines.Length; ++j)
                    {
                        var coordinates = new Position[buf.ReadInt32(littleEndian)];
                        for (var k = 0; k < coordinates.Length; ++k)
                        {
                            await buf.Ensure(SizeOfPoint(type), async);

                            var position = ReadPosition(buf, type, littleEndian);
                            boundingBox?.Accumulate(position);
                            coordinates[k] = position;
                        }
                        lines[j] = new LineString(coordinates);
                    }
                    polygons[i] = new Polygon(lines);
                }
                geometry = new MultiPolygon(polygons);
                break;
            }

            case EwkbGeometryType.GeometryCollection:
            {
                await buf.Ensure(SizeOfLength, async);

                var elements = new IGeometryObject[buf.ReadInt32(littleEndian)];
                for (var i = 0; i < elements.Length; ++i)
                {
                    elements[i] = (IGeometryObject) await ReadGeometryCore(buf, async, boundingBox);
                }
                geometry = new GeometryCollection(elements);
                break;
            }

            default:
                throw UnknownPostGisType();
            }

            geometry.CRS = crs;
            return(geometry);
        }
 protected virtual DateTimeOffset ReadDateTimeOffset(NpgsqlReadBuffer buf, int len, FieldDescription fieldDescription = null)
 {
     buf.Skip(len);
     throw new NpgsqlSafeReadException(new InvalidCastException("Only writing of DateTimeOffset to PostgreSQL timestamp is supported, not reading."));
 }
예제 #13
0
        internal CommandCompleteMessage Load(NpgsqlReadBuffer buf, int len)
        {
            Rows = 0;
            OID  = 0;

            var bytes = buf.Buffer;
            var i     = buf.ReadPosition;

            buf.Skip(len);
            switch (bytes[i])
            {
            case (byte)'I':
                if (!AreEqual(bytes, i, "INSERT "))
                {
                    goto default;
                }
                StatementType = StatementType.Insert;
                i            += 7;
                OID           = (uint)ParseNumber(bytes, ref i);
                i++;
                Rows = ParseNumber(bytes, ref i);
                return(this);

            case (byte)'D':
                if (!AreEqual(bytes, i, "DELETE "))
                {
                    goto default;
                }
                StatementType = StatementType.Delete;
                i            += 7;
                Rows          = ParseNumber(bytes, ref i);
                return(this);

            case (byte)'U':
                if (!AreEqual(bytes, i, "UPDATE "))
                {
                    goto default;
                }
                StatementType = StatementType.Update;
                i            += 7;
                Rows          = ParseNumber(bytes, ref i);
                return(this);

            case (byte)'S':
                if (!AreEqual(bytes, i, "SELECT "))
                {
                    goto default;
                }
                StatementType = StatementType.Select;
                i            += 7;
                Rows          = ParseNumber(bytes, ref i);
                return(this);

            case (byte)'M':
                if (!AreEqual(bytes, i, "MOVE "))
                {
                    goto default;
                }
                StatementType = StatementType.Move;
                i            += 5;
                Rows          = ParseNumber(bytes, ref i);
                return(this);

            case (byte)'F':
                if (!AreEqual(bytes, i, "FETCH "))
                {
                    goto default;
                }
                StatementType = StatementType.Fetch;
                i            += 6;
                Rows          = ParseNumber(bytes, ref i);
                return(this);

            case (byte)'C':
                if (!AreEqual(bytes, i, "COPY "))
                {
                    goto default;
                }
                StatementType = StatementType.Copy;
                i            += 5;
                Rows          = ParseNumber(bytes, ref i);
                return(this);

            default:
                StatementType = StatementType.Other;
                return(this);
            }
        }