/// <summary>
        /// Gets the NATIVE_indexcolumn structure that represents the object.
        /// </summary>
        /// <param name="handles">GC handle collection to add any pinned handles.</param>
        /// <returns>The NATIVE_indexcolumn structure.</returns>
        internal NATIVE_INDEX_RANGE GetNativeIndexRange(ref GCHandleCollection handles)
        {
            NATIVE_INDEX_RANGE indexRange = new NATIVE_INDEX_RANGE();

            NATIVE_INDEX_COLUMN[] nativeColumns;
            if (this.startColumns != null)
            {
                nativeColumns = new NATIVE_INDEX_COLUMN[this.startColumns.Length];
                for (int i = 0; i < this.startColumns.Length; i++)
                {
                    nativeColumns[i] = this.startColumns[i].GetNativeIndexColumn(ref handles);
                }

                indexRange.rgStartColumns = handles.Add(nativeColumns);
                indexRange.cStartColumns  = (uint)this.startColumns.Length;
            }

            if (this.endColumns != null)
            {
                nativeColumns = new NATIVE_INDEX_COLUMN[this.endColumns.Length];
                for (int i = 0; i < this.endColumns.Length; i++)
                {
                    nativeColumns[i] = this.endColumns[i].GetNativeIndexColumn(ref handles);
                }

                indexRange.rgEndColumns = handles.Add(nativeColumns);
                indexRange.cEndColumns  = (uint)this.endColumns.Length;
            }

            return(indexRange);
        }
        /// <summary>
        /// If the records with the specified key ranges are not in the
        /// buffer cache then start asynchronous reads to bring the records
        /// into the database buffer cache.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The table to issue the prereads against.</param>
        /// <param name="keysStart">The start of key ranges to preread.</param>
        /// <param name="keyStartLengths">The lengths of the start keys to preread.</param>
        /// <param name="keysEnd">The end of key rangess to preread.</param>
        /// <param name="keyEndLengths">The lengths of the end keys to preread.</param>
        /// <param name="rangeIndex">The index of the first key range in the array to read.</param>
        /// <param name="rangeCount">The maximum number of key ranges to preread.</param>
        /// <param name="rangesPreread">Returns the number of keys actually preread.</param>
        /// <param name="columnsPreread">List of column ids for long value columns to preread.</param>
        /// <param name="grbit">Preread options. Used to specify the direction of the preread.</param>
        /// <returns>An error or warning.</returns>
        public int JetPrereadKeyRanges(
            JET_SESID sesid,
            JET_TABLEID tableid,
            byte[][] keysStart,
            int[] keyStartLengths,
            byte[][] keysEnd,
            int[] keyEndLengths,
            int rangeIndex,
            int rangeCount,
            out int rangesPreread,
            JET_COLUMNID[] columnsPreread,
            PrereadIndexRangesGrbit grbit)
        {
            TraceFunctionCall("JetPrereadKeyRanges");
            this.CheckSupportsWindows8Features("JetPrereadKeyRanges");
            CheckDataSize(keysStart, rangeIndex, "rangeIndex", rangeCount, "rangeCount");
            CheckDataSize(keyStartLengths, rangeIndex, "rangeIndex", rangeCount, "rangeCount");
            CheckNotNull(keysStart, "keysStart");
            if (keysEnd != null)
            {
                CheckNotNull(keyEndLengths, "keyEndLengths");
                CheckDataSize(keysEnd, rangeIndex, "rangeIndex", rangeCount, "rangeCount");
            }

            if (keyEndLengths != null)
            {
                CheckNotNull(keysEnd, "keysEnd");
                CheckDataSize(keyEndLengths, rangeIndex, "rangeIndex", rangeCount, "rangeCount");
            }

            grbit = grbit | PrereadIndexRangesGrbit.NormalizedKey;

            using (var handles = new GCHandleCollection())
            {
                NATIVE_INDEX_COLUMN[] startColumn;
                NATIVE_INDEX_COLUMN[] endColumn;
                NATIVE_INDEX_RANGE[] ranges = new NATIVE_INDEX_RANGE[rangeCount];
                for (int i = 0; i < rangeCount; i++)
                {
                    startColumn = new NATIVE_INDEX_COLUMN[1];
                    startColumn[0].pvData = handles.Add(keysStart[i + rangeIndex]);
                    startColumn[0].cbData = (uint)keyStartLengths[i + rangeIndex];
                    ranges[i].rgStartColumns = handles.Add(startColumn);
                    ranges[i].cStartColumns = 1;
                    if (keysEnd != null)
                    {
                        endColumn = new NATIVE_INDEX_COLUMN[1];
                        endColumn[0].pvData = handles.Add(keysEnd[i + rangeIndex]);
                        endColumn[0].cbData = (uint)keyEndLengths[i + rangeIndex];
                        ranges[i].rgEndColumns = handles.Add(endColumn);
                        ranges[i].cEndColumns = 1;
                    }
                }

                if (columnsPreread != null)
                {
                    var nativecolumnids = new uint[columnsPreread.Length];
                    for (int i = 0; i < columnsPreread.Length; i++)
                    {
                        nativecolumnids[i] = (uint)columnsPreread[i].Value;
                    }

                    return Err(NativeMethods.JetPrereadIndexRanges(sesid.Value, tableid.Value, ranges, (uint)rangeCount, out rangesPreread, nativecolumnids, (uint)columnsPreread.Length, checked((uint)grbit)));
                }
                else
                {
                    return Err(NativeMethods.JetPrereadIndexRanges(sesid.Value, tableid.Value, ranges, (uint)rangeCount, out rangesPreread, null, (uint)0, checked((uint)grbit)));
                }
            }
        }
        /// <summary>
        /// If the records with the specified key rangess are not in the buffer
        /// cache, then start asynchronous reads to bring the records into the
        /// database buffer cache.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The table to issue the prereads against.</param>
        /// <param name="indexRanges">The key rangess to preread.</param>
        /// <param name="rangeIndex">The index of the first key range in the array to read.</param>
        /// <param name="rangeCount">The maximum number of key ranges to preread.</param>
        /// <param name="rangesPreread">Returns the number of keys actually preread.</param>
        /// <param name="columnsPreread">List of column ids for long value columns to preread.</param>
        /// <param name="grbit">Preread options. Used to specify the direction of the preread.</param>
        /// <returns>
        /// An error if the call fails.
        /// </returns>
        public int JetPrereadIndexRanges(
            JET_SESID sesid,
            JET_TABLEID tableid,
            JET_INDEX_RANGE[] indexRanges,
            int rangeIndex,
            int rangeCount,
            out int rangesPreread,
            JET_COLUMNID[] columnsPreread,
            PrereadIndexRangesGrbit grbit)
        {
            TraceFunctionCall("JetPrereadIndexRanges");
            this.CheckSupportsWindows8Features("JetPrereadIndexRanges");
            CheckNotNull(indexRanges, "indexRanges");
            CheckDataSize(indexRanges, rangeIndex, "rangeIndex", rangeCount, "rangeCount");

            var handles = new GCHandleCollection();
            try
            {
                NATIVE_INDEX_RANGE[] nativeRanges = new NATIVE_INDEX_RANGE[rangeCount];
                for (int i = 0; i < rangeCount; i++)
                {
                    nativeRanges[i] = indexRanges[i + rangeIndex].GetNativeIndexRange(ref handles);
                }

                if (columnsPreread != null)
                {
                    var nativecolumnids = new uint[columnsPreread.Length];
                    for (int i = 0; i < columnsPreread.Length; i++)
                    {
                         nativecolumnids[i] = (uint)columnsPreread[i].Value;
                    }

                    return Err(NativeMethods.JetPrereadIndexRanges(sesid.Value, tableid.Value, nativeRanges, (uint)rangeCount, out rangesPreread, nativecolumnids, (uint)columnsPreread.Length, checked((uint)grbit)));
                }
                else
                {
                    return Err(NativeMethods.JetPrereadIndexRanges(sesid.Value, tableid.Value, nativeRanges, (uint)rangeCount, out rangesPreread, null, (uint)0, checked((uint)grbit)));
                }
            }
            finally
            {
                handles.Dispose();
            }
        }
        /// <summary>
        /// Gets the NATIVE_indexcolumn structure that represents the object.
        /// </summary>
        /// <param name="handles">GC handle collection to add any pinned handles.</param>
        /// <returns>The NATIVE_indexcolumn structure.</returns>
        internal NATIVE_INDEX_RANGE GetNativeIndexRange(ref GCHandleCollection handles)
        {
            NATIVE_INDEX_RANGE indexRange = new NATIVE_INDEX_RANGE();
            NATIVE_INDEX_COLUMN[] nativeColumns;
            if (this.startColumns != null)
            {
                nativeColumns = new NATIVE_INDEX_COLUMN[this.startColumns.Length];
                for (int i = 0; i < this.startColumns.Length; i++)
                {
                    nativeColumns[i] = this.startColumns[i].GetNativeIndexColumn(ref handles);
                }

                indexRange.rgStartColumns = handles.Add(nativeColumns);
                indexRange.cStartColumns = (uint)this.startColumns.Length;
            }

            if (this.endColumns != null)
            {
                nativeColumns = new NATIVE_INDEX_COLUMN[this.endColumns.Length];
                for (int i = 0; i < this.endColumns.Length; i++)
                {
                    nativeColumns[i] = this.endColumns[i].GetNativeIndexColumn(ref handles);
                }

                indexRange.rgEndColumns = handles.Add(nativeColumns);
                indexRange.cEndColumns = (uint)this.endColumns.Length;
            }

            return indexRange;
        }