//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // //----------------------------------------------------------------------- namespace Microsoft.Isam.Esent.Interop { using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using Microsoft.Isam.Esent.Interop.Vista; /// /// Contains the information needed to create an index over data in an ESE database. /// [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "This should match the unmanaged API, which isn't capitalized.")] [Serializable] public sealed partial class JET_INDEXCREATE : IContentEquatable, IDeepCloneable { /// /// Name of the index. /// private string name; /// /// Index key. /// private string key; /// /// Length of the index key. /// private int keyLength; /// /// Index options. /// private CreateIndexGrbit options; /// /// Index density. /// private int density; /// /// Unicode comparison options. /// private JET_UNICODEINDEX unicodeOptions; /// /// Maximum length of a column to store in the index. /// private int maxSegmentLength; /// /// Conditional columns. /// private JET_CONDITIONALCOLUMN[] conditionalColumns; /// /// Number of conditional columns. /// private int numConditionalColumns; /// /// Error code from index creation. /// private JET_err errorCode; /// /// Maximum length of index keys. /// private int maximumKeyLength; /// /// Space allocation, maintenance, and usage hints. /// private JET_SPACEHINTS spaceHints; /// /// Gets or sets the error code from creating this index. /// public JET_err err { [DebuggerStepThrough] get { return this.errorCode; } set { this.errorCode = value; } } /// /// Gets or sets the name of the index to create. /// public string szIndexName { [DebuggerStepThrough] get { return this.name; } set { this.name = value; } } /// /// Gets or sets the description of the index key. This is a double /// null-terminated string of null-delimited tokens. Each token is /// of the form [direction-specifier][column-name], where /// direction-specification is either "+" or "-". for example, a /// szKey of "+abc\0-def\0+ghi\0" will index over the three columns /// "abc" (in ascending order), "def" (in descending order), and "ghi" /// (in ascending order). /// public string szKey { [DebuggerStepThrough] get { return this.key; } set { this.key = value; } } /// /// Gets or sets the length, in characters, of szKey including the two terminating nulls. /// public int cbKey { [DebuggerStepThrough] get { return this.keyLength; } set { this.keyLength = value; } } /// /// Gets or sets index creation options. /// public CreateIndexGrbit grbit { [DebuggerStepThrough] get { return this.options; } set { this.options = value; } } /// /// Gets or sets the density of the index. /// public int ulDensity { [DebuggerStepThrough] get { return this.density; } set { this.density = value; } } /// /// Gets or sets the optional unicode comparison options. /// public JET_UNICODEINDEX pidxUnicode { [DebuggerStepThrough] get { return this.unicodeOptions; } set { this.unicodeOptions = value; } } /// /// Gets or sets the maximum length, in bytes, of each column to store in the index. /// public int cbVarSegMac { [DebuggerStepThrough] get { return this.maxSegmentLength; } set { this.maxSegmentLength = value; } } /// /// Gets or sets the optional conditional columns. /// public JET_CONDITIONALCOLUMN[] rgconditionalcolumn { [DebuggerStepThrough] get { return this.conditionalColumns; } set { this.conditionalColumns = value; } } /// /// Gets or sets the number of conditional columns. /// public int cConditionalColumn { [DebuggerStepThrough] get { return this.numConditionalColumns; } set { this.numConditionalColumns = value; } } /// /// Gets or sets the maximum allowable size, in bytes, for keys in the index. /// The minimum supported maximum key size is JET_cbKeyMostMin (255) which /// is the legacy maximum key size. The maximum key size is dependent on /// the database page size . The /// maximum key size can be retrieved with . /// /// This parameter is ignored on Windows XP and Windows Server 2003. /// /// /// Unlike the unmanaged API, /// (JET_bitIndexKeyMost) is not needed, it will be added automatically. /// /// public int cbKeyMost { [DebuggerStepThrough] get { return this.maximumKeyLength; } set { this.maximumKeyLength = value; } } /// /// Gets or sets space allocation, maintenance, and usage hints. /// public JET_SPACEHINTS pSpaceHints { [DebuggerStepThrough] get { return this.spaceHints; } set { this.spaceHints = value; } } /// /// Returns a deep copy of the object. /// /// A deep copy of the object. public JET_INDEXCREATE DeepClone() { JET_INDEXCREATE result = (JET_INDEXCREATE)this.MemberwiseClone(); result.pidxUnicode = (null == this.pidxUnicode) ? null : this.pidxUnicode.DeepClone(); this.conditionalColumns = Util.DeepCloneArray(this.conditionalColumns); return result; } /// /// Generate a string representation of the instance. /// /// The structure as a string. public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "JET_INDEXCREATE({0}:{1})", this.szIndexName, this.szKey); } /// /// Returns a value indicating whether this instance is equal /// to another instance. /// /// An instance to compare with this instance. /// True if the two instances are equal. public bool ContentEquals(JET_INDEXCREATE other) { if (null == other) { return false; } this.CheckMembersAreValid(); other.CheckMembersAreValid(); return this.err == other.err && this.szIndexName == other.szIndexName && this.szKey == other.szKey && this.cbKey == other.cbKey && this.grbit == other.grbit && this.ulDensity == other.ulDensity && this.cbVarSegMac == other.cbVarSegMac && this.cbKeyMost == other.cbKeyMost && this.IsUnicodeIndexEqual(other) && this.AreConditionalColumnsEqual(other); } /// /// Check this object to make sure its parameters are valid. /// internal void CheckMembersAreValid() { if (null == this.szIndexName) { throw new ArgumentNullException("szIndexName"); } if (null == this.szKey) { throw new ArgumentNullException("szKey"); } if (this.cbKey > checked(this.szKey.Length + 1)) { throw new ArgumentOutOfRangeException("cbKey", this.cbKey, "cannot be greater than the length of szKey"); } if (this.cbKey < 0) { throw new ArgumentOutOfRangeException("cbKey", this.cbKey, "cannot be negative"); } if (this.ulDensity < 0) { throw new ArgumentOutOfRangeException("ulDensity", this.ulDensity, "cannot be negative"); } if (this.cbKeyMost < 0) { throw new ArgumentOutOfRangeException("cbKeyMost", this.cbKeyMost, "cannot be negative"); } if (this.cbVarSegMac < 0) { throw new ArgumentOutOfRangeException("cbVarSegMac", this.cbVarSegMac, "cannot be negative"); } if ((this.cConditionalColumn > 0 && null == this.rgconditionalcolumn) || (this.cConditionalColumn > 0 && this.cConditionalColumn > this.rgconditionalcolumn.Length)) { throw new ArgumentOutOfRangeException("cConditionalColumn", this.cConditionalColumn, "cannot be greater than the length of rgconditionalcolumn"); } if (this.cConditionalColumn < 0) { throw new ArgumentOutOfRangeException( "cConditionalColumn", this.cConditionalColumn, "cannot be negative"); } } #if !MANAGEDESENT_ON_WSA // Not exposed in MSDK /// /// Gets the native (interop) version of this object, except for /// and . /// /// The native (interop) version of this object. internal NATIVE_INDEXCREATE GetNativeIndexcreate() { this.CheckMembersAreValid(); var native = new NATIVE_INDEXCREATE(); native.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXCREATE))); // szIndexName and szKey are converted at pinvoke time. // // native.szIndexName = this.szIndexName; // native.szKey = this.szKey; native.cbKey = checked((uint)this.cbKey); native.grbit = unchecked((uint)this.grbit); native.ulDensity = checked((uint)this.ulDensity); native.cbVarSegMac = new IntPtr(this.cbVarSegMac); native.cConditionalColumn = checked((uint)this.cConditionalColumn); return native; } /// /// Gets the native (interop) version of this object, except for /// and . /// /// The native (interop) version of this object. internal NATIVE_INDEXCREATE1 GetNativeIndexcreate1() { var native = new NATIVE_INDEXCREATE1(); native.indexcreate = this.GetNativeIndexcreate(); native.indexcreate.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXCREATE1))); if (0 != this.cbKeyMost) { native.cbKeyMost = checked((uint)this.cbKeyMost); native.indexcreate.grbit |= unchecked((uint)VistaGrbits.IndexKeyMost); } return native; } /// /// Gets the native (interop) version of this object. The following members /// are not converted: /// , , . /// /// The native (interop) version of this object. internal NATIVE_INDEXCREATE2 GetNativeIndexcreate2() { var native = new NATIVE_INDEXCREATE2(); native.indexcreate1 = this.GetNativeIndexcreate1(); native.indexcreate1.indexcreate.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXCREATE2))); // pSpaceHints conversion is done at pinvoke time. return native; } /// /// Sets only the output fields of the object from a NATIVE_INDEXCREATE2 struct, /// specifically . /// /// /// The native indexcreate to set the values from. /// internal void SetFromNativeIndexCreate(NATIVE_INDEXCREATE2 value) { this.SetFromNativeIndexCreate(value.indexcreate1); } /// /// Sets only the output fields of the object from a NATIVE_INDEXCREATE1 struct, /// specifically . /// /// /// The native indexcreate to set the values from. /// internal void SetFromNativeIndexCreate(NATIVE_INDEXCREATE1 value) { this.SetFromNativeIndexCreate(value.indexcreate); } /// /// Sets only the output fields of the object from a native NATIVE_INDEXCREATE struct, /// specifically . /// /// /// The native indexcreate to set the values from. /// internal void SetFromNativeIndexCreate(NATIVE_INDEXCREATE value) { this.err = (JET_err)value.err; } #endif // !MANAGEDESENT_ON_WSA /// /// Returns a value indicating whether the pidxUnicode member of this /// instance is equal to another instance. /// /// An instance to compare with this instance. /// True if the pidxUnicode members of two instances are equal. private bool IsUnicodeIndexEqual(JET_INDEXCREATE other) { return (null == this.pidxUnicode) ? (null == other.pidxUnicode) : this.pidxUnicode.ContentEquals(other.pidxUnicode); } /// /// Returns a value indicating whether the conditional column members of this /// instance is equal to another instance. /// /// An instance to compare with this instance. /// True if the conditional column members of two instances are equal. private bool AreConditionalColumnsEqual(JET_INDEXCREATE other) { if (this.cConditionalColumn != other.cConditionalColumn) { return false; } for (int i = 0; i < this.cConditionalColumn; ++i) { if (!this.rgconditionalcolumn[i].ContentEquals(other.rgconditionalcolumn[i])) { return false; } } return true; } #if !MANAGEDESENT_ON_WSA // Not exposed in MSDK /// /// The native version of the JET_INDEXCREATE structure. /// [StructLayout(LayoutKind.Sequential)] [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "This should match the unmanaged API, which isn't capitalized.")] [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "This should match the unmanaged API, which isn't capitalized.")] internal unsafe struct NATIVE_INDEXCREATE { /// /// Size of the structure. /// public uint cbStruct; /// /// Name of the index. /// public IntPtr szIndexName; /// /// Index key description. /// public IntPtr szKey; /// /// Size of index key description. /// public uint cbKey; /// /// Index options. /// public uint grbit; /// /// Index density. /// public uint ulDensity; /// /// Pointer to unicode sort options. /// public NATIVE_UNICODEINDEX* pidxUnicode; /// /// Maximum size of column data to index. This can also be /// a pointer to a JET_TUPLELIMITS structure. /// public IntPtr cbVarSegMac; /// /// Pointer to array of conditional columns. /// public IntPtr rgconditionalcolumn; /// /// Count of conditional columns. /// public uint cConditionalColumn; /// /// Returned error from index creation. /// public int err; } /// /// The native version of the JET_INDEXCREATE2 structure. Introduced in Windows 7, /// this includes a member. /// [StructLayout(LayoutKind.Sequential)] [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "This should match the unmanaged API, which isn't capitalized.")] [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "This should match the unmanaged API, which isn't capitalized.")] internal struct NATIVE_INDEXCREATE2 { /// /// Nested NATIVE_INDEXCREATE1 structure. /// public NATIVE_INDEXCREATE1 indexcreate1; /// /// A pointer. /// public IntPtr pSpaceHints; } /// /// The native version of the JET_INDEXCREATE structure. This version includes the cbKeyMost /// member, which is only valid on Windows Vista and above, but the name of the structure /// was not changed for Vista. /// [StructLayout(LayoutKind.Sequential)] [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "This should match the unmanaged API, which isn't capitalized.")] [SuppressMessage( "Microsoft.StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "This should match the unmanaged API, which isn't capitalized.")] internal struct NATIVE_INDEXCREATE1 { /// /// Nested NATIVE_INDEXCREATE structure. /// public NATIVE_INDEXCREATE indexcreate; /// /// Maximum size of the key. /// public uint cbKeyMost; } #endif // !MANAGEDESENT_ON_WSA } }