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(); }
internal async Task SkipMessage() { await _readBuffer.EnsureAsync(4); var len = _readBuffer.ReadInt32(); await _readBuffer.EnsureAsync(len - 4); _readBuffer.Skip(len - 4); }
/// <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)); }
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)); }
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())); }
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)); }
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.")); }
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.")); }
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."); } }
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.")); }
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); } }