mirror of
https://github.com/MichaelGrafnetter/DSInternals
synced 2025-02-04 13:11:33 +00:00
584 lines
21 KiB
C#
Vendored
584 lines
21 KiB
C#
Vendored
//-----------------------------------------------------------------------
|
|
// <copyright file="jet_indexcreate.cs" company="Microsoft Corporation">
|
|
// Copyright (c) Microsoft Corporation.
|
|
// </copyright>
|
|
//-----------------------------------------------------------------------
|
|
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Contains the information needed to create an index over data in an ESE database.
|
|
/// </summary>
|
|
[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<JET_INDEXCREATE>, IDeepCloneable<JET_INDEXCREATE>
|
|
{
|
|
/// <summary>
|
|
/// Name of the index.
|
|
/// </summary>
|
|
private string name;
|
|
|
|
/// <summary>
|
|
/// Index key.
|
|
/// </summary>
|
|
private string key;
|
|
|
|
/// <summary>
|
|
/// Length of the index key.
|
|
/// </summary>
|
|
private int keyLength;
|
|
|
|
/// <summary>
|
|
/// Index options.
|
|
/// </summary>
|
|
private CreateIndexGrbit options;
|
|
|
|
/// <summary>
|
|
/// Index density.
|
|
/// </summary>
|
|
private int density;
|
|
|
|
/// <summary>
|
|
/// Unicode comparison options.
|
|
/// </summary>
|
|
private JET_UNICODEINDEX unicodeOptions;
|
|
|
|
/// <summary>
|
|
/// Maximum length of a column to store in the index.
|
|
/// </summary>
|
|
private int maxSegmentLength;
|
|
|
|
/// <summary>
|
|
/// Conditional columns.
|
|
/// </summary>
|
|
private JET_CONDITIONALCOLUMN[] conditionalColumns;
|
|
|
|
/// <summary>
|
|
/// Number of conditional columns.
|
|
/// </summary>
|
|
private int numConditionalColumns;
|
|
|
|
/// <summary>
|
|
/// Error code from index creation.
|
|
/// </summary>
|
|
private JET_err errorCode;
|
|
|
|
/// <summary>
|
|
/// Maximum length of index keys.
|
|
/// </summary>
|
|
private int maximumKeyLength;
|
|
|
|
/// <summary>
|
|
/// Space allocation, maintenance, and usage hints.
|
|
/// </summary>
|
|
private JET_SPACEHINTS spaceHints;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the error code from creating this index.
|
|
/// </summary>
|
|
public JET_err err
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.errorCode; }
|
|
set { this.errorCode = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the name of the index to create.
|
|
/// </summary>
|
|
public string szIndexName
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.name; }
|
|
set { this.name = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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).
|
|
/// </summary>
|
|
public string szKey
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.key; }
|
|
set { this.key = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the length, in characters, of szKey including the two terminating nulls.
|
|
/// </summary>
|
|
public int cbKey
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.keyLength; }
|
|
set { this.keyLength = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets index creation options.
|
|
/// </summary>
|
|
public CreateIndexGrbit grbit
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.options; }
|
|
set { this.options = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the density of the index.
|
|
/// </summary>
|
|
public int ulDensity
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.density; }
|
|
set { this.density = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the optional unicode comparison options.
|
|
/// </summary>
|
|
public JET_UNICODEINDEX pidxUnicode
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.unicodeOptions; }
|
|
set { this.unicodeOptions = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the maximum length, in bytes, of each column to store in the index.
|
|
/// </summary>
|
|
public int cbVarSegMac
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.maxSegmentLength; }
|
|
set { this.maxSegmentLength = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the optional conditional columns.
|
|
/// </summary>
|
|
public JET_CONDITIONALCOLUMN[] rgconditionalcolumn
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.conditionalColumns; }
|
|
set { this.conditionalColumns = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of conditional columns.
|
|
/// </summary>
|
|
public int cConditionalColumn
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.numConditionalColumns; }
|
|
set { this.numConditionalColumns = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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 <see cref="JET_param.DatabasePageSize"/>. The
|
|
/// maximum key size can be retrieved with <see cref="SystemParameters.KeyMost"/>.
|
|
/// <para>
|
|
/// This parameter is ignored on Windows XP and Windows Server 2003.
|
|
/// </para>
|
|
/// <para>
|
|
/// Unlike the unmanaged API, <see cref="VistaGrbits.IndexKeyMost"/>
|
|
/// (JET_bitIndexKeyMost) is not needed, it will be added automatically.
|
|
/// </para>
|
|
/// </summary>
|
|
public int cbKeyMost
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.maximumKeyLength; }
|
|
set { this.maximumKeyLength = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets space allocation, maintenance, and usage hints.
|
|
/// </summary>
|
|
public JET_SPACEHINTS pSpaceHints
|
|
{
|
|
[DebuggerStepThrough]
|
|
get { return this.spaceHints; }
|
|
set { this.spaceHints = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a deep copy of the object.
|
|
/// </summary>
|
|
/// <returns>A deep copy of the object.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate a string representation of the instance.
|
|
/// </summary>
|
|
/// <returns>The structure as a string.</returns>
|
|
public override string ToString()
|
|
{
|
|
return string.Format(CultureInfo.InvariantCulture, "JET_INDEXCREATE({0}:{1})", this.szIndexName, this.szKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a value indicating whether this instance is equal
|
|
/// to another instance.
|
|
/// </summary>
|
|
/// <param name="other">An instance to compare with this instance.</param>
|
|
/// <returns>True if the two instances are equal.</returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check this object to make sure its parameters are valid.
|
|
/// </summary>
|
|
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
|
|
/// <summary>
|
|
/// Gets the native (interop) version of this object, except for
|
|
/// <see cref="szIndexName"/> and <see cref="szKey"/>.
|
|
/// </summary>
|
|
/// <returns>The native (interop) version of this object.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the native (interop) version of this object, except for
|
|
/// <see cref="szIndexName"/> and <see cref="szKey"/>.
|
|
/// </summary>
|
|
/// <returns>The native (interop) version of this object.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the native (interop) version of this object. The following members
|
|
/// are not converted:
|
|
/// <see cref="szIndexName"/>, <see cref="szKey"/>, <see cref="pSpaceHints"/>.
|
|
/// </summary>
|
|
/// <returns>The native (interop) version of this object.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets only the output fields of the object from a NATIVE_INDEXCREATE2 struct,
|
|
/// specifically <see cref="err"/>.
|
|
/// </summary>
|
|
/// <param name="value">
|
|
/// The native indexcreate to set the values from.
|
|
/// </param>
|
|
internal void SetFromNativeIndexCreate(NATIVE_INDEXCREATE2 value)
|
|
{
|
|
this.SetFromNativeIndexCreate(value.indexcreate1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets only the output fields of the object from a NATIVE_INDEXCREATE1 struct,
|
|
/// specifically <see cref="err"/>.
|
|
/// </summary>
|
|
/// <param name="value">
|
|
/// The native indexcreate to set the values from.
|
|
/// </param>
|
|
internal void SetFromNativeIndexCreate(NATIVE_INDEXCREATE1 value)
|
|
{
|
|
this.SetFromNativeIndexCreate(value.indexcreate);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets only the output fields of the object from a native NATIVE_INDEXCREATE struct,
|
|
/// specifically <see cref="err"/>.
|
|
/// </summary>
|
|
/// <param name="value">
|
|
/// The native indexcreate to set the values from.
|
|
/// </param>
|
|
internal void SetFromNativeIndexCreate(NATIVE_INDEXCREATE value)
|
|
{
|
|
this.err = (JET_err)value.err;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Returns a value indicating whether the pidxUnicode member of this
|
|
/// instance is equal to another instance.
|
|
/// </summary>
|
|
/// <param name="other">An instance to compare with this instance.</param>
|
|
/// <returns>True if the pidxUnicode members of two instances are equal.</returns>
|
|
private bool IsUnicodeIndexEqual(JET_INDEXCREATE other)
|
|
{
|
|
return (null == this.pidxUnicode)
|
|
? (null == other.pidxUnicode)
|
|
: this.pidxUnicode.ContentEquals(other.pidxUnicode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a value indicating whether the conditional column members of this
|
|
/// instance is equal to another instance.
|
|
/// </summary>
|
|
/// <param name="other">An instance to compare with this instance.</param>
|
|
/// <returns>True if the conditional column members of two instances are equal.</returns>
|
|
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
|
|
/// <summary>
|
|
/// The native version of the JET_INDEXCREATE structure.
|
|
/// </summary>
|
|
[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
|
|
{
|
|
/// <summary>
|
|
/// Size of the structure.
|
|
/// </summary>
|
|
public uint cbStruct;
|
|
|
|
/// <summary>
|
|
/// Name of the index.
|
|
/// </summary>
|
|
public IntPtr szIndexName;
|
|
|
|
/// <summary>
|
|
/// Index key description.
|
|
/// </summary>
|
|
public IntPtr szKey;
|
|
|
|
/// <summary>
|
|
/// Size of index key description.
|
|
/// </summary>
|
|
public uint cbKey;
|
|
|
|
/// <summary>
|
|
/// Index options.
|
|
/// </summary>
|
|
public uint grbit;
|
|
|
|
/// <summary>
|
|
/// Index density.
|
|
/// </summary>
|
|
public uint ulDensity;
|
|
|
|
/// <summary>
|
|
/// Pointer to unicode sort options.
|
|
/// </summary>
|
|
public NATIVE_UNICODEINDEX* pidxUnicode;
|
|
|
|
/// <summary>
|
|
/// Maximum size of column data to index. This can also be
|
|
/// a pointer to a JET_TUPLELIMITS structure.
|
|
/// </summary>
|
|
public IntPtr cbVarSegMac;
|
|
|
|
/// <summary>
|
|
/// Pointer to array of conditional columns.
|
|
/// </summary>
|
|
public IntPtr rgconditionalcolumn;
|
|
|
|
/// <summary>
|
|
/// Count of conditional columns.
|
|
/// </summary>
|
|
public uint cConditionalColumn;
|
|
|
|
/// <summary>
|
|
/// Returned error from index creation.
|
|
/// </summary>
|
|
public int err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The native version of the JET_INDEXCREATE2 structure. Introduced in Windows 7,
|
|
/// this includes a <see cref="JET_SPACEHINTS"/> member.
|
|
/// </summary>
|
|
[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
|
|
{
|
|
/// <summary>
|
|
/// Nested NATIVE_INDEXCREATE1 structure.
|
|
/// </summary>
|
|
public NATIVE_INDEXCREATE1 indexcreate1;
|
|
|
|
/// <summary>
|
|
/// A <see cref="NATIVE_SPACEHINTS"/> pointer.
|
|
/// </summary>
|
|
public IntPtr pSpaceHints;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
[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
|
|
{
|
|
/// <summary>
|
|
/// Nested NATIVE_INDEXCREATE structure.
|
|
/// </summary>
|
|
public NATIVE_INDEXCREATE indexcreate;
|
|
|
|
/// <summary>
|
|
/// Maximum size of the key.
|
|
/// </summary>
|
|
public uint cbKeyMost;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
}
|
|
}
|