T DoRead <T>(TypeHandler handler) { ReadColumnLenIfNeeded(); if (_columnLen == -1) { // TODO: What actual exception to throw here? Oracle throws InvalidCast, SqlClient throws its // own SqlNullValueException throw new InvalidCastException("Column is null"); } var result = handler.Read <T>(_buf, _columnLen); _leftToReadInDataMsg -= _columnLen; _columnLen = int.MinValue; // Mark that the (next) column length hasn't been read yet _column++; return(result); }
void ActivateEnumType(TypeHandler handler, BackendType backendType) { handler.PgName = backendType.Name; handler.OID = backendType.OID; handler.NpgsqlDbType = NpgsqlDbType.Enum; _oidIndex[backendType.OID] = handler; _byType[handler.GetFieldType()] = handler; if (backendType.ArrayOID != 0) { var arrayHandler = RegisterArrayType(backendType.ArrayOID, handler, backendType.ArrayTextDelimiter); if (_byEnumTypeAsArray == null) { _byEnumTypeAsArray = new Dictionary <Type, TypeHandler>(); } var enumType = handler.GetType().GetGenericArguments()[0]; Contract.Assert(enumType.IsEnum); _byEnumTypeAsArray[enumType] = arrayHandler; } }
void DoWrite <T>(TypeHandler handler, [CanBeNull] T value) { try { // We simulate the regular writing process with a validation/length calculation pass, // followed by a write pass _dummyParam.ConvertedValue = null; _lengthCache.Clear(); handler.ValidateAndGetLength(value, ref _lengthCache, _dummyParam); _lengthCache.Rewind(); handler.WriteWithLength(value, _buf, _lengthCache, _dummyParam, false, CancellationToken.None); _column++; } catch { _connector.Break(); Cleanup(); throw; } }
T DoRead <T>(TypeHandler handler) { try { ReadColumnLenIfNeeded(); if (_columnLen == -1) { throw new InvalidCastException("Column is null"); } var result = handler.ReadFully <T>(_buf, _columnLen); _leftToReadInDataMsg -= _columnLen; _columnLen = int.MinValue; // Mark that the (next) column length hasn't been read yet _column++; return(result); } catch { _connector.Break(); Cleanup(); throw; } }
void DoWrite <T>(TypeHandler handler, T value) { if (_buf.WriteSpaceLeft < 4) { Flush(); } EnsureDataMessage(); var asObject = (object)value; // TODO: Implement boxless writing in the future if (asObject == null) { _buf.WriteInt32(-1); _column++; return; } var asSimple = handler as ISimpleTypeWriter; if (asSimple != null) { var len = asSimple.ValidateAndGetLength(asObject); _buf.WriteInt32(len); if (_buf.WriteSpaceLeft < len) { Contract.Assume(_buf.Size >= len); FlushAndStartDataMessage(); } asSimple.Write(asObject, _buf); _column++; return; } var asChunking = handler as IChunkingTypeWriter; if (asChunking != null) { _lengthCache.Clear(); var len = asChunking.ValidateAndGetLength(asObject, ref _lengthCache); _buf.WriteInt32(len); _lengthCache.Rewind(); _lengthCache.Get(); // Hack asChunking.PrepareWrite(asObject, _buf, _lengthCache); var directBuf = new DirectBuffer(); while (!asChunking.Write(ref directBuf)) { FlushAndStartDataMessage(); // The following is an optimization hack for writing large byte arrays without passing // through our buffer if (directBuf.Buffer != null) { len = directBuf.Size == 0 ? directBuf.Buffer.Length : directBuf.Size; _buf.WriteInt32(len); Flush(); _buf.Underlying.Write(directBuf.Buffer, directBuf.Offset, len); directBuf.Buffer = null; directBuf.Size = 0; } } _column++; return; } throw PGUtil.ThrowIfReached(); }
void DoWrite <T>(TypeHandler handler, T value) { try { if (_buf.WriteSpaceLeft < 4) { FlushAndStartDataMessage(); } var asObject = (object)value; // TODO: Implement boxless writing in the future if (asObject == null) { _buf.WriteInt32(-1); _column++; return; } _dummyParam.ConvertedValue = null; var asSimple = handler as ISimpleTypeWriter; if (asSimple != null) { var len = asSimple.ValidateAndGetLength(asObject, _dummyParam); _buf.WriteInt32(len); if (_buf.WriteSpaceLeft < len) { Contract.Assume(_buf.Size >= len); FlushAndStartDataMessage(); } asSimple.Write(asObject, _buf, _dummyParam); _column++; return; } var asChunking = handler as IChunkingTypeWriter; if (asChunking != null) { _lengthCache.Clear(); var len = asChunking.ValidateAndGetLength(asObject, ref _lengthCache, _dummyParam); _buf.WriteInt32(len); // If the type handler used the length cache, rewind it to skip the first position: // it contains the entire value length which we already have in len. if (_lengthCache.Position > 0) { _lengthCache.Rewind(); _lengthCache.Position++; } asChunking.PrepareWrite(asObject, _buf, _lengthCache, _dummyParam); var directBuf = new DirectBuffer(); while (!asChunking.Write(ref directBuf)) { Flush(); // The following is an optimization hack for writing large byte arrays without passing // through our buffer if (directBuf.Buffer != null) { len = directBuf.Size == 0 ? directBuf.Buffer.Length : directBuf.Size; _buf.WritePosition = 1; _buf.WriteInt32(len + 4); _buf.Flush(); _writingDataMsg = false; _buf.Underlying.Write(directBuf.Buffer, directBuf.Offset, len); directBuf.Buffer = null; directBuf.Size = 0; } EnsureDataMessage(); } _column++; return; } throw PGUtil.ThrowIfReached(); } catch { _connector.Break(); Cleanup(); throw; } }
T DoRead <T>(TypeHandler handler) { try { ReadColumnLenIfNeeded(); if (_columnLen == -1) { throw new InvalidCastException("Column is null"); } // TODO: Duplication with NpgsqlDataReader.GetFieldValueInternal T result; // The type handler supports the requested type directly var tHandler = handler as ITypeHandler <T>; if (tHandler != null) { result = handler.Read <T>(_buf, _columnLen, false).Result; } else { var t = typeof(T); if (!t.IsArray) { throw new InvalidCastException($"Can't cast database type {handler.PgDisplayName} to {typeof(T).Name}"); } // Getting an array // We need to treat this as an actual array type, these need special treatment because of // typing/generics reasons (there is no way to express "array of X" with generics var elementType = t.GetElementType(); var arrayHandler = handler as ArrayHandler; if (arrayHandler == null) { throw new InvalidCastException($"Can't cast database type {handler.PgDisplayName} to {typeof(T).Name}"); } if (arrayHandler.GetElementFieldType() == elementType) { result = (T)handler.ReadAsObject(_buf, _columnLen, false).Result; } else if (arrayHandler.GetElementPsvType() == elementType) { result = (T)handler.ReadPsvAsObject(_buf, _columnLen, false).Result; } else { throw new InvalidCastException($"Can't cast database type {handler.PgDisplayName} to {typeof(T).Name}"); } } _leftToReadInDataMsg -= _columnLen; _columnLen = int.MinValue; // Mark that the (next) column length hasn't been read yet _column++; return(result); } catch { _connector.Break(); Cleanup(); throw; } }