/// <summary> /// Convert a System.Array to PG binary format. /// Write the array header and prepare to write array data to the stream. /// </summary> public byte[] ArrayToArrayBinary(NpgsqlNativeTypeInfo TypeInfo, object oNativeData, NativeToBackendTypeConverterOptions options) { Array NativeData = (Array)oNativeData; MemoryStream dst = new MemoryStream(); // Write the number of dimensions in the array. PGUtil.WriteInt32(dst, NativeData.Rank); // Placeholder for null bitmap flag, which isn't used? PGUtil.WriteInt32(dst, 0); // Write the OID of the elements of the array. PGUtil.WriteInt32(dst, options.OidToNameMapping[_elementConverter.Name].OID); // White dimension descriptors. for (int i = 0; i < NativeData.Rank; i++) { // Number of elements in the dimension. PGUtil.WriteInt32(dst, NativeData.GetLength(i)); // Lower bounds of the dimension, 1-based for SQL. PGUtil.WriteInt32(dst, NativeData.GetLowerBound(i) + 1); } int[] dimensionOffsets = new int[NativeData.Rank]; // Write all array data. WriteBinaryArrayData(TypeInfo, NativeData, options, dst, 0, dimensionOffsets); return(dst.ToArray()); }
/* * This sends this argument down the network stream. * * <p>The stream sent consists of the length.int4 then the contents. * * <p><b>Note:</b> This is called from Fastpath, and cannot be called from * client code. * * @param s output stream * @exception IOException if something failed on the network stream */ public void Send(Stream s) { if (type) { // argument is an integer PGUtil.WriteInt32(s, 4); PGUtil.WriteInt32(s, value); // integer value of argument } else { // argument is a byte array PGUtil.WriteInt32(s, bytes.Length); s.Write(bytes, 0, bytes.Length); } }
/// <summary> /// Append all array data to the binary stream. /// </summary> private void WriteBinaryArrayData(NpgsqlNativeTypeInfo TypeInfo, Array nativeData, NativeToBackendTypeConverterOptions options, MemoryStream dst, int dimensionOffset, int[] dimensionOffsets) { int dimensionLength = nativeData.GetLength(dimensionOffset); int dimensionLBound = nativeData.GetLowerBound(dimensionOffset); if (dimensionOffset < nativeData.Rank - 1) { // Drill down recursively until we hit a single dimension array. for (int i = dimensionLBound; i < dimensionLBound + dimensionLength; i++) { dimensionOffsets[dimensionOffset] = i; WriteBinaryArrayData(TypeInfo, nativeData, options, dst, dimensionOffset + 1, dimensionOffsets); } } else { // Write the individual array elements to the output stream. for (int i = dimensionLBound; i < dimensionLBound + dimensionLength; i++) { object elementNative; dimensionOffsets[dimensionOffset] = i; elementNative = nativeData.GetValue(dimensionOffsets); if (elementNative == null || elementNative == DBNull.Value) { // Write length identifier -1 indicating NULL value. PGUtil.WriteInt32(dst, -1); } else { byte[] elementBinary; elementBinary = (byte[])_elementConverter.ConvertToBackend(elementNative, true, options); // Write lenght identifier. PGUtil.WriteInt32(dst, elementBinary.Length); // Write element data. dst.Write(elementBinary, 0, elementBinary.Length); } } } }
private Object FastpathV2(Int32 fnid, Boolean resulttype, FastpathArg[] args) { // added Oct 7 1998 to give us thread safety lock (stream) { // send the function call // 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding // that confuses the backend. The 0 terminates the command line. stream.WriteByte((Byte)70); stream.WriteByte((Byte)0); PGUtil.WriteInt32(stream, fnid); PGUtil.WriteInt32(stream, args.Length); for (Int32 i = 0; i < args.Length; i++) { args[i].Send(stream); } // This is needed, otherwise data can be lost stream.Flush(); // Now handle the result // Now loop, reading the results Object result = null; // our result String errorMessage = ""; Byte[] input_buffer = new Byte[512]; Int32 c; Boolean l_endQuery = false; while (!l_endQuery) { c = (Char)stream.ReadByte(); switch (c) { case 'A': // Asynchronous Notify //TODO: do something with this Int32 pid = PGUtil.ReadInt32(stream, input_buffer); String msg = PGUtil.ReadString(stream, conn.Connector.Encoding); conn.Connector.CheckErrorsAndNotifications(); break; //------------------------------ // Error message returned case 'E': NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion); e.ReadFromStream(stream, conn.Connector.Encoding); errorMessage += e.Message; break; //------------------------------ // Notice from backend case 'N': NpgsqlError notice = new NpgsqlError(conn.BackendProtocolVersion); notice.ReadFromStream(stream, conn.Connector.Encoding); errorMessage += notice.Message; break; case 'V': Char l_nextChar = (Char)stream.ReadByte(); if (l_nextChar == 'G') { Int32 sz = PGUtil.ReadInt32(stream, input_buffer); // Return an Integer if if (resulttype) { result = PGUtil.ReadInt32(stream, input_buffer); } else { Byte[] buf = new Byte[sz]; Int32 bytes_from_stream = 0; Int32 total_bytes_read = 0; Int32 size = sz; do { bytes_from_stream = stream.Read(buf, total_bytes_read, size); total_bytes_read += bytes_from_stream; size -= bytes_from_stream; }while(size > 0); result = buf; } //There should be a trailing '0' Int32 l_endChar = (Char)stream.ReadByte(); } else { //it must have been a '0', thus no results } break; case 'Z': l_endQuery = true; break; default: throw new NpgsqlException("postgresql.fp.protocol " + c.ToString()); } } if (errorMessage != null) { throw new NpgsqlException("postgresql.fp.error" + errorMessage); } return(result); } }
private Object FastpathV3(Int32 fnid, Boolean resulttype, FastpathArg[] args) { // give thread safety lock (stream) { // send the function call { Int32 l_msgLen = 0; l_msgLen += 16; for (Int32 i = 0; i < args.Length; i++) { l_msgLen += args[i].SendSize(); } stream.WriteByte((Byte)'F'); PGUtil.WriteInt32(stream, l_msgLen); PGUtil.WriteInt32(stream, fnid); PGUtil.WriteInt16(stream, 1); PGUtil.WriteInt16(stream, 1); PGUtil.WriteInt16(stream, (short)args.Length); for (Int32 i = 0; i < args.Length; i++) { args[i].Send(stream); } PGUtil.WriteInt16(stream, 1); // This is needed, otherwise data can be lost stream.Flush(); } // Now handle the result // Now loop, reading the results Object result = null; // our result Exception error = null; Int32 c; Boolean l_endQuery = false; Byte[] input_buffer = new Byte[512]; while (!l_endQuery) { c = (Char)stream.ReadByte(); switch (c) { case 'A': // Asynchronous Notify Int32 msglen = PGUtil.ReadInt32(stream, input_buffer); Int32 pid = PGUtil.ReadInt32(stream, input_buffer); String msg = PGUtil.ReadString(stream, conn.Connector.Encoding); PGUtil.ReadString(stream, conn.Connector.Encoding); String param = PGUtil.ReadString(stream, conn.Connector.Encoding); conn.Connector.CheckErrorsAndNotifications(); break; //------------------------------ // Error message returned case 'E': NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion); e.ReadFromStream(stream, conn.Connector.Encoding); throw new NpgsqlException(e.ToString()); //------------------------------ // Notice from backend case 'N': Int32 l_nlen = PGUtil.ReadInt32(stream, input_buffer); NpgsqlError e1 = new NpgsqlError(conn.BackendProtocolVersion); e1.ReadFromStream(stream, conn.Connector.Encoding); conn.Connector.Mediator.Errors.Add(e1); break; case 'V': Int32 l_msgLen = PGUtil.ReadInt32(stream, input_buffer); Int32 l_valueLen = PGUtil.ReadInt32(stream, input_buffer); if (l_valueLen == -1) { //null value } else if (l_valueLen == 0) { result = new Byte[0]; } else { // Return an Integer if if (resulttype) { result = PGUtil.ReadInt32(stream, input_buffer); } else { Byte[] buf = new Byte[l_valueLen]; Int32 bytes_from_stream = 0; Int32 total_bytes_read = 0; Int32 size = l_valueLen; do { bytes_from_stream = stream.Read(buf, total_bytes_read, size); total_bytes_read += bytes_from_stream; size -= bytes_from_stream; }while(size > 0); result = buf; } } break; case 'Z': //TODO: use size better if (PGUtil.ReadInt32(stream, input_buffer) != 5) { throw new NpgsqlException("Received Z"); } //TODO: handle transaction status Char l_tStatus = (Char)stream.ReadByte(); l_endQuery = true; break; default: throw new NpgsqlException("postgresql.fp.protocol received " + c.ToString()); } } if (error != null) { throw error; } return(result); } }