Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
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;
                    }
                }
            }
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Create a new ArrayBackendToNativeTypeConverter
 /// </summary>
 /// <param name="elementConverter"><see cref="NpgsqlBackendTypeInfo"/> for the element type.</param>
 public ArrayBackendToNativeTypeConverter(NpgsqlBackendTypeInfo elementConverter)
 {
     _elementConverter = elementConverter;
 }