示例#1
0
        /// <summary>
        /// Recursively populates an array from PB binary data representation.
        /// </summary>
        private void PopulateArrayFromBinaryArray(NpgsqlBackendTypeInfo TypeInfo, byte[] backendData, Int32 fieldValueSize, Int32 TypeModifier, ref int dataOffset, int[] dimLengths, int[] dimLBounds, int dimOffset, Array dst, int[] dstOffsets)
        {
            int dimensionLBound = dimLBounds[dimOffset];
            int end             = dimensionLBound + dimLengths[dimOffset];

            if (dimOffset < dimLengths.Length - 1)
            {
                // Drill down recursively until we hit a single dimension array.
                for (int i = dimensionLBound; i < end; i++)
                {
                    dstOffsets[dimOffset] = i;

                    PopulateArrayFromBinaryArray(TypeInfo, backendData, fieldValueSize, TypeModifier, ref dataOffset, dimLengths, dimLBounds, dimOffset + 1, dst, dstOffsets);
                }
            }
            else
            {
                // Populate a single dimension array.
                for (int i = dimensionLBound; i < end; i++)
                {
                    // Sanity check.
                    if (backendData.Length < dataOffset + 4)
                    {
                        throw new NpgsqlException("Out of backend data while reading binary array");
                    }

                    int elementLength;

                    // Each element consists of an int length identifier, followed by that many bytes of raw data.
                    // Length -1 indicates a NULL value, and is naturally followed by no data.
                    elementLength = PGUtil.ReadInt32(backendData, dataOffset);
                    dataOffset   += 4;

                    if (elementLength == -1)
                    {
                        // This currently throws an exception on value types.
                        dst.SetValue(DBNull.Value, dstOffsets);
                    }
                    else
                    {
                        // Sanity check.
                        if (backendData.Length < dataOffset + elementLength)
                        {
                            throw new NpgsqlException("Out of backend data while reading binary array");
                        }

                        byte[] elementBinary;

                        // Get element data from backend data.
                        elementBinary = PGUtil.ReadBytes(backendData, dataOffset, elementLength);

                        object elementNative;

                        elementNative = _elementConverter.ConvertBackendBinaryToNative(elementBinary, fieldValueSize, TypeModifier);

                        dstOffsets[dimOffset] = i;
                        dst.SetValue(elementNative, dstOffsets);

                        dataOffset += elementLength;
                    }
                }
            }
        }
示例#2
0
        /// <summary>
        /// Creates an n-dimensional System.Array from PG binary representation.
        /// This function reads the array header and sets up an n-dimensional System.Array object to hold its data.
        /// PopulateArrayFromBinaryArray() is then called to carry out array population.
        /// </summary>
        public object ArrayBinaryToArray(NpgsqlBackendTypeInfo TypeInfo, byte[] BackendData, Int32 fieldValueSize, Int32 TypeModifier)
        {
            // Sanity check.
            if (BackendData.Length < 4)
            {
                throw new Exception("Insuffient backend data to describe dimension count in binary array header");
            }

            // Offset 0 holds an integer dscribing the number of dimensions in the array.
            int nDims = PGUtil.ReadInt32(BackendData, 0);

            // Sanity check.
            if (nDims < 0)
            {
                throw new NpgsqlException("Invalid array dimension count encountered in binary array header");
            }

            // {PG handles 0-dimension arrays, but .net does not.  Return a 0-size 1-dimensional array.
            if (nDims == 0)
            {
                return(Array.CreateInstance(_elementConverter.FrameworkType, 0));
            }

            int dimOffset;
            // Offset 12 begins an array of {int,int} objects, of length nDims.
            int dataOffset = 12;

            // Sanity check.
            if (BackendData.Length < dataOffset + nDims * 8)
            {
                throw new NpgsqlException("Insuffient backend data to describe all expected dimensions in binary array header");
            }

            int[] dimLengths;
            int[] dimLBounds;

            dimLengths = new int[nDims];
            dimLBounds = new int[nDims];

            // Populate array dimension lengths and lower bounds.
            for (dimOffset = 0; dimOffset < nDims; dimOffset++)
            {
                dimLengths[dimOffset] = PGUtil.ReadInt32(BackendData, dataOffset);
                dataOffset           += 4;

                // Lower bounds is 1-based in SQL, 0-based in .NET.
                dimLBounds[dimOffset] = PGUtil.ReadInt32(BackendData, dataOffset) - 1;
                dataOffset           += 4;
            }

            Array dst;

            int[] dstOffsets;

            dst = Array.CreateInstance(_elementConverter.FrameworkType, dimLengths, dimLBounds);

            dstOffsets = new int[nDims];

            // Right after the dimension descriptors begins array data.
            // Populate the new array.
            PopulateArrayFromBinaryArray(TypeInfo, BackendData, fieldValueSize, TypeModifier, ref dataOffset, dimLengths, dimLBounds, 0, dst, dstOffsets);

            return(dst);
        }
示例#3
0
        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);
            }
        }
示例#4
0
        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);
            }
        }
示例#5
0
        private Object FastpathV2(Int32 fnid, Boolean resulttype, FastpathArg[] args)
        {
            // added Oct 7 1998 to give us thread safety
            lock (stream)
            {
                // send the function call

                stream
                .WriteBytesNullTerminated((byte)ASCIIBytes.F)
                .WriteInt32(fnid)
                .WriteInt32(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 = "";
                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);
                        String msg = PGUtil.ReadString(stream);

                        break;

                    //------------------------------
                    // Error message returned
                    case 'E':
                        NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion, stream);
                        errorMessage += e.Message;
                        break;

                    //------------------------------
                    // Notice from backend
                    case 'N':
                        NpgsqlError notice = new NpgsqlError(conn.BackendProtocolVersion, stream);
                        errorMessage += notice.Message;
                        break;

                    case 'V':
                        Char l_nextChar = (Char)stream.ReadByte();
                        if (l_nextChar == 'G')
                        {
                            Int32 sz = PGUtil.ReadInt32(stream);
                            // Return an Integer if
                            if (resulttype)
                            {
                                result = PGUtil.ReadInt32(stream);
                            }
                            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(string.Format("postgresql.fp.protocol {0}", c));
                    }
                }

                if (errorMessage != null)
                {
                    throw new NpgsqlException("postgresql.fp.error" + errorMessage);
                }

                return(result);
            }
        }