mirror of
https://github.com/MichaelGrafnetter/DSInternals
synced 2025-01-20 22:10:46 +00:00
6437 lines
280 KiB
C#
6437 lines
280 KiB
C#
//-----------------------------------------------------------------------
|
|
// <copyright file="JetApi.cs" company="Microsoft Corporation">
|
|
// Copyright (c) Microsoft Corporation.
|
|
// </copyright>
|
|
//-----------------------------------------------------------------------
|
|
|
|
namespace Microsoft.Isam.Esent.Interop.Implementation
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Microsoft.Isam.Esent.Interop.Server2003;
|
|
using Microsoft.Isam.Esent.Interop.Vista;
|
|
using Microsoft.Isam.Esent.Interop.Windows7;
|
|
using Microsoft.Isam.Esent.Interop.Windows8;
|
|
|
|
using Win32 = Microsoft.Isam.Esent.Interop.Win32;
|
|
|
|
/// <summary>
|
|
/// Calls to the ESENT interop layer. These calls take the managed types (e.g. JET_SESID) and
|
|
/// return errors.
|
|
/// </summary>
|
|
internal sealed partial class JetApi : IJetApi
|
|
{
|
|
/// <summary>
|
|
/// API call tracing.
|
|
/// </summary>
|
|
private static readonly TraceSwitch TraceSwitch = new TraceSwitch("ESENT P/Invoke", "P/Invoke calls to ESENT");
|
|
|
|
/// <summary>
|
|
/// The version of esent. If this is zero then it is looked up
|
|
/// with JetGetVersion.
|
|
/// </summary>
|
|
private readonly uint versionOverride;
|
|
|
|
/// <summary>
|
|
/// Callback wrapper collection. This is used for long-running callbacks
|
|
/// (callbacks which can be called after the API call returns). Create a
|
|
/// wrapper here and occasionally clean them up.
|
|
/// </summary>
|
|
private readonly CallbackWrappers callbackWrappers = new CallbackWrappers();
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Initializes static members of the JetApi class.
|
|
/// </summary>
|
|
static JetApi()
|
|
{
|
|
// Prepare these methods for inclusion in a constrained execution region (CER).
|
|
// This is needed by the Instance class. Instance accesses these methods virtually
|
|
// so RemoveUnnecessaryCode won't be able to prepare them.
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetCreateInstance").MethodHandle);
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetCreateInstance2").MethodHandle);
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetInit").MethodHandle);
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetInit2").MethodHandle);
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetInit3").MethodHandle);
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetTerm").MethodHandle);
|
|
RuntimeHelpers.PrepareMethod(typeof(JetApi).GetMethod("JetTerm2").MethodHandle);
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the JetApi class. This allows the version
|
|
/// to be set.
|
|
/// </summary>
|
|
/// <param name="version">
|
|
/// The version of Esent. This is used to override the results of
|
|
/// JetGetVersion.
|
|
/// </param>
|
|
public JetApi(uint version)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
// JetGetVersion isn't available in new Windows UI, so we'll pretend it's always Win8:
|
|
this.versionOverride = 8250 << 8;
|
|
#else
|
|
this.versionOverride = version;
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
this.DetermineCapabilities();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the JetApi class.
|
|
/// </summary>
|
|
public JetApi()
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
// JetGetVersion isn't available in new Windows UI, so we'll pretend it's always Win8:
|
|
this.versionOverride = 8250 << 8;
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
this.DetermineCapabilities();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the capabilities of this implementation of ESENT.
|
|
/// </summary>
|
|
public JetCapabilities Capabilities { get; private set; }
|
|
|
|
#region Init/Term
|
|
|
|
/// <summary>
|
|
/// Allocates a new instance of the database engine.
|
|
/// </summary>
|
|
/// <param name="instance">Returns the new instance.</param>
|
|
/// <param name="name">The name of the instance. Names must be unique.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCreateInstance(out JET_INSTANCE instance, string name)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetCreateInstance2(out instance, name, null, CreateInstanceGrbit.None);
|
|
#else
|
|
TraceFunctionCall("JetCreateInstance");
|
|
instance.Value = IntPtr.Zero;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetCreateInstanceW(out instance.Value, name));
|
|
}
|
|
else
|
|
{
|
|
return Err(NativeMethods.JetCreateInstance(out instance.Value, name));
|
|
}
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Allocate a new instance of the database engine for use in a single
|
|
/// process, with a display name specified.
|
|
/// </summary>
|
|
/// <param name="instance">Returns the newly create instance.</param>
|
|
/// <param name="name">
|
|
/// Specifies a unique string identifier for the instance to be created.
|
|
/// This string must be unique within a given process hosting the
|
|
/// database engine.
|
|
/// </param>
|
|
/// <param name="displayName">
|
|
/// A display name for the instance to be created. This will be used
|
|
/// in eventlog entries.
|
|
/// </param>
|
|
/// <param name="grbit">Creation options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCreateInstance2(out JET_INSTANCE instance, string name, string displayName, CreateInstanceGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetCreateInstance2");
|
|
instance.Value = IntPtr.Zero;
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetCreateInstance2W(out instance.Value, name, displayName, (uint)grbit));
|
|
#else
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetCreateInstance2W(out instance.Value, name, displayName, (uint)grbit));
|
|
}
|
|
else
|
|
{
|
|
return Err(NativeMethods.JetCreateInstance2(out instance.Value, name, displayName, (uint)grbit));
|
|
}
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize the ESENT database engine.
|
|
/// </summary>
|
|
/// <param name="instance">
|
|
/// The instance to initialize. If an instance hasn't been
|
|
/// allocated then a new one is created and the engine
|
|
/// will operate in single-instance mode.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetInit(ref JET_INSTANCE instance)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetInit3(ref instance, null, InitGrbit.None);
|
|
#else
|
|
TraceFunctionCall("JetInit");
|
|
return Err(NativeMethods.JetInit(ref instance.Value));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize the ESENT database engine.
|
|
/// </summary>
|
|
/// <param name="instance">
|
|
/// The instance to initialize. If an instance hasn't been
|
|
/// allocated then a new one is created and the engine
|
|
/// will operate in single-instance mode.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Initialization options.
|
|
/// </param>
|
|
/// <returns>An error or a warning.</returns>
|
|
public int JetInit2(ref JET_INSTANCE instance, InitGrbit grbit)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetInit3(ref instance, null, grbit);
|
|
#else
|
|
TraceFunctionCall("JetInit2");
|
|
return Err(NativeMethods.JetInit2(ref instance.Value, (uint)grbit));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize the ESENT database engine.
|
|
/// </summary>
|
|
/// <param name="instance">
|
|
/// The instance to initialize. If an instance hasn't been
|
|
/// allocated then a new one is created and the engine
|
|
/// will operate in single-instance mode.
|
|
/// </param>
|
|
/// <param name="recoveryOptions">
|
|
/// Additional recovery parameters for remapping databases during
|
|
/// recovery, position where to stop recovery at, or recovery status.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Initialization options.
|
|
/// </param>
|
|
/// <returns>An error code or warning.</returns>
|
|
public int JetInit3(ref JET_INSTANCE instance, JET_RSTINFO recoveryOptions, InitGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetInit3");
|
|
this.CheckSupportsVistaFeatures("JetInit3");
|
|
|
|
if (null != recoveryOptions)
|
|
{
|
|
var callbackWrapper = new StatusCallbackWrapper(recoveryOptions.pfnStatus);
|
|
NATIVE_RSTINFO rstinfo = recoveryOptions.GetNativeRstinfo();
|
|
|
|
unsafe
|
|
{
|
|
int numMaps = (null == recoveryOptions.rgrstmap) ? 0 : recoveryOptions.rgrstmap.Length;
|
|
try
|
|
{
|
|
NATIVE_RSTMAP* maps = stackalloc NATIVE_RSTMAP[numMaps];
|
|
|
|
if (numMaps > 0)
|
|
{
|
|
rstinfo.rgrstmap = maps;
|
|
for (int i = 0; i < numMaps; ++i)
|
|
{
|
|
rstinfo.rgrstmap[i] = recoveryOptions.rgrstmap[i].GetNativeRstmap();
|
|
}
|
|
}
|
|
|
|
rstinfo.pfnStatus = callbackWrapper.NativeCallback;
|
|
int err = Err(NativeMethods.JetInit3W(ref instance.Value, ref rstinfo, (uint)grbit));
|
|
callbackWrapper.ThrowSavedException();
|
|
return err;
|
|
}
|
|
finally
|
|
{
|
|
if (null != rstinfo.rgrstmap)
|
|
{
|
|
for (int i = 0; i < numMaps; ++i)
|
|
{
|
|
rstinfo.rgrstmap[i].FreeHGlobal();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return Err(NativeMethods.JetInit3W(ref instance.Value, IntPtr.Zero, (uint)grbit));
|
|
}
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Retrieves information about the instances that are running.
|
|
/// </summary>
|
|
/// <param name="numInstances">
|
|
/// Returns the number of instances.
|
|
/// </param>
|
|
/// <param name="instances">
|
|
/// Returns an array of instance info objects, one for each running
|
|
/// instance.
|
|
/// </param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetGetInstanceInfo(out int numInstances, out JET_INSTANCE_INFO[] instances)
|
|
{
|
|
TraceFunctionCall("JetGetInstanceInfo");
|
|
|
|
unsafe
|
|
{
|
|
uint nativeNumInstance = 0;
|
|
|
|
// Esent will allocate memory which will be freed by the ConvertInstanceInfos call.
|
|
NATIVE_INSTANCE_INFO* nativeInstanceInfos = null;
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = NativeMethods.JetGetInstanceInfoW(out nativeNumInstance, out nativeInstanceInfos);
|
|
instances = this.ConvertInstanceInfosUnicode(nativeNumInstance, nativeInstanceInfos);
|
|
}
|
|
else
|
|
{
|
|
err = NativeMethods.JetGetInstanceInfo(out nativeNumInstance, out nativeInstanceInfos);
|
|
instances = this.ConvertInstanceInfosAscii(nativeNumInstance, nativeInstanceInfos);
|
|
}
|
|
|
|
numInstances = instances.Length;
|
|
|
|
return Err(err);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about an instance.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to get information about.</param>
|
|
/// <param name="signature">Retrieved information.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetGetInstanceMiscInfo(JET_INSTANCE instance, out JET_SIGNATURE signature, JET_InstanceMiscInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetInstanceMiscInfo");
|
|
this.CheckSupportsVistaFeatures("JetGetInstanceMiscInfo");
|
|
|
|
var nativeSignature = new NATIVE_SIGNATURE();
|
|
int err = NativeMethods.JetGetInstanceMiscInfo(
|
|
instance.Value,
|
|
ref nativeSignature,
|
|
checked((uint)NATIVE_SIGNATURE.Size),
|
|
unchecked((uint)infoLevel));
|
|
|
|
signature = new JET_SIGNATURE(nativeSignature);
|
|
return Err(err);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prevents streaming backup-related activity from continuing on a
|
|
/// specific running instance, thus ending the streaming backup in
|
|
/// a predictable way.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to use.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetStopBackupInstance(JET_INSTANCE instance)
|
|
{
|
|
TraceFunctionCall("JetStopBackupInstance");
|
|
return Err(NativeMethods.JetStopBackupInstance(instance.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepares an instance for termination.
|
|
/// </summary>
|
|
/// <param name="instance">The (running) instance to use.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetStopServiceInstance(JET_INSTANCE instance)
|
|
{
|
|
TraceFunctionCall("JetStopServiceInstance");
|
|
return Err(NativeMethods.JetStopServiceInstance(instance.Value));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Prepares an instance for termination. Can also be used to resume a previous quiescing.
|
|
/// </summary>
|
|
/// <param name="instance">The (running) instance to use.</param>
|
|
/// <param name="grbit">The options to stop or resume the instance.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetStopServiceInstance2(
|
|
JET_INSTANCE instance,
|
|
StopServiceGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetStopServiceInstance2");
|
|
this.CheckSupportsWindows8Features("JetStopServiceInstance2");
|
|
return Err(NativeMethods.JetStopServiceInstance2(instance.Value, unchecked((uint)grbit)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Terminate an instance that was created with <see cref="IJetApi.JetInit"/> or
|
|
/// <see cref="IJetApi.JetCreateInstance"/>.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to terminate.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetTerm(JET_INSTANCE instance)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetTerm2(instance, TermGrbit.None);
|
|
#else
|
|
TraceFunctionCall("JetTerm");
|
|
this.callbackWrappers.Collect();
|
|
if (!instance.IsInvalid)
|
|
{
|
|
return Err(NativeMethods.JetTerm(instance.Value));
|
|
}
|
|
|
|
return (int)JET_err.Success;
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Terminate an instance that was created with <see cref="IJetApi.JetInit"/> or
|
|
/// <see cref="IJetApi.JetCreateInstance"/>.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to terminate.</param>
|
|
/// <param name="grbit">Termination options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetTerm2(JET_INSTANCE instance, TermGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetTerm2");
|
|
this.callbackWrappers.Collect();
|
|
if (!instance.IsInvalid)
|
|
{
|
|
return Err(NativeMethods.JetTerm2(instance.Value, (uint)grbit));
|
|
}
|
|
|
|
return (int)JET_err.Success;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets database configuration options.
|
|
/// </summary>
|
|
/// <param name="instance">
|
|
/// The instance to set the option on or <see cref="JET_INSTANCE.Nil"/>
|
|
/// to set the option on all instances.
|
|
/// </param>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="paramid">The parameter to set.</param>
|
|
/// <param name="paramValue">The value of the parameter to set, if the parameter is an integer type.</param>
|
|
/// <param name="paramString">The value of the parameter to set, if the parameter is a string type.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetSetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, IntPtr paramValue, string paramString)
|
|
{
|
|
TraceFunctionCall("JetSetSystemParameter");
|
|
unsafe
|
|
{
|
|
IntPtr* pinstance = (IntPtr.Zero == instance.Value) ? null : &instance.Value;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetSetSystemParameterW(pinstance, sesid.Value, (uint)paramid, paramValue, paramString));
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetSetSystemParameter(pinstance, sesid.Value, (uint)paramid, paramValue, paramString));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets database configuration options. This overload is used when the
|
|
/// parameter being set is of type JET_CALLBACK.
|
|
/// </summary>
|
|
/// <param name="instance">
|
|
/// The instance to set the option on or <see cref="JET_INSTANCE.Nil"/>
|
|
/// to set the option on all instances.
|
|
/// </param>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="paramid">The parameter to set.</param>
|
|
/// <param name="paramValue">The value of the parameter to set.</param>
|
|
/// <param name="paramString">The value of the string parameter to set.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetSetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, JET_CALLBACK paramValue, string paramString)
|
|
{
|
|
TraceFunctionCall("JetSetSystemParameter");
|
|
|
|
unsafe
|
|
{
|
|
// We are interested in the callback, not the string so we always use the ASCII API.
|
|
IntPtr* pinstance = (IntPtr.Zero == instance.Value) ? null : &instance.Value;
|
|
|
|
if (null == paramValue)
|
|
{
|
|
return
|
|
Err(
|
|
#if MANAGEDESENT_ON_WSA
|
|
NativeMethods.JetSetSystemParameterW(
|
|
pinstance,
|
|
sesid.Value,
|
|
(uint)paramid,
|
|
IntPtr.Zero,
|
|
paramString));
|
|
#else
|
|
NativeMethods.JetSetSystemParameter(
|
|
pinstance,
|
|
sesid.Value,
|
|
(uint)paramid,
|
|
IntPtr.Zero,
|
|
paramString));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
JetCallbackWrapper wrapper = this.callbackWrappers.Add(paramValue);
|
|
this.callbackWrappers.Collect();
|
|
IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(wrapper.NativeCallback);
|
|
#if DEBUG
|
|
GC.Collect();
|
|
#endif // DEBUG
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(
|
|
NativeMethods.JetSetSystemParameterW(
|
|
pinstance,
|
|
sesid.Value,
|
|
(uint)paramid,
|
|
functionPointer,
|
|
paramString));
|
|
#else
|
|
return Err(
|
|
NativeMethods.JetSetSystemParameter(
|
|
pinstance,
|
|
sesid.Value,
|
|
(uint)paramid,
|
|
functionPointer,
|
|
paramString));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets database configuration options.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to retrieve the options from.</param>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="paramid">The parameter to get.</param>
|
|
/// <param name="paramValue">Returns the value of the parameter, if the value is an integer.</param>
|
|
/// <param name="paramString">Returns the value of the parameter, if the value is a string.</param>
|
|
/// <param name="maxParam">The maximum size of the parameter string.</param>
|
|
/// <returns>An ESENT warning code.</returns>
|
|
/// <remarks>
|
|
/// <see cref="JET_param.ErrorToString"/> passes in the error number in the paramValue, which is why it is
|
|
/// a ref parameter and not an out parameter.
|
|
/// </remarks>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetGetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, ref IntPtr paramValue, out string paramString, int maxParam)
|
|
{
|
|
TraceFunctionCall("JetGetSystemParameter");
|
|
CheckNotNegative(maxParam, "maxParam");
|
|
|
|
uint bytesMax = checked((uint)(this.Capabilities.SupportsUnicodePaths ? maxParam * sizeof(char) : maxParam));
|
|
|
|
var sb = new StringBuilder(maxParam);
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetGetSystemParameterW(instance.Value, sesid.Value, (uint)paramid, ref paramValue, sb, bytesMax));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetSystemParameter(instance.Value, sesid.Value, (uint)paramid, ref paramValue, sb, bytesMax));
|
|
#endif
|
|
}
|
|
|
|
paramString = sb.ToString();
|
|
paramString = StringCache.TryToIntern(paramString);
|
|
return err;
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Retrieves the version of the database engine.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="version">Returns the version number of the database engine.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetGetVersion(JET_SESID sesid, out uint version)
|
|
{
|
|
TraceFunctionCall("JetGetVersion");
|
|
uint nativeVersion;
|
|
int err;
|
|
|
|
if (0 != this.versionOverride)
|
|
{
|
|
// We have an explicitly set version
|
|
Trace.WriteLineIf(
|
|
TraceSwitch.TraceVerbose, string.Format(CultureInfo.InvariantCulture, "JetGetVersion overridden with 0x{0:X}", this.versionOverride));
|
|
nativeVersion = this.versionOverride;
|
|
err = 0;
|
|
}
|
|
else
|
|
{
|
|
// Get the version from Esent
|
|
err = Err(NativeMethods.JetGetVersion(sesid.Value, out nativeVersion));
|
|
}
|
|
|
|
version = nativeVersion;
|
|
return err;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
#endregion
|
|
|
|
#region Databases
|
|
|
|
/// <summary>
|
|
/// Creates and attaches a database file.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="database">The path to the database file to create.</param>
|
|
/// <param name="connect">The parameter is not used.</param>
|
|
/// <param name="dbid">Returns the dbid of the new database.</param>
|
|
/// <param name="grbit">Database creation options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetCreateDatabase(JET_SESID sesid, string database, string connect, out JET_DBID dbid, CreateDatabaseGrbit grbit)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetCreateDatabase2(sesid, database, 0, out dbid, grbit);
|
|
#else
|
|
TraceFunctionCall("JetCreateDatabase");
|
|
CheckNotNull(database, "database");
|
|
|
|
dbid = JET_DBID.Nil;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetCreateDatabaseW(sesid.Value, database, connect, out dbid.Value, (uint)grbit));
|
|
}
|
|
|
|
return Err(NativeMethods.JetCreateDatabase(sesid.Value, database, connect, out dbid.Value, (uint)grbit));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates and attaches a database file with a maximum database size specified.
|
|
/// <seealso cref="JetAttachDatabase2"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="database">The path to the database file to create.</param>
|
|
/// <param name="maxPages">
|
|
/// The maximum size, in database pages, of the database. Passing 0 means there is
|
|
/// no enforced maximum.
|
|
/// </param>
|
|
/// <param name="dbid">Returns the dbid of the new database.</param>
|
|
/// <param name="grbit">Database creation options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetCreateDatabase2(JET_SESID sesid, string database, int maxPages, out JET_DBID dbid, CreateDatabaseGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetCreateDatabase2");
|
|
CheckNotNull(database, "database");
|
|
CheckNotNegative(maxPages, "maxPages");
|
|
|
|
dbid = JET_DBID.Nil;
|
|
uint cpgDatabaseSizeMax = checked((uint)maxPages);
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetCreateDatabase2W(sesid.Value, database, cpgDatabaseSizeMax, out dbid.Value, (uint)grbit));
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetCreateDatabase2(sesid.Value, database, cpgDatabaseSizeMax, out dbid.Value, (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attaches a database file for use with a database instance. In order to use the
|
|
/// database, it will need to be subsequently opened with <see cref="IJetApi.JetOpenDatabase"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="database">The database to attach.</param>
|
|
/// <param name="grbit">Attach options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetAttachDatabase(JET_SESID sesid, string database, AttachDatabaseGrbit grbit)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetAttachDatabase2(sesid, database, 0, grbit);
|
|
#else
|
|
TraceFunctionCall("JetAttachDatabase");
|
|
CheckNotNull(database, "database");
|
|
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetAttachDatabaseW(sesid.Value, database, (uint)grbit));
|
|
}
|
|
|
|
return Err(NativeMethods.JetAttachDatabase(sesid.Value, database, (uint)grbit));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attaches a database file for use with a database instance. In order to use the
|
|
/// database, it will need to be subsequently opened with <see cref="JetOpenDatabase"/>.
|
|
/// <seealso cref="JetCreateDatabase2"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="database">The database to attach.</param>
|
|
/// <param name="maxPages">
|
|
/// The maximum size, in database pages, of the database. Passing 0 means there is
|
|
/// no enforced maximum.
|
|
/// </param>
|
|
/// <param name="grbit">Attach options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetAttachDatabase2(JET_SESID sesid, string database, int maxPages, AttachDatabaseGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetAttachDatabase2");
|
|
CheckNotNull(database, "database");
|
|
CheckNotNegative(maxPages, "maxPages");
|
|
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetAttachDatabase2W(sesid.Value, database, checked((uint)maxPages), (uint)grbit));
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetAttachDatabase2(sesid.Value, database, checked((uint)maxPages), (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens a database previously attached with <see cref="IJetApi.JetAttachDatabase"/>,
|
|
/// for use with a database session. This function can be called multiple times
|
|
/// for the same database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session that is opening the database.</param>
|
|
/// <param name="database">The database to open.</param>
|
|
/// <param name="connect">Reserved for future use.</param>
|
|
/// <param name="dbid">Returns the dbid of the attached database.</param>
|
|
/// <param name="grbit">Open database options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetOpenDatabase(JET_SESID sesid, string database, string connect, out JET_DBID dbid, OpenDatabaseGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOpenDatabase");
|
|
CheckNotNull(database, "database");
|
|
dbid = JET_DBID.Nil;
|
|
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetOpenDatabaseW(sesid.Value, database, connect, out dbid.Value, (uint)grbit));
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetOpenDatabase(sesid.Value, database, connect, out dbid.Value, (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes a database file that was previously opened with <see cref="IJetApi.JetOpenDatabase"/> or
|
|
/// created with <see cref="IJetApi.JetCreateDatabase"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to close.</param>
|
|
/// <param name="grbit">Close options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetCloseDatabase(JET_SESID sesid, JET_DBID dbid, CloseDatabaseGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetCloseDatabase");
|
|
return Err(NativeMethods.JetCloseDatabase(sesid.Value, dbid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Releases a database file that was previously attached to a database session.
|
|
/// </summary>
|
|
/// <param name="sesid">The database session to use.</param>
|
|
/// <param name="database">The database to detach.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetDetachDatabase(JET_SESID sesid, string database)
|
|
{
|
|
TraceFunctionCall("JetDetachDatabase");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetDetachDatabase2(sesid, database, DetachDatabaseGrbit.None);
|
|
#else
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetDetachDatabaseW(sesid.Value, database));
|
|
}
|
|
|
|
return Err(NativeMethods.JetDetachDatabase(sesid.Value, database));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Releases a database file that was previously attached to a database session.
|
|
/// </summary>
|
|
/// <param name="sesid">The database session to use.</param>
|
|
/// <param name="database">The database to detach.</param>
|
|
/// <param name="grbit">Detach options.</param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetDetachDatabase2(JET_SESID sesid, string database, DetachDatabaseGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetDetachDatabase2");
|
|
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
return Err(NativeMethods.JetDetachDatabase2W(sesid.Value, database, (uint)grbit));
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetDetachDatabase2(sesid.Value, database, (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Makes a copy of an existing database. The copy is compacted to a
|
|
/// state optimal for usage. Data in the copied data will be packed
|
|
/// according to the measures chosen for the indexes at index create.
|
|
/// In this way, compacted data may be stored as densely as possible.
|
|
/// Alternatively, compacted data may reserve space for subsequent
|
|
/// record growth or index insertions.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use for the call.</param>
|
|
/// <param name="sourceDatabase">The source database that will be compacted.</param>
|
|
/// <param name="destinationDatabase">The name to use for the compacted database.</param>
|
|
/// <param name="statusCallback">
|
|
/// A callback function that can be called periodically through the
|
|
/// database compact operation to report progress.
|
|
/// </param>
|
|
/// <param name="ignored">
|
|
/// This parameter is ignored and should be null.
|
|
/// </param>
|
|
/// <param name="grbit">Compact options.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetCompact(
|
|
JET_SESID sesid,
|
|
string sourceDatabase,
|
|
string destinationDatabase,
|
|
JET_PFNSTATUS statusCallback,
|
|
object ignored,
|
|
CompactGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetCompact");
|
|
CheckNotNull(sourceDatabase, "sourceDatabase");
|
|
CheckNotNull(destinationDatabase, "destinationDatabase");
|
|
if (null != ignored)
|
|
{
|
|
throw new ArgumentException("must be null", "ignored");
|
|
}
|
|
|
|
var callbackWrapper = new StatusCallbackWrapper(statusCallback);
|
|
IntPtr functionPointer = (null == statusCallback) ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(callbackWrapper.NativeCallback);
|
|
#if DEBUG
|
|
GC.Collect();
|
|
#endif
|
|
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetCompactW(
|
|
sesid.Value, sourceDatabase, destinationDatabase, functionPointer, IntPtr.Zero, (uint)grbit));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetCompact(
|
|
sesid.Value, sourceDatabase, destinationDatabase, functionPointer, IntPtr.Zero, (uint)grbit));
|
|
}
|
|
|
|
callbackWrapper.ThrowSavedException();
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extends the size of a database that is currently open.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to grow.</param>
|
|
/// <param name="desiredPages">The desired size of the database, in pages.</param>
|
|
/// <param name="actualPages">
|
|
/// The size of the database, in pages, after the call.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGrowDatabase(JET_SESID sesid, JET_DBID dbid, int desiredPages, out int actualPages)
|
|
{
|
|
TraceFunctionCall("JetGrowDatabase");
|
|
CheckNotNegative(desiredPages, "desiredPages");
|
|
|
|
uint actualPagesNative = 0;
|
|
int err = Err(NativeMethods.JetGrowDatabase(
|
|
sesid.Value, dbid.Value, checked((uint)desiredPages), out actualPagesNative));
|
|
actualPages = checked((int)actualPagesNative);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extends the size of a database that is currently open.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="database">The name of the database to grow.</param>
|
|
/// <param name="desiredPages">The desired size of the database, in pages.</param>
|
|
/// <param name="actualPages">
|
|
/// The size of the database, in pages, after the call.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetDatabaseSize(JET_SESID sesid, string database, int desiredPages, out int actualPages)
|
|
{
|
|
TraceFunctionCall("JetSetDatabaseSize");
|
|
CheckNotNegative(desiredPages, "desiredPages");
|
|
CheckNotNull(database, "database");
|
|
|
|
uint actualPagesNative = 0;
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetSetDatabaseSizeW(
|
|
sesid.Value, database, checked((uint)desiredPages), out actualPagesNative));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetSetDatabaseSize(
|
|
sesid.Value, database, checked((uint)desiredPages), out actualPagesNative));
|
|
}
|
|
|
|
actualPages = checked((int)actualPagesNative);
|
|
return err;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Retrieves certain information about the given database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database identifier.</param>
|
|
/// <param name="value">The value to be retrieved.</param>
|
|
/// <param name="infoLevel">The specific data to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetDatabaseInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
out int value,
|
|
JET_DbInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetDatabaseInfo");
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetGetDatabaseInfoW(sesid.Value, dbid.Value, out value, sizeof(int), (uint)infoLevel));
|
|
#else
|
|
return Err(NativeMethods.JetGetDatabaseInfo(sesid.Value, dbid.Value, out value, sizeof(int), (uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves certain information about the given database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database identifier.</param>
|
|
/// <param name="dbinfomisc">The value to be retrieved.</param>
|
|
/// <param name="infoLevel">The specific data to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetDatabaseInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
out JET_DBINFOMISC dbinfomisc,
|
|
JET_DbInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetDatabaseInfo");
|
|
int err = (int)JET_err.Success;
|
|
dbinfomisc = null;
|
|
|
|
bool notYetPublishedSupported = false;
|
|
this.NotYetPublishedGetDbinfomisc(sesid, dbid, ref dbinfomisc, infoLevel, ref notYetPublishedSupported, ref err);
|
|
|
|
if (notYetPublishedSupported)
|
|
{
|
|
// The not-yet-published function in the other file set the 'ref' parameters.
|
|
}
|
|
else if (this.Capabilities.SupportsWindows7Features)
|
|
{
|
|
NATIVE_DBINFOMISC4 native;
|
|
err = Err(NativeMethods.JetGetDatabaseInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
out native,
|
|
(uint)Marshal.SizeOf(typeof(NATIVE_DBINFOMISC4)),
|
|
(uint)infoLevel));
|
|
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
#if MANAGEDESENT_ON_WSA
|
|
else
|
|
{
|
|
var native = new NATIVE_DBINFOMISC4();
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
#else
|
|
else if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
NATIVE_DBINFOMISC native;
|
|
err = Err(NativeMethods.JetGetDatabaseInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
out native,
|
|
(uint)Marshal.SizeOf(typeof(NATIVE_DBINFOMISC)),
|
|
(uint)infoLevel));
|
|
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
else
|
|
{
|
|
NATIVE_DBINFOMISC native;
|
|
err = Err(NativeMethods.JetGetDatabaseInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
out native,
|
|
(uint)Marshal.SizeOf(typeof(NATIVE_DBINFOMISC)),
|
|
(uint)infoLevel));
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves certain information about the given database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database identifier.</param>
|
|
/// <param name="value">The value to be retrieved.</param>
|
|
/// <param name="infoLevel">The specific data to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetDatabaseInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
out string value,
|
|
JET_DbInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetDatabaseInfo");
|
|
int err;
|
|
|
|
const int MaxCharacters = 1024;
|
|
StringBuilder sb = new StringBuilder(MaxCharacters);
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetGetDatabaseInfoW(sesid.Value, dbid.Value, sb, MaxCharacters, (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetDatabaseInfo(sesid.Value, dbid.Value, sb, MaxCharacters, (uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
value = sb.ToString();
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves certain information about the given database.
|
|
/// </summary>
|
|
/// <param name="databaseName">The file name of the database.</param>
|
|
/// <param name="value">The value to be retrieved.</param>
|
|
/// <param name="infoLevel">The specific data to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetDatabaseFileInfo(
|
|
string databaseName,
|
|
out int value,
|
|
JET_DbInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetDatabaseFileInfo");
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfoW(databaseName, out value, sizeof(int), (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
value = 0;
|
|
#else
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfo(databaseName, out value, sizeof(int), (uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves certain information about the given database.
|
|
/// </summary>
|
|
/// <param name="databaseName">The file name of the database.</param>
|
|
/// <param name="value">The value to be retrieved.</param>
|
|
/// <param name="infoLevel">The specific data to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetDatabaseFileInfo(
|
|
string databaseName,
|
|
out long value,
|
|
JET_DbInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetDatabaseFileInfo");
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfoW(databaseName, out value, sizeof(long), (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
value = 0;
|
|
#else
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfo(databaseName, out value, sizeof(long), (uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves certain information about the given database.
|
|
/// </summary>
|
|
/// <param name="databaseName">The file name of the database.</param>
|
|
/// <param name="dbinfomisc">The value to be retrieved.</param>
|
|
/// <param name="infoLevel">The specific data to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetDatabaseFileInfo(
|
|
string databaseName,
|
|
out JET_DBINFOMISC dbinfomisc,
|
|
JET_DbInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetDatabaseFileInfo");
|
|
int err = (int)JET_err.Success;
|
|
dbinfomisc = null;
|
|
|
|
bool notYetPublishedSupported = false;
|
|
this.NotYetPublishedGetDbinfomisc(databaseName, ref dbinfomisc, infoLevel, ref notYetPublishedSupported, ref err);
|
|
|
|
if (notYetPublishedSupported)
|
|
{
|
|
// The not-yet-published function in the other file set the 'ref' parameters.
|
|
}
|
|
else if (this.Capabilities.SupportsWindows7Features)
|
|
{
|
|
// Windows7 -> Unicode path support
|
|
NATIVE_DBINFOMISC4 native;
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfoW(databaseName, out native, (uint)Marshal.SizeOf(typeof(NATIVE_DBINFOMISC4)), (uint)infoLevel));
|
|
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
#if MANAGEDESENT_ON_WSA
|
|
else
|
|
{
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
var native = new NATIVE_DBINFOMISC4();
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
#else
|
|
else
|
|
{
|
|
NATIVE_DBINFOMISC native;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfoW(databaseName, out native, (uint)Marshal.SizeOf(typeof(NATIVE_DBINFOMISC)), (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetGetDatabaseFileInfo(databaseName, out native, (uint)Marshal.SizeOf(typeof(NATIVE_DBINFOMISC)), (uint)infoLevel));
|
|
}
|
|
|
|
dbinfomisc = new JET_DBINFOMISC();
|
|
dbinfomisc.SetFromNativeDbinfoMisc(ref native);
|
|
}
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Backup/Restore
|
|
|
|
#if !MANAGEDESENT_ON_WSA
|
|
/// <summary>
|
|
/// Performs a streaming backup of an instance, including all the attached
|
|
/// databases, to a directory. With multiple backup methods supported by
|
|
/// the engine, this is the simplest and most encapsulated function.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to backup.</param>
|
|
/// <param name="destination">
|
|
/// The directory where the backup is to be stored. If the backup path is
|
|
/// null to use the function will truncate the logs, if possible.
|
|
/// </param>
|
|
/// <param name="grbit">Backup options.</param>
|
|
/// <param name="statusCallback">
|
|
/// Optional status notification callback.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetBackupInstance(
|
|
JET_INSTANCE instance, string destination, BackupGrbit grbit, JET_PFNSTATUS statusCallback)
|
|
{
|
|
TraceFunctionCall("JetBackupInstance");
|
|
|
|
var callbackWrapper = new StatusCallbackWrapper(statusCallback);
|
|
IntPtr functionPointer = (null == statusCallback) ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(callbackWrapper.NativeCallback);
|
|
#if DEBUG
|
|
GC.Collect();
|
|
#endif
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetBackupInstanceW(instance.Value, destination, (uint)grbit, functionPointer));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetBackupInstance(instance.Value, destination, (uint)grbit, functionPointer));
|
|
}
|
|
|
|
callbackWrapper.ThrowSavedException();
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restores and recovers a streaming backup of an instance including all
|
|
/// the attached databases. It is designed to work with a backup created
|
|
/// with the <see cref="Api.JetBackupInstance"/> function. This is the
|
|
/// simplest and most encapsulated restore function.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to use.</param>
|
|
/// <param name="source">
|
|
/// Location of the backup. The backup should have been created with
|
|
/// <see cref="Api.JetBackupInstance"/>.
|
|
/// </param>
|
|
/// <param name="destination">
|
|
/// Name of the folder where the database files from the backup set will
|
|
/// be copied and recovered. If this is set to null, the database files
|
|
/// will be copied and recovered to their original location.
|
|
/// </param>
|
|
/// <param name="statusCallback">
|
|
/// Optional status notification callback.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetRestoreInstance(JET_INSTANCE instance, string source, string destination, JET_PFNSTATUS statusCallback)
|
|
{
|
|
TraceFunctionCall("JetRestoreInstance");
|
|
CheckNotNull(source, "source");
|
|
|
|
var callbackWrapper = new StatusCallbackWrapper(statusCallback);
|
|
IntPtr functionPointer = (null == statusCallback) ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(callbackWrapper.NativeCallback);
|
|
#if DEBUG
|
|
GC.Collect();
|
|
#endif
|
|
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetRestoreInstanceW(instance.Value, source, destination, functionPointer));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetRestoreInstance(instance.Value, source, destination, functionPointer));
|
|
}
|
|
|
|
callbackWrapper.ThrowSavedException();
|
|
return err;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
#endregion
|
|
|
|
#region Snapshot Backup
|
|
|
|
#if !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Begins the preparations for a snapshot session. A snapshot session
|
|
/// is a short time interval in which the engine does not issue any
|
|
/// write IOs to disk, so that the engine can participate in a volume
|
|
/// snapshot session (when driven by a snapshot writer).
|
|
/// </summary>
|
|
/// <param name="snapid">Returns the ID of the snapshot session.</param>
|
|
/// <param name="grbit">Snapshot options.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotPrepare(out JET_OSSNAPID snapid, SnapshotPrepareGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotPrepare");
|
|
snapid = JET_OSSNAPID.Nil;
|
|
return Err(NativeMethods.JetOSSnapshotPrepare(out snapid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Selects a specific instance to be part of the snapshot session.
|
|
/// </summary>
|
|
/// <param name="snapshot">The snapshot identifier.</param>
|
|
/// <param name="instance">The instance to add to the snapshot.</param>
|
|
/// <param name="grbit">Options for this call.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotPrepareInstance(JET_OSSNAPID snapshot, JET_INSTANCE instance, SnapshotPrepareInstanceGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotPrepareInstance");
|
|
this.CheckSupportsVistaFeatures("JetOSSnapshotPrepareInstance");
|
|
return Err(NativeMethods.JetOSSnapshotPrepareInstance(snapshot.Value, instance.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts a snapshot. While the snapshot is in progress, no
|
|
/// write-to-disk activity by the engine can take place.
|
|
/// </summary>
|
|
/// <param name="snapshot">The snapshot session.</param>
|
|
/// <param name="numInstances">
|
|
/// Returns the number of instances that are part of the snapshot session.
|
|
/// </param>
|
|
/// <param name="instances">
|
|
/// Returns information about the instances that are part of the snapshot session.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Snapshot freeze options.
|
|
/// </param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotFreeze(JET_OSSNAPID snapshot, out int numInstances, out JET_INSTANCE_INFO[] instances, SnapshotFreezeGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotFreeze");
|
|
|
|
unsafe
|
|
{
|
|
uint nativeNumInstance = 0;
|
|
NATIVE_INSTANCE_INFO* nativeInstanceInfos = null;
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = NativeMethods.JetOSSnapshotFreezeW(snapshot.Value, out nativeNumInstance, out nativeInstanceInfos, (uint)grbit);
|
|
instances = this.ConvertInstanceInfosUnicode(nativeNumInstance, nativeInstanceInfos);
|
|
}
|
|
else
|
|
{
|
|
err = NativeMethods.JetOSSnapshotFreeze(snapshot.Value, out nativeNumInstance, out nativeInstanceInfos, (uint)grbit);
|
|
instances = this.ConvertInstanceInfosAscii(nativeNumInstance, nativeInstanceInfos);
|
|
}
|
|
|
|
numInstances = instances.Length;
|
|
|
|
return Err(err);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the list of instances and databases that are part of the
|
|
/// snapshot session at any given moment.
|
|
/// </summary>
|
|
/// <param name="snapshot">The identifier of the snapshot session.</param>
|
|
/// <param name="numInstances">Returns the number of instances.</param>
|
|
/// <param name="instances">Returns information about the instances.</param>
|
|
/// <param name="grbit">Options for this call.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotGetFreezeInfo(
|
|
JET_OSSNAPID snapshot,
|
|
out int numInstances,
|
|
out JET_INSTANCE_INFO[] instances,
|
|
SnapshotGetFreezeInfoGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotGetFreezeInfo");
|
|
this.CheckSupportsVistaFeatures("JetOSSnapshotGetFreezeInfo");
|
|
Debug.Assert(this.Capabilities.SupportsUnicodePaths, "JetOSSnapshotGetFreezeInfo is always Unicode");
|
|
|
|
unsafe
|
|
{
|
|
uint nativeNumInstance = 0;
|
|
NATIVE_INSTANCE_INFO* nativeInstanceInfos = null;
|
|
int err = NativeMethods.JetOSSnapshotGetFreezeInfoW(snapshot.Value, out nativeNumInstance, out nativeInstanceInfos, (uint)grbit);
|
|
instances = this.ConvertInstanceInfosUnicode(nativeNumInstance, nativeInstanceInfos);
|
|
numInstances = instances.Length;
|
|
|
|
return Err(err);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies the engine that it can resume normal IO operations after a
|
|
/// freeze period and a successful snapshot.
|
|
/// </summary>
|
|
/// <param name="snapid">The ID of the snapshot.</param>
|
|
/// <param name="grbit">Thaw options.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotThaw(JET_OSSNAPID snapid, SnapshotThawGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotThaw");
|
|
return Err(NativeMethods.JetOSSnapshotThaw(snapid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables log truncation for all instances that are part of the snapshot session.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This function should be called only if the snapshot was created with the
|
|
/// <see cref="VistaGrbits.ContinueAfterThaw"/> option. Otherwise, the snapshot
|
|
/// session ends after the call to <see cref="Api.JetOSSnapshotThaw"/>.
|
|
/// </remarks>
|
|
/// <param name="snapshot">The snapshot identifier.</param>
|
|
/// <param name="grbit">Options for this call.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotTruncateLog(JET_OSSNAPID snapshot, SnapshotTruncateLogGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotTruncateLog");
|
|
this.CheckSupportsVistaFeatures("JetOSSnapshotTruncateLog");
|
|
return Err(NativeMethods.JetOSSnapshotTruncateLog(snapshot.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Truncates the log for a specified instance during a snapshot session.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This function should be called only if the snapshot was created with the
|
|
/// <see cref="VistaGrbits.ContinueAfterThaw"/> option. Otherwise, the snapshot
|
|
/// session ends after the call to <see cref="Api.JetOSSnapshotThaw"/>.
|
|
/// </remarks>
|
|
/// <param name="snapshot">The snapshot identifier.</param>
|
|
/// <param name="instance">The instance to truncat the log for.</param>
|
|
/// <param name="grbit">Options for this call.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOSSnapshotTruncateLogInstance(JET_OSSNAPID snapshot, JET_INSTANCE instance, SnapshotTruncateLogGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotTruncateLogInstance");
|
|
this.CheckSupportsVistaFeatures("JetOSSnapshotTruncateLogInstance");
|
|
return Err(NativeMethods.JetOSSnapshotTruncateLogInstance(snapshot.Value, instance.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies the engine that the snapshot session finished.
|
|
/// </summary>
|
|
/// <param name="snapid">The identifier of the snapshot session.</param>
|
|
/// <param name="grbit">Snapshot end options.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetOSSnapshotEnd(JET_OSSNAPID snapid, SnapshotEndGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotEnd");
|
|
this.CheckSupportsVistaFeatures("JetOSSnapshotEnd");
|
|
return Err(NativeMethods.JetOSSnapshotEnd(snapid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies the engine that it can resume normal IO operations after a
|
|
/// freeze period ended with a failed snapshot.
|
|
/// </summary>
|
|
/// <param name="snapid">Identifier of the snapshot session.</param>
|
|
/// <param name="grbit">Options for this call.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetOSSnapshotAbort(JET_OSSNAPID snapid, SnapshotAbortGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetOSSnapshotAbort");
|
|
this.CheckSupportsServer2003Features("JetOSSnapshotAbort");
|
|
return Err(NativeMethods.JetOSSnapshotAbort(snapid.Value, (uint)grbit));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
#endregion
|
|
|
|
#region Streaming Backup/Restore
|
|
#if !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Initiates an external backup while the engine and database are online and active.
|
|
/// </summary>
|
|
/// <param name="instance">The instance prepare for backup.</param>
|
|
/// <param name="grbit">Backup options.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetBeginExternalBackupInstance(JET_INSTANCE instance, BeginExternalBackupGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetBeginExternalBackupInstance");
|
|
return Err(NativeMethods.JetBeginExternalBackupInstance(instance.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes a file that was opened with JetOpenFileInstance after the
|
|
/// data from that file has been extracted using JetReadFileInstance.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to use.</param>
|
|
/// <param name="handle">The handle to close.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetCloseFileInstance(JET_INSTANCE instance, JET_HANDLE handle)
|
|
{
|
|
TraceFunctionCall("JetCloseFileInstance");
|
|
return Err(NativeMethods.JetCloseFileInstance(instance.Value, handle.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ends an external backup session. This API is the last API in a series
|
|
/// of APIs that must be called to execute a successful online
|
|
/// (non-VSS based) backup.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to end the backup for.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetEndExternalBackupInstance(JET_INSTANCE instance)
|
|
{
|
|
TraceFunctionCall("JetEndExternalBackupInstance");
|
|
return Err(NativeMethods.JetEndExternalBackupInstance(instance.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ends an external backup session. This API is the last API in a series
|
|
/// of APIs that must be called to execute a successful online
|
|
/// (non-VSS based) backup.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to end the backup for.</param>
|
|
/// <param name="grbit">Options that specify how the backup ended.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetEndExternalBackupInstance2(JET_INSTANCE instance, EndExternalBackupGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetEndExternalBackupInstance2");
|
|
return Err(NativeMethods.JetEndExternalBackupInstance2(instance.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used during a backup initiated by <see cref="JetBeginExternalBackupInstance"/>
|
|
/// to query an instance for the names of database files that should become part of
|
|
/// the backup file set. Only databases that are currently attached to the instance
|
|
/// using <see cref="JetAttachDatabase"/> will be considered. These files may
|
|
/// subsequently be opened using <see cref="JetOpenFileInstance"/> and read
|
|
/// using <see cref="JetReadFileInstance"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// It is important to note that this API does not return an error or warning if
|
|
/// the output buffer is too small to accept the full list of files that should be
|
|
/// part of the backup file set.
|
|
/// </remarks>
|
|
/// <param name="instance">The instance to get the information for.</param>
|
|
/// <param name="files">
|
|
/// Returns a list of null terminated strings describing the set of database files
|
|
/// that should be a part of the backup file set. The list of strings returned in
|
|
/// this buffer is in the same format as a multi-string used by the registry. Each
|
|
/// null-terminated string is returned in sequence followed by a final null terminator.
|
|
/// </param>
|
|
/// <param name="maxChars">
|
|
/// Maximum number of characters to retrieve.
|
|
/// </param>
|
|
/// <param name="actualChars">
|
|
/// Actual size of the file list. If this is greater than maxChars
|
|
/// then the list has been truncated.
|
|
/// </param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetGetAttachInfoInstance(JET_INSTANCE instance, out string files, int maxChars, out int actualChars)
|
|
{
|
|
TraceFunctionCall("JetGetAttachInfoInstance");
|
|
CheckNotNegative(maxChars, "maxChars");
|
|
|
|
// These strings have embedded nulls so we can't use a StringBuilder.
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
uint bytesMax = checked((uint)maxChars) * sizeof(char);
|
|
byte[] szz = new byte[bytesMax];
|
|
uint bytesActual = 0;
|
|
err = Err(NativeMethods.JetGetAttachInfoInstanceW(instance.Value, szz, bytesMax, out bytesActual));
|
|
actualChars = checked((int)bytesActual) / sizeof(char);
|
|
files = Encoding.Unicode.GetString(szz, 0, Math.Min(szz.Length, (int)bytesActual));
|
|
}
|
|
else
|
|
{
|
|
uint bytesMax = checked((uint)maxChars);
|
|
byte[] szz = new byte[bytesMax];
|
|
uint bytesActual = 0;
|
|
err = Err(NativeMethods.JetGetAttachInfoInstance(instance.Value, szz, bytesMax, out bytesActual));
|
|
actualChars = checked((int)bytesActual);
|
|
files = LibraryHelpers.EncodingASCII.GetString(szz, 0, Math.Min(szz.Length, (int)bytesActual));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used during a backup initiated by <see cref="JetBeginExternalBackupInstance"/>
|
|
/// to query an instance for the names of database patch files and logfiles that
|
|
/// should become part of the backup file set. These files may subsequently be
|
|
/// opened using <see cref="JetOpenFileInstance"/> and read using <see cref="JetReadFileInstance"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// It is important to note that this API does not return an error or warning if
|
|
/// the output buffer is too small to accept the full list of files that should be
|
|
/// part of the backup file set.
|
|
/// </remarks>
|
|
/// <param name="instance">The instance to get the information for.</param>
|
|
/// <param name="files">
|
|
/// Returns a list of null terminated strings describing the set of database patch files
|
|
/// and log files that should be a part of the backup file set. The list of strings returned in
|
|
/// this buffer is in the same format as a multi-string used by the registry. Each
|
|
/// null-terminated string is returned in sequence followed by a final null terminator.
|
|
/// </param>
|
|
/// <param name="maxChars">
|
|
/// Maximum number of characters to retrieve.
|
|
/// </param>
|
|
/// <param name="actualChars">
|
|
/// Actual size of the file list. If this is greater than maxChars
|
|
/// then the list has been truncated.
|
|
/// </param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetGetLogInfoInstance(JET_INSTANCE instance, out string files, int maxChars, out int actualChars)
|
|
{
|
|
TraceFunctionCall("JetGetLogInfoInstance");
|
|
CheckNotNegative(maxChars, "maxChars");
|
|
|
|
// These strings have embedded nulls so we can't use a StringBuilder.
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
uint bytesMax = checked((uint)maxChars) * sizeof(char);
|
|
byte[] szz = new byte[bytesMax];
|
|
uint bytesActual = 0;
|
|
err = Err(NativeMethods.JetGetLogInfoInstanceW(instance.Value, szz, bytesMax, out bytesActual));
|
|
actualChars = checked((int)bytesActual) / sizeof(char);
|
|
files = Encoding.Unicode.GetString(szz, 0, Math.Min(szz.Length, (int)bytesActual));
|
|
}
|
|
else
|
|
{
|
|
uint bytesMax = checked((uint)maxChars);
|
|
byte[] szz = new byte[bytesMax];
|
|
uint bytesActual = 0;
|
|
err = Err(NativeMethods.JetGetLogInfoInstance(instance.Value, szz, bytesMax, out bytesActual));
|
|
actualChars = checked((int)bytesActual);
|
|
files = LibraryHelpers.EncodingASCII.GetString(szz, 0, Math.Min(szz.Length, (int)bytesActual));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used during a backup initiated by <see cref="JetBeginExternalBackupInstance"/>
|
|
/// to query an instance for the names of the transaction log files that can be safely
|
|
/// deleted after the backup has successfully completed.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// It is important to note that this API does not return an error or warning if
|
|
/// the output buffer is too small to accept the full list of files that should be
|
|
/// part of the backup file set.
|
|
/// </remarks>
|
|
/// <param name="instance">The instance to get the information for.</param>
|
|
/// <param name="files">
|
|
/// Returns a list of null terminated strings describing the set of database log files
|
|
/// that can be safely deleted after the backup completes. The list of strings returned in
|
|
/// this buffer is in the same format as a multi-string used by the registry. Each
|
|
/// null-terminated string is returned in sequence followed by a final null terminator.
|
|
/// </param>
|
|
/// <param name="maxChars">
|
|
/// Maximum number of characters to retrieve.
|
|
/// </param>
|
|
/// <param name="actualChars">
|
|
/// Actual size of the file list. If this is greater than maxChars
|
|
/// then the list has been truncated.
|
|
/// </param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetGetTruncateLogInfoInstance(JET_INSTANCE instance, out string files, int maxChars, out int actualChars)
|
|
{
|
|
TraceFunctionCall("JetGetTruncateLogInfoInstance");
|
|
CheckNotNegative(maxChars, "maxChars");
|
|
|
|
// These strings have embedded nulls so we can't use a StringBuilder.
|
|
int err;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
uint bytesMax = checked((uint)maxChars) * sizeof(char);
|
|
byte[] szz = new byte[bytesMax];
|
|
uint bytesActual = 0;
|
|
err = Err(NativeMethods.JetGetTruncateLogInfoInstanceW(instance.Value, szz, bytesMax, out bytesActual));
|
|
actualChars = checked((int)bytesActual) / sizeof(char);
|
|
files = Encoding.Unicode.GetString(szz, 0, Math.Min(szz.Length, (int)bytesActual));
|
|
}
|
|
else
|
|
{
|
|
uint bytesMax = checked((uint)maxChars);
|
|
byte[] szz = new byte[bytesMax];
|
|
uint bytesActual = 0;
|
|
err = Err(NativeMethods.JetGetTruncateLogInfoInstance(instance.Value, szz, bytesMax, out bytesActual));
|
|
actualChars = checked((int)bytesActual);
|
|
files = LibraryHelpers.EncodingASCII.GetString(szz, 0, Math.Min(szz.Length, (int)bytesActual));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens an attached database, database patch file, or transaction log
|
|
/// file of an active instance for the purpose of performing a streaming
|
|
/// fuzzy backup. The data from these files can subsequently be read
|
|
/// through the returned handle using JetReadFileInstance. The returned
|
|
/// handle must be closed using JetCloseFileInstance. An external backup
|
|
/// of the instance must have been previously initiated using
|
|
/// JetBeginExternalBackupInstance.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to use.</param>
|
|
/// <param name="file">The file to open.</param>
|
|
/// <param name="handle">Returns a handle to the file.</param>
|
|
/// <param name="fileSizeLow">Returns the least significant 32 bits of the file size.</param>
|
|
/// <param name="fileSizeHigh">Returns the most significant 32 bits of the file size.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetOpenFileInstance(JET_INSTANCE instance, string file, out JET_HANDLE handle, out long fileSizeLow, out long fileSizeHigh)
|
|
{
|
|
TraceFunctionCall("JetOpenFileInstance");
|
|
CheckNotNull(file, "file");
|
|
handle = JET_HANDLE.Nil;
|
|
int err;
|
|
uint nativeFileSizeLow;
|
|
uint nativeFileSizeHigh;
|
|
if (this.Capabilities.SupportsUnicodePaths)
|
|
{
|
|
err = Err(NativeMethods.JetOpenFileInstanceW(
|
|
instance.Value, file, out handle.Value, out nativeFileSizeLow, out nativeFileSizeHigh));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetOpenFileInstance(
|
|
instance.Value, file, out handle.Value, out nativeFileSizeLow, out nativeFileSizeHigh));
|
|
}
|
|
|
|
fileSizeLow = nativeFileSizeLow;
|
|
fileSizeHigh = nativeFileSizeHigh;
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the contents of a file opened with <see cref="Api.JetOpenFileInstance"/>.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to use.</param>
|
|
/// <param name="file">The file to read from.</param>
|
|
/// <param name="buffer">The buffer to read into.</param>
|
|
/// <param name="bufferSize">The size of the buffer.</param>
|
|
/// <param name="bytesRead">Returns the amount of data read into the buffer.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetReadFileInstance(JET_INSTANCE instance, JET_HANDLE file, byte[] buffer, int bufferSize, out int bytesRead)
|
|
{
|
|
TraceFunctionCall("JetReadFileInstance");
|
|
CheckNotNull(buffer, "buffer");
|
|
CheckDataSize(buffer, bufferSize, "bufferSize");
|
|
|
|
// ESENT requires that the buffer be aligned on a page allocation boundary.
|
|
// VirtualAlloc is the API used to do that, so we use P/Invoke to call it.
|
|
IntPtr alignedBuffer = Win32.NativeMethods.VirtualAlloc(
|
|
IntPtr.Zero,
|
|
(UIntPtr)bufferSize,
|
|
(uint)(Win32.AllocationType.MEM_COMMIT | Win32.AllocationType.MEM_RESERVE),
|
|
(uint)Win32.MemoryProtection.PAGE_READWRITE);
|
|
Win32.NativeMethods.ThrowExceptionOnNull(alignedBuffer, "VirtualAlloc");
|
|
|
|
try
|
|
{
|
|
uint nativeBytesRead = 0;
|
|
int err =
|
|
Err(
|
|
NativeMethods.JetReadFileInstance(
|
|
instance.Value, file.Value, alignedBuffer, checked((uint)bufferSize), out nativeBytesRead));
|
|
bytesRead = checked((int)nativeBytesRead);
|
|
|
|
// Copy the memory out of the aligned buffer into the user buffer.
|
|
Marshal.Copy(alignedBuffer, buffer, 0, bytesRead);
|
|
return err;
|
|
}
|
|
finally
|
|
{
|
|
bool freeSucceded = Win32.NativeMethods.VirtualFree(alignedBuffer, UIntPtr.Zero, (uint)Win32.FreeType.MEM_RELEASE);
|
|
Win32.NativeMethods.ThrowExceptionOnFailure(freeSucceded, "VirtualFree");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used during a backup initiated by JetBeginExternalBackup to delete
|
|
/// any transaction log files that will no longer be needed once the
|
|
/// current backup completes successfully.
|
|
/// </summary>
|
|
/// <param name="instance">The instance to truncate.</param>
|
|
/// <returns>An error code if the call fails.</returns>
|
|
public int JetTruncateLogInstance(JET_INSTANCE instance)
|
|
{
|
|
TraceFunctionCall("JetTruncateLogInstance");
|
|
return Err(NativeMethods.JetTruncateLogInstance(instance.Value));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
#endregion
|
|
|
|
#region Sessions
|
|
|
|
/// <summary>
|
|
/// Initialize a new ESENT session.
|
|
/// </summary>
|
|
/// <param name="instance">The initialized instance to create the session in.</param>
|
|
/// <param name="sesid">Returns the created session.</param>
|
|
/// <param name="username">The parameter is not used.</param>
|
|
/// <param name="password">The parameter is not used.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetBeginSession(JET_INSTANCE instance, out JET_SESID sesid, string username, string password)
|
|
{
|
|
TraceFunctionCall("JetBeginSession");
|
|
sesid = JET_SESID.Nil;
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetBeginSessionW(instance.Value, out sesid.Value, username, password));
|
|
#else
|
|
return Err(NativeMethods.JetBeginSession(instance.Value, out sesid.Value, username, password));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Associates a session with the current thread using the given context
|
|
/// handle. This association overrides the default engine requirement
|
|
/// that a transaction for a given session must occur entirely on the
|
|
/// same thread.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to set the context on.</param>
|
|
/// <param name="context">The context to set.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetSessionContext(JET_SESID sesid, IntPtr context)
|
|
{
|
|
TraceFunctionCall("JetSetSessionContext");
|
|
return Err(NativeMethods.JetSetSessionContext(sesid.Value, context));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disassociates a session from the current thread. This should be
|
|
/// used in conjunction with JetSetSessionContext.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetResetSessionContext(JET_SESID sesid)
|
|
{
|
|
TraceFunctionCall("JetResetSessionContext");
|
|
return Err(NativeMethods.JetResetSessionContext(sesid.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ends a session.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to end.</param>
|
|
/// <param name="grbit">This parameter is not used.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetEndSession(JET_SESID sesid, EndSessionGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetEndSession");
|
|
return Err(NativeMethods.JetEndSession(sesid.Value, (uint)grbit));
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Initialize a new ESE session in the same instance as the given sesid.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to duplicate.</param>
|
|
/// <param name="newSesid">Returns the new session.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDupSession(JET_SESID sesid, out JET_SESID newSesid)
|
|
{
|
|
TraceFunctionCall("JetDupSession");
|
|
newSesid = JET_SESID.Nil;
|
|
return Err(NativeMethods.JetDupSession(sesid.Value, out newSesid.Value));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Retrieves performance information from the database engine for the
|
|
/// current thread. Multiple calls can be used to collect statistics
|
|
/// that reflect the activity of the database engine on this thread
|
|
/// between those calls.
|
|
/// </summary>
|
|
/// <param name="threadstats">
|
|
/// Returns the thread statistics..
|
|
/// </param>
|
|
/// <returns>An error code if the operation fails.</returns>
|
|
public int JetGetThreadStats(out JET_THREADSTATS threadstats)
|
|
{
|
|
TraceFunctionCall("JetGetThreadStats");
|
|
this.CheckSupportsVistaFeatures("JetGetThreadStats");
|
|
|
|
// To speed up the interop we use unsafe code to avoid initializing
|
|
// the out parameter. We just call the interop code.
|
|
unsafe
|
|
{
|
|
fixed (JET_THREADSTATS* rawJetThreadstats = &threadstats)
|
|
{
|
|
return Err(NativeMethods.JetGetThreadStats(rawJetThreadstats, checked((uint)JET_THREADSTATS.Size)));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tables
|
|
|
|
/// <summary>
|
|
/// Opens a cursor on a previously created table.
|
|
/// </summary>
|
|
/// <param name="sesid">The database session to use.</param>
|
|
/// <param name="dbid">The database to open the table in.</param>
|
|
/// <param name="tablename">The name of the table to open.</param>
|
|
/// <param name="parameters">The parameter is not used.</param>
|
|
/// <param name="parametersLength">The parameter is not used.</param>
|
|
/// <param name="grbit">Table open options.</param>
|
|
/// <param name="tableid">Returns the opened table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetOpenTable(JET_SESID sesid, JET_DBID dbid, string tablename, byte[] parameters, int parametersLength, OpenTableGrbit grbit, out JET_TABLEID tableid)
|
|
{
|
|
TraceFunctionCall("JetOpenTable");
|
|
tableid = JET_TABLEID.Nil;
|
|
CheckNotNull(tablename, "tablename");
|
|
CheckDataSize(parameters, parametersLength, "parametersLength");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetOpenTableW(sesid.Value, dbid.Value, tablename, parameters, checked((uint)parametersLength), (uint)grbit, out tableid.Value));
|
|
#else
|
|
return Err(NativeMethods.JetOpenTable(sesid.Value, dbid.Value, tablename, parameters, checked((uint)parametersLength), (uint)grbit, out tableid.Value));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Close an open table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session which opened the table.</param>
|
|
/// <param name="tableid">The table to close.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCloseTable(JET_SESID sesid, JET_TABLEID tableid)
|
|
{
|
|
TraceFunctionCall("JetCloseTable");
|
|
return Err(NativeMethods.JetCloseTable(sesid.Value, tableid.Value));
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Duplicates an open cursor and returns a handle to the duplicated cursor.
|
|
/// If the cursor that was duplicated was a read-only cursor then the
|
|
/// duplicated cursor is also a read-only cursor.
|
|
/// Any state related to constructing a search key or updating a record is
|
|
/// not copied into the duplicated cursor. In addition, the location of the
|
|
/// original cursor is not duplicated into the duplicated cursor. The
|
|
/// duplicated cursor is always opened on the clustered index and its
|
|
/// location is always on the first row of the table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to duplicate.</param>
|
|
/// <param name="newTableid">The duplicated cursor.</param>
|
|
/// <param name="grbit">Reserved for future use.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDupCursor(JET_SESID sesid, JET_TABLEID tableid, out JET_TABLEID newTableid, DupCursorGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetDupCursor");
|
|
newTableid = JET_TABLEID.Nil;
|
|
return Err(NativeMethods.JetDupCursor(sesid.Value, tableid.Value, out newTableid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Walks each index of a table to exactly compute the number of entries
|
|
/// in an index, and the number of distinct keys in an index. This
|
|
/// information, together with the number of database pages allocated
|
|
/// for an index and the current time of the computation is stored in
|
|
/// index metadata in the database. This data can be subsequently retrieved
|
|
/// with information operations.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table that the statistics will be computed on.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetComputeStats(JET_SESID sesid, JET_TABLEID tableid)
|
|
{
|
|
TraceFunctionCall("JetComputeStats");
|
|
return Err(NativeMethods.JetComputeStats(sesid.Value, tableid.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables the application to associate a context handle known as
|
|
/// Local Storage with a cursor or the table associated with that
|
|
/// cursor. This context handle can be used by the application to
|
|
/// store auxiliary data that is associated with a cursor or table.
|
|
/// The application is later notified using a runtime callback when
|
|
/// the context handle must be released. This makes it possible to
|
|
/// associate dynamically allocated state with a cursor or table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to use.</param>
|
|
/// <param name="ls">The context handle to be associated with the session or cursor.</param>
|
|
/// <param name="grbit">Set options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetLS(JET_SESID sesid, JET_TABLEID tableid, JET_LS ls, LsGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetSetLS");
|
|
return Err(NativeMethods.JetSetLS(sesid.Value, tableid.Value, ls.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enables the application to retrieve the context handle known
|
|
/// as Local Storage that is associated with a cursor or the table
|
|
/// associated with that cursor. This context handle must have been
|
|
/// previously set using <see cref="JetSetLS"/>. JetGetLS can also
|
|
/// be used to simultaneously fetch the current context handle for
|
|
/// a cursor or table and reset that context handle.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to use.</param>
|
|
/// <param name="ls">Returns the retrieved context handle.</param>
|
|
/// <param name="grbit">Retrieve options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetLS(JET_SESID sesid, JET_TABLEID tableid, out JET_LS ls, LsGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetGetLS");
|
|
IntPtr native;
|
|
int err = NativeMethods.JetGetLS(sesid.Value, tableid.Value, out native, (uint)grbit);
|
|
ls = new JET_LS { Value = native };
|
|
return Err(err);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine whether an update of the current record of a cursor
|
|
/// will result in a write conflict, based on the current update
|
|
/// status of the record. It is possible that a write conflict will
|
|
/// ultimately be returned even if JetGetCursorInfo returns successfully.
|
|
/// because another session may update the record before the current
|
|
/// session is able to update the same record.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to check.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetCursorInfo(JET_SESID sesid, JET_TABLEID tableid)
|
|
{
|
|
TraceFunctionCall("JetGetCursorInfo");
|
|
return Err(NativeMethods.JetGetCursorInfo(sesid.Value, tableid.Value, IntPtr.Zero, 0, 0));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region Transactions
|
|
|
|
/// <summary>
|
|
/// Causes a session to enter a transaction or create a new save point in an existing
|
|
/// transaction.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to begin the transaction for.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetBeginTransaction(JET_SESID sesid)
|
|
{
|
|
TraceFunctionCall("JetBeginTransaction");
|
|
#if MANAGEDESENT_ON_WSA
|
|
// 19513 is an arbitrary number.
|
|
return this.JetBeginTransaction3(sesid, 19513, BeginTransactionGrbit.None);
|
|
#else
|
|
return Err(NativeMethods.JetBeginTransaction(sesid.Value));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Causes a session to enter a transaction or create a new save point in an existing
|
|
/// transaction.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to begin the transaction for.</param>
|
|
/// <param name="grbit">Transaction options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetBeginTransaction2(JET_SESID sesid, BeginTransactionGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetBeginTransaction2");
|
|
#if MANAGEDESENT_ON_WSA
|
|
// 33193 is an arbitrary number.
|
|
return this.JetBeginTransaction3(sesid, 33193, BeginTransactionGrbit.None);
|
|
#else
|
|
return Err(NativeMethods.JetBeginTransaction2(sesid.Value, unchecked((uint)grbit)));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Commits the changes made to the state of the database during the current save point
|
|
/// and migrates them to the previous save point. If the outermost save point is committed
|
|
/// then the changes made during that save point will be committed to the state of the
|
|
/// database and the session will exit the transaction.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to commit the transaction for.</param>
|
|
/// <param name="grbit">Commit options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCommitTransaction(JET_SESID sesid, CommitTransactionGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetCommitTransaction");
|
|
#if MANAGEDESENT_ON_WSA
|
|
JET_COMMIT_ID commitId;
|
|
return this.JetCommitTransaction2(sesid, grbit, TimeSpan.Zero, out commitId);
|
|
#else
|
|
return Err(NativeMethods.JetCommitTransaction(sesid.Value, unchecked((uint)grbit)));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Undoes the changes made to the state of the database
|
|
/// and returns to the last save point. JetRollback will also close any cursors
|
|
/// opened during the save point. If the outermost save point is undone, the
|
|
/// session will exit the transaction.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to rollback the transaction for.</param>
|
|
/// <param name="grbit">Rollback options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetRollback(JET_SESID sesid, RollbackTransactionGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetRollback");
|
|
return Err(NativeMethods.JetRollback(sesid.Value, unchecked((uint)grbit)));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DDL
|
|
|
|
/// <summary>
|
|
/// Create an empty table. The newly created table is opened exclusively.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to create the table in.</param>
|
|
/// <param name="table">The name of the table to create.</param>
|
|
/// <param name="pages">Initial number of pages in the table.</param>
|
|
/// <param name="density">
|
|
/// The default density of the table. This is used when doing sequential inserts.
|
|
/// </param>
|
|
/// <param name="tableid">Returns the tableid of the new table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCreateTable(JET_SESID sesid, JET_DBID dbid, string table, int pages, int density, out JET_TABLEID tableid)
|
|
{
|
|
TraceFunctionCall("JetCreateTable");
|
|
tableid = JET_TABLEID.Nil;
|
|
CheckNotNull(table, "table");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
var tablecreate = new JET_TABLECREATE
|
|
{
|
|
szTableName = table,
|
|
ulPages = pages,
|
|
ulDensity = density,
|
|
};
|
|
int err = this.JetCreateTableColumnIndex4(sesid, dbid, tablecreate);
|
|
tableid = tablecreate.tableid;
|
|
return err;
|
|
#else
|
|
return Err(NativeMethods.JetCreateTable(sesid.Value, dbid.Value, table, pages, density, out tableid.Value));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a table from a database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to delete the table from.</param>
|
|
/// <param name="table">The name of the table to delete.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDeleteTable(JET_SESID sesid, JET_DBID dbid, string table)
|
|
{
|
|
TraceFunctionCall("JetDeleteTable");
|
|
CheckNotNull(table, "table");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetDeleteTableW(sesid.Value, dbid.Value, table));
|
|
#else
|
|
return Err(NativeMethods.JetDeleteTable(sesid.Value, dbid.Value, table));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a new column to an existing table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to add the column to.</param>
|
|
/// <param name="column">The name of the column.</param>
|
|
/// <param name="columndef">The definition of the column.</param>
|
|
/// <param name="defaultValue">The default value of the column.</param>
|
|
/// <param name="defaultValueSize">The size of the default value.</param>
|
|
/// <param name="columnid">Returns the columnid of the new column.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetAddColumn(JET_SESID sesid, JET_TABLEID tableid, string column, JET_COLUMNDEF columndef, byte[] defaultValue, int defaultValueSize, out JET_COLUMNID columnid)
|
|
{
|
|
TraceFunctionCall("JetAddColumn");
|
|
columnid = JET_COLUMNID.Nil;
|
|
CheckNotNull(column, "column");
|
|
CheckNotNull(columndef, "columndef");
|
|
CheckDataSize(defaultValue, defaultValueSize, "defaultValueSize");
|
|
|
|
NATIVE_COLUMNDEF nativeColumndef = columndef.GetNativeColumndef();
|
|
#if MANAGEDESENT_ON_WSA
|
|
int err = Err(NativeMethods.JetAddColumnW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
column,
|
|
ref nativeColumndef,
|
|
defaultValue,
|
|
checked((uint)defaultValueSize),
|
|
out columnid.Value));
|
|
#else
|
|
int err = Err(NativeMethods.JetAddColumn(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
column,
|
|
ref nativeColumndef,
|
|
defaultValue,
|
|
checked((uint)defaultValueSize),
|
|
out columnid.Value));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
// esent doesn't actually set the columnid member of the passed in JET_COLUMNDEF, but we will do that here for
|
|
// completeness.
|
|
columndef.columnid = new JET_COLUMNID { Value = columnid.Value };
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a column from a database table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">A cursor on the table to delete the column from.</param>
|
|
/// <param name="column">The name of the column to be deleted.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDeleteColumn(JET_SESID sesid, JET_TABLEID tableid, string column)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetDeleteColumn2(sesid, tableid, column, DeleteColumnGrbit.None);
|
|
#else
|
|
TraceFunctionCall("JetDeleteColumn");
|
|
CheckNotNull(column, "column");
|
|
return Err(NativeMethods.JetDeleteColumn(sesid.Value, tableid.Value, column));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a column from a database table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">A cursor on the table to delete the column from.</param>
|
|
/// <param name="column">The name of the column to be deleted.</param>
|
|
/// <param name="grbit">Column deletion options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDeleteColumn2(JET_SESID sesid, JET_TABLEID tableid, string column, DeleteColumnGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetDeleteColumn2");
|
|
CheckNotNull(column, "column");
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetDeleteColumn2W(sesid.Value, tableid.Value, column, (uint)grbit));
|
|
#else
|
|
return Err(NativeMethods.JetDeleteColumn2(sesid.Value, tableid.Value, column, (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an index over data in an ESE database. An index can be used to locate
|
|
/// specific data quickly.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to create the index on.</param>
|
|
/// <param name="indexName">
|
|
/// Pointer to a null-terminated string that specifies the name of the index to create.
|
|
/// </param>
|
|
/// <param name="grbit">Index creation options.</param>
|
|
/// <param name="keyDescription">
|
|
/// Pointer to a double null-terminated string of null-delimited tokens.
|
|
/// </param>
|
|
/// <param name="keyDescriptionLength">
|
|
/// The length, in characters, of szKey including the two terminating nulls.
|
|
/// </param>
|
|
/// <param name="density">Initial B+ tree density.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCreateIndex(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string indexName,
|
|
CreateIndexGrbit grbit,
|
|
string keyDescription,
|
|
int keyDescriptionLength,
|
|
int density)
|
|
{
|
|
TraceFunctionCall("JetCreateIndex");
|
|
#if MANAGEDESENT_ON_WSA
|
|
// Up-convert to JetCreateIndex2().
|
|
JET_INDEXCREATE indexcreate = new JET_INDEXCREATE();
|
|
indexcreate.szIndexName = indexName;
|
|
indexcreate.grbit = grbit;
|
|
indexcreate.szKey = keyDescription;
|
|
indexcreate.cbKey = keyDescriptionLength;
|
|
indexcreate.ulDensity = density;
|
|
|
|
JET_INDEXCREATE[] indexcreates = new JET_INDEXCREATE[] { indexcreate };
|
|
|
|
return this.JetCreateIndex2(sesid, tableid, indexcreates, indexcreates.Length);
|
|
#else
|
|
CheckNotNull(indexName, "indexName");
|
|
CheckNotNegative(keyDescriptionLength, "keyDescriptionLength");
|
|
CheckNotNegative(density, "density");
|
|
if (keyDescriptionLength > checked(keyDescription.Length + 1))
|
|
{
|
|
throw new ArgumentOutOfRangeException(
|
|
"keyDescriptionLength", keyDescriptionLength, "cannot be greater than keyDescription.Length");
|
|
}
|
|
|
|
return Err(NativeMethods.JetCreateIndex(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexName,
|
|
(uint)grbit,
|
|
keyDescription,
|
|
checked((uint)keyDescriptionLength),
|
|
checked((uint)density)));
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates indexes over data in an ESE database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to create the index on.</param>
|
|
/// <param name="indexcreates">Array of objects describing the indexes to be created.</param>
|
|
/// <param name="numIndexCreates">Number of index description objects.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetCreateIndex2(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
JET_INDEXCREATE[] indexcreates,
|
|
int numIndexCreates)
|
|
{
|
|
TraceFunctionCall("JetCreateIndex2");
|
|
CheckNotNull(indexcreates, "indexcreates");
|
|
CheckNotNegative(numIndexCreates, "numIndexCreates");
|
|
if (numIndexCreates > indexcreates.Length)
|
|
{
|
|
throw new ArgumentOutOfRangeException(
|
|
"numIndexCreates", numIndexCreates, "numIndexCreates is larger than the number of indexes passed in");
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
// Note that it is actually a bit risky to up-convert to CreateIndexes3(), which is why we don't
|
|
// do it in the regular case.
|
|
// Creating the NATIVE_UNICODEINDEX2 structure requires a locale string (not an LCID). If
|
|
// JetCreateIndex2() is called, then the caller very likely used an LCID (or no locale at all).
|
|
// If no locale is specified then it's OK.
|
|
// But we can't convert an LCID to a locale name reliably on Core CLR platforms.
|
|
// To get our test code working, we have a small hard-coded list of LCID->locale names.
|
|
return CreateIndexes3(sesid, tableid, indexcreates, numIndexCreates);
|
|
#else
|
|
// NOTE: Don't call CreateIndexes3() on Win8. Unlike other APIs, CreateIndexes3() is
|
|
// not a superset. It requires locale names, and if the user called JetCreateIndex2(),
|
|
// the input will likely have LCIDs.
|
|
if (this.Capabilities.SupportsWindows7Features)
|
|
{
|
|
return CreateIndexes2(sesid, tableid, indexcreates, numIndexCreates);
|
|
}
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
return CreateIndexes1(sesid, tableid, indexcreates, numIndexCreates);
|
|
}
|
|
|
|
return CreateIndexes(sesid, tableid, indexcreates, numIndexCreates);
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes an index from a database table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">A cursor on the table to delete the index from.</param>
|
|
/// <param name="index">The name of the index to be deleted.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDeleteIndex(JET_SESID sesid, JET_TABLEID tableid, string index)
|
|
{
|
|
TraceFunctionCall("JetDeleteIndex");
|
|
CheckNotNull(index, "index");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetDeleteIndexW(sesid.Value, tableid.Value, index));
|
|
#else
|
|
return Err(NativeMethods.JetDeleteIndex(sesid.Value, tableid.Value, index));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a temporary table with a single index. A temporary table
|
|
/// stores and retrieves records just like an ordinary table created
|
|
/// using JetCreateTableColumnIndex. However, temporary tables are
|
|
/// much faster than ordinary tables due to their volatile nature.
|
|
/// They can also be used to very quickly sort and perform duplicate
|
|
/// removal on record sets when accessed in a purely sequential manner.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="columns">
|
|
/// Column definitions for the columns created in the temporary table.
|
|
/// </param>
|
|
/// <param name="numColumns">Number of column definitions.</param>
|
|
/// <param name="grbit">Table creation options.</param>
|
|
/// <param name="tableid">
|
|
/// Returns the tableid of the temporary table. Closing this tableid
|
|
/// frees the resources associated with the temporary table.
|
|
/// </param>
|
|
/// <param name="columnids">
|
|
/// The output buffer that receives the array of column IDs generated
|
|
/// during the creation of the temporary table. The column IDs in this
|
|
/// array will exactly correspond to the input array of column definitions.
|
|
/// As a result, the size of this buffer must correspond to the size of the input array.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetOpenTempTable(
|
|
JET_SESID sesid,
|
|
JET_COLUMNDEF[] columns,
|
|
int numColumns,
|
|
TempTableGrbit grbit,
|
|
out JET_TABLEID tableid,
|
|
JET_COLUMNID[] columnids)
|
|
{
|
|
TraceFunctionCall("JetOpenTempTable");
|
|
CheckNotNull(columns, "columnns");
|
|
CheckDataSize(columns, numColumns, "numColumns");
|
|
CheckNotNull(columnids, "columnids");
|
|
CheckDataSize(columnids, numColumns, "numColumns");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetOpenTempTable3(sesid, columns, numColumns, null, grbit, out tableid, columnids);
|
|
#else
|
|
tableid = JET_TABLEID.Nil;
|
|
|
|
NATIVE_COLUMNDEF[] nativecolumndefs = GetNativecolumndefs(columns, numColumns);
|
|
var nativecolumnids = new uint[numColumns];
|
|
|
|
int err = Err(NativeMethods.JetOpenTempTable(
|
|
sesid.Value, nativecolumndefs, checked((uint)numColumns), (uint)grbit, out tableid.Value, nativecolumnids));
|
|
|
|
SetColumnids(columns, columnids, nativecolumnids, numColumns);
|
|
|
|
return err;
|
|
#endif
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Creates a temporary table with a single index. A temporary table
|
|
/// stores and retrieves records just like an ordinary table created
|
|
/// using JetCreateTableColumnIndex. However, temporary tables are
|
|
/// much faster than ordinary tables due to their volatile nature.
|
|
/// They can also be used to very quickly sort and perform duplicate
|
|
/// removal on record sets when accessed in a purely sequential manner.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="columns">
|
|
/// Column definitions for the columns created in the temporary table.
|
|
/// </param>
|
|
/// <param name="numColumns">Number of column definitions.</param>
|
|
/// <param name="lcid">
|
|
/// The locale ID to use to compare any Unicode key column data in the temporary table.
|
|
/// Any locale may be used as long as the appropriate language pack has been installed
|
|
/// on the machine.
|
|
/// </param>
|
|
/// <param name="grbit">Table creation options.</param>
|
|
/// <param name="tableid">
|
|
/// Returns the tableid of the temporary table. Closing this tableid
|
|
/// frees the resources associated with the temporary table.
|
|
/// </param>
|
|
/// <param name="columnids">
|
|
/// The output buffer that receives the array of column IDs generated
|
|
/// during the creation of the temporary table. The column IDs in this
|
|
/// array will exactly correspond to the input array of column definitions.
|
|
/// As a result, the size of this buffer must correspond to the size of the input array.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetOpenTempTable2(
|
|
JET_SESID sesid,
|
|
JET_COLUMNDEF[] columns,
|
|
int numColumns,
|
|
int lcid,
|
|
TempTableGrbit grbit,
|
|
out JET_TABLEID tableid,
|
|
JET_COLUMNID[] columnids)
|
|
{
|
|
TraceFunctionCall("JetOpenTempTable2");
|
|
CheckNotNull(columns, "columnns");
|
|
CheckDataSize(columns, numColumns, "numColumns");
|
|
CheckNotNull(columnids, "columnids");
|
|
CheckDataSize(columnids, numColumns, "numColumns");
|
|
|
|
tableid = JET_TABLEID.Nil;
|
|
|
|
NATIVE_COLUMNDEF[] nativecolumndefs = GetNativecolumndefs(columns, numColumns);
|
|
var nativecolumnids = new uint[numColumns];
|
|
|
|
int err = Err(NativeMethods.JetOpenTempTable2(
|
|
sesid.Value, nativecolumndefs, checked((uint)numColumns), (uint)lcid, (uint)grbit, out tableid.Value, nativecolumnids));
|
|
|
|
SetColumnids(columns, columnids, nativecolumnids, numColumns);
|
|
|
|
return err;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Creates a temporary table with a single index. A temporary table
|
|
/// stores and retrieves records just like an ordinary table created
|
|
/// using JetCreateTableColumnIndex. However, temporary tables are
|
|
/// much faster than ordinary tables due to their volatile nature.
|
|
/// They can also be used to very quickly sort and perform duplicate
|
|
/// removal on record sets when accessed in a purely sequential manner.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="columns">
|
|
/// Column definitions for the columns created in the temporary table.
|
|
/// </param>
|
|
/// <param name="numColumns">Number of column definitions.</param>
|
|
/// <param name="unicodeindex">
|
|
/// The Locale ID and normalization flags that will be used to compare
|
|
/// any Unicode key column data in the temporary table. When this
|
|
/// is not present then the default options are used.
|
|
/// </param>
|
|
/// <param name="grbit">Table creation options.</param>
|
|
/// <param name="tableid">
|
|
/// Returns the tableid of the temporary table. Closing this tableid
|
|
/// frees the resources associated with the temporary table.
|
|
/// </param>
|
|
/// <param name="columnids">
|
|
/// The output buffer that receives the array of column IDs generated
|
|
/// during the creation of the temporary table. The column IDs in this
|
|
/// array will exactly correspond to the input array of column definitions.
|
|
/// As a result, the size of this buffer must correspond to the size of the input array.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetOpenTempTable3(
|
|
JET_SESID sesid,
|
|
JET_COLUMNDEF[] columns,
|
|
int numColumns,
|
|
JET_UNICODEINDEX unicodeindex,
|
|
TempTableGrbit grbit,
|
|
out JET_TABLEID tableid,
|
|
JET_COLUMNID[] columnids)
|
|
{
|
|
TraceFunctionCall("JetOpenTempTable3");
|
|
CheckNotNull(columns, "columnns");
|
|
CheckDataSize(columns, numColumns, "numColumns");
|
|
CheckNotNull(columnids, "columnids");
|
|
CheckDataSize(columnids, numColumns, "numColumns");
|
|
|
|
tableid = JET_TABLEID.Nil;
|
|
|
|
NATIVE_COLUMNDEF[] nativecolumndefs = GetNativecolumndefs(columns, numColumns);
|
|
var nativecolumnids = new uint[numColumns];
|
|
|
|
int err;
|
|
if (null != unicodeindex)
|
|
{
|
|
NATIVE_UNICODEINDEX nativeunicodeindex = unicodeindex.GetNativeUnicodeIndex();
|
|
err = Err(NativeMethods.JetOpenTempTable3(
|
|
sesid.Value, nativecolumndefs, checked((uint)numColumns), ref nativeunicodeindex, (uint)grbit, out tableid.Value, nativecolumnids));
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetOpenTempTable3(
|
|
sesid.Value, nativecolumndefs, checked((uint)numColumns), IntPtr.Zero, (uint)grbit, out tableid.Value, nativecolumnids));
|
|
}
|
|
|
|
SetColumnids(columns, columnids, nativecolumnids, numColumns);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a temporary table with a single index. A temporary table
|
|
/// stores and retrieves records just like an ordinary table created
|
|
/// using JetCreateTableColumnIndex. However, temporary tables are
|
|
/// much faster than ordinary tables due to their volatile nature.
|
|
/// They can also be used to very quickly sort and perform duplicate
|
|
/// removal on record sets when accessed in a purely sequential manner.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Introduced in Windows Vista.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="temporarytable">
|
|
/// Description of the temporary table to create on input. After a
|
|
/// successful call, the structure contains the handle to the temporary
|
|
/// table and column identifications.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetOpenTemporaryTable(JET_SESID sesid, JET_OPENTEMPORARYTABLE temporarytable)
|
|
{
|
|
TraceFunctionCall("JetOpenTemporaryTable");
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetOpenTemporaryTable2(sesid, temporarytable);
|
|
#else
|
|
this.CheckSupportsVistaFeatures("JetOpenTemporaryTable");
|
|
CheckNotNull(temporarytable, "temporarytable");
|
|
|
|
NATIVE_OPENTEMPORARYTABLE nativetemporarytable = temporarytable.GetNativeOpenTemporaryTable();
|
|
var nativecolumnids = new uint[nativetemporarytable.ccolumn];
|
|
NATIVE_COLUMNDEF[] nativecolumndefs = GetNativecolumndefs(temporarytable.prgcolumndef, temporarytable.ccolumn);
|
|
unsafe
|
|
{
|
|
using (var gchandlecollection = new GCHandleCollection())
|
|
{
|
|
// Pin memory
|
|
nativetemporarytable.prgcolumndef = (NATIVE_COLUMNDEF*)gchandlecollection.Add(nativecolumndefs);
|
|
nativetemporarytable.rgcolumnid = (uint*)gchandlecollection.Add(nativecolumnids);
|
|
if (null != temporarytable.pidxunicode)
|
|
{
|
|
nativetemporarytable.pidxunicode = (NATIVE_UNICODEINDEX*)
|
|
gchandlecollection.Add(temporarytable.pidxunicode.GetNativeUnicodeIndex());
|
|
}
|
|
|
|
// Call the interop method
|
|
int err = Err(NativeMethods.JetOpenTemporaryTable(sesid.Value, ref nativetemporarytable));
|
|
|
|
// Convert the return values
|
|
SetColumnids(temporarytable.prgcolumndef, temporarytable.prgcolumnid, nativecolumnids, temporarytable.ccolumn);
|
|
temporarytable.tableid = new JET_TABLEID { Value = nativetemporarytable.tableid };
|
|
|
|
return err;
|
|
}
|
|
}
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a table, adds columns, and indices on that table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to which to add the new table.</param>
|
|
/// <param name="tablecreate">Object describing the table to create.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetCreateTableColumnIndex3(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
JET_TABLECREATE tablecreate)
|
|
{
|
|
TraceFunctionCall("JetCreateTableColumnIndex3");
|
|
CheckNotNull(tablecreate, "tablecreate");
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
return CreateTableColumnIndex4(sesid, dbid, tablecreate);
|
|
#else
|
|
if (this.Capabilities.SupportsWindows7Features)
|
|
{
|
|
return CreateTableColumnIndex3(sesid, dbid, tablecreate);
|
|
}
|
|
|
|
return this.CreateTableColumnIndex2(sesid, dbid, tablecreate);
|
|
#endif
|
|
}
|
|
|
|
#region JetGetTableColumnInfo overloads
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a table column.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table containing the column.</param>
|
|
/// <param name="columnName">The name of the column.</param>
|
|
/// <param name="columndef">Filled in with information about the column.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string columnName,
|
|
out JET_COLUMNDEF columndef)
|
|
{
|
|
TraceFunctionCall("JetGetTableColumnInfo");
|
|
columndef = new JET_COLUMNDEF();
|
|
CheckNotNull(columnName, "columnName");
|
|
|
|
var nativeColumndef = new NATIVE_COLUMNDEF();
|
|
nativeColumndef.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNDEF)));
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableColumnInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnName,
|
|
ref nativeColumndef,
|
|
nativeColumndef.cbStruct,
|
|
(uint)JET_ColInfo.Default));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableColumnInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnName,
|
|
ref nativeColumndef,
|
|
nativeColumndef.cbStruct,
|
|
(uint)JET_ColInfo.Default));
|
|
#endif
|
|
}
|
|
|
|
columndef.SetFromNativeColumndef(nativeColumndef);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a table column.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table containing the column.</param>
|
|
/// <param name="columnid">The columnid of the column.</param>
|
|
/// <param name="columndef">Filled in with information about the column.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
JET_COLUMNID columnid,
|
|
out JET_COLUMNDEF columndef)
|
|
{
|
|
TraceFunctionCall("JetGetTableColumnInfo");
|
|
columndef = new JET_COLUMNDEF();
|
|
int err;
|
|
|
|
var nativeColumndef = new NATIVE_COLUMNDEF();
|
|
nativeColumndef.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNDEF)));
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableColumnInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
ref columnid.Value,
|
|
ref nativeColumndef,
|
|
nativeColumndef.cbStruct,
|
|
(uint)JET_ColInfo.ByColid));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableColumnInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
ref columnid.Value,
|
|
ref nativeColumndef,
|
|
nativeColumndef.cbStruct,
|
|
(uint)JET_ColInfo.ByColid));
|
|
#endif
|
|
}
|
|
|
|
columndef.SetFromNativeColumndef(nativeColumndef);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a table column, given its <see cref="JET_TABLEID"/> and name.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table containing the column.</param>
|
|
/// <param name="columnName">The name of the column.</param>
|
|
/// <param name="columnbase">Filled in with information about the column.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string columnName,
|
|
out JET_COLUMNBASE columnbase)
|
|
{
|
|
TraceFunctionCall("JetGetTableColumnInfo");
|
|
CheckNotNull(columnName, "columnName");
|
|
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE_WIDE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE_WIDE)));
|
|
|
|
err = Err(NativeMethods.JetGetTableColumnInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnName,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)JET_ColInfo.Base));
|
|
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
columnbase = null;
|
|
#else
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE)));
|
|
|
|
err = Err(NativeMethods.JetGetTableColumnInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnName,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)JET_ColInfo.Base));
|
|
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a table column, given its <see cref="JET_TABLEID"/> and <see cref="JET_COLUMNID"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table containing the column.</param>
|
|
/// <param name="columnid">The columnid of the column.</param>
|
|
/// <param name="columnbase">Filled in with information about the column.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
JET_COLUMNID columnid,
|
|
out JET_COLUMNBASE columnbase)
|
|
{
|
|
TraceFunctionCall("JetGetTableColumnInfo");
|
|
this.CheckSupportsVistaFeatures("JetGetTableColumnInfo");
|
|
int err;
|
|
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE_WIDE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE_WIDE)));
|
|
|
|
err = Err(NativeMethods.JetGetTableColumnInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
ref columnid.Value,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)VistaColInfo.BaseByColid));
|
|
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about all columns in the table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table containing the column.</param>
|
|
/// <param name="ignored">The parameter is ignored.</param>
|
|
/// <param name="grbit">Additional options for JetGetTableColumnInfo.</param>
|
|
/// <param name="columnlist">Filled in with information about the columns in the table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string ignored,
|
|
ColInfoGrbit grbit,
|
|
out JET_COLUMNLIST columnlist)
|
|
{
|
|
TraceFunctionCall("JetGetTableColumnInfo");
|
|
columnlist = new JET_COLUMNLIST();
|
|
int err;
|
|
|
|
var nativeColumnlist = new NATIVE_COLUMNLIST();
|
|
nativeColumnlist.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNLIST)));
|
|
|
|
// Technically, this should have worked in Vista. But there was a bug, and
|
|
// it was fixed after Windows 7.
|
|
if (this.Capabilities.SupportsWindows8Features)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableColumnInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
ignored,
|
|
ref nativeColumnlist,
|
|
nativeColumnlist.cbStruct,
|
|
(uint)grbit | (uint)JET_ColInfo.List));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableColumnInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
ignored,
|
|
ref nativeColumnlist,
|
|
nativeColumnlist.cbStruct,
|
|
(uint)grbit | (uint)JET_ColInfo.List));
|
|
#endif
|
|
}
|
|
|
|
columnlist.SetFromNativeColumnlist(nativeColumnlist);
|
|
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JetGetColumnInfo overloads
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a table column.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database that contains the table.</param>
|
|
/// <param name="tablename">The name of the table containing the column.</param>
|
|
/// <param name="columnName">The name of the column.</param>
|
|
/// <param name="columndef">Filled in with information about the column.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string columnName,
|
|
out JET_COLUMNDEF columndef)
|
|
{
|
|
TraceFunctionCall("JetGetColumnInfo");
|
|
columndef = new JET_COLUMNDEF();
|
|
CheckNotNull(tablename, "tablename");
|
|
CheckNotNull(columnName, "columnName");
|
|
int err;
|
|
|
|
var nativeColumndef = new NATIVE_COLUMNDEF();
|
|
nativeColumndef.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNDEF)));
|
|
|
|
// Technically, this should have worked in Vista. But there was a bug, and
|
|
// it was fixed after Windows 7.
|
|
if (this.Capabilities.SupportsWindows8Features)
|
|
{
|
|
err = Err(NativeMethods.JetGetColumnInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
columnName,
|
|
ref nativeColumndef,
|
|
nativeColumndef.cbStruct,
|
|
(uint)JET_ColInfo.Default));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetColumnInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
columnName,
|
|
ref nativeColumndef,
|
|
nativeColumndef.cbStruct,
|
|
(uint)JET_ColInfo.Default));
|
|
#endif
|
|
}
|
|
|
|
columndef.SetFromNativeColumndef(nativeColumndef);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about all columns in a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database that contains the table.</param>
|
|
/// <param name="tablename">The name of the table containing the column.</param>
|
|
/// <param name="ignored">This parameter is ignored.</param>
|
|
/// <param name="columnlist">Filled in with information about the columns in the table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string ignored,
|
|
out JET_COLUMNLIST columnlist)
|
|
{
|
|
TraceFunctionCall("JetGetColumnInfo");
|
|
columnlist = new JET_COLUMNLIST();
|
|
CheckNotNull(tablename, "tablename");
|
|
int err;
|
|
|
|
var nativeColumnlist = new NATIVE_COLUMNLIST();
|
|
nativeColumnlist.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNLIST)));
|
|
|
|
// Technically, this should have worked in Vista. But there was a bug, and
|
|
// it was fixed after Windows 7.
|
|
if (this.Capabilities.SupportsWindows8Features)
|
|
{
|
|
err = Err(NativeMethods.JetGetColumnInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
ignored,
|
|
ref nativeColumnlist,
|
|
nativeColumnlist.cbStruct,
|
|
(uint)JET_ColInfo.List));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetColumnInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
ignored,
|
|
ref nativeColumnlist,
|
|
nativeColumnlist.cbStruct,
|
|
(uint)JET_ColInfo.List));
|
|
#endif
|
|
}
|
|
|
|
columnlist.SetFromNativeColumnlist(nativeColumnlist);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a column in a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database that contains the table.</param>
|
|
/// <param name="tablename">The name of the table containing the column.</param>
|
|
/// <param name="columnName">The name of the column.</param>
|
|
/// <param name="columnbase">Filled in with information about the columns in the table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string columnName,
|
|
out JET_COLUMNBASE columnbase)
|
|
{
|
|
TraceFunctionCall("JetGetColumnInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
CheckNotNull(columnName, "columnName");
|
|
int err;
|
|
|
|
// Technically, this should have worked in Vista. But there was a bug, and
|
|
// it was fixed after Windows 7.
|
|
if (this.Capabilities.SupportsWindows8Features)
|
|
{
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE_WIDE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE_WIDE)));
|
|
|
|
err = Err(NativeMethods.JetGetColumnInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
columnName,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)JET_ColInfo.Base));
|
|
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
}
|
|
else
|
|
{
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE)));
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetColumnInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
columnName,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)JET_ColInfo.Base));
|
|
#endif
|
|
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about a column.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database that contains the table.</param>
|
|
/// <param name="tablename">The name of the table containing the column.</param>
|
|
/// <param name="columnid">The columnid of the column.</param>
|
|
/// <param name="columnbase">Filled in with information about the columns in the table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetColumnInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
JET_COLUMNID columnid,
|
|
out JET_COLUMNBASE columnbase)
|
|
{
|
|
TraceFunctionCall("JetGetColumnInfo");
|
|
this.CheckSupportsVistaFeatures("JetGetColumnInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
int err;
|
|
|
|
// Technically, this should have worked in Vista. But there was a bug, and
|
|
// it was fixed after Windows 7.
|
|
if (this.Capabilities.SupportsWindows8Features)
|
|
{
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE_WIDE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE_WIDE)));
|
|
|
|
err = Err(NativeMethods.JetGetColumnInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
ref columnid.Value,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)VistaColInfo.BaseByColid));
|
|
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
}
|
|
else
|
|
{
|
|
var nativeColumnbase = new NATIVE_COLUMNBASE();
|
|
nativeColumnbase.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_COLUMNBASE)));
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetColumnInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
ref columnid.Value,
|
|
ref nativeColumnbase,
|
|
nativeColumnbase.cbStruct,
|
|
(uint)VistaColInfo.BaseByColid));
|
|
|
|
#endif
|
|
columnbase = new JET_COLUMNBASE(nativeColumnbase);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JetGetObjectInfo overloads
|
|
|
|
/// <summary>
|
|
/// Retrieves information about database objects.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="objectlist">Filled in with information about the objects in the database.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetObjectInfo(JET_SESID sesid, JET_DBID dbid, out JET_OBJECTLIST objectlist)
|
|
{
|
|
TraceFunctionCall("JetGetObjectInfo");
|
|
objectlist = new JET_OBJECTLIST();
|
|
|
|
var nativeObjectlist = new NATIVE_OBJECTLIST();
|
|
nativeObjectlist.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_OBJECTLIST)));
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetObjectInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
(uint)JET_objtyp.Table,
|
|
null,
|
|
null,
|
|
ref nativeObjectlist,
|
|
nativeObjectlist.cbStruct,
|
|
(uint)JET_ObjInfo.ListNoStats));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetObjectInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
(uint)JET_objtyp.Table,
|
|
null,
|
|
null,
|
|
ref nativeObjectlist,
|
|
nativeObjectlist.cbStruct,
|
|
(uint)JET_ObjInfo.ListNoStats));
|
|
#endif
|
|
}
|
|
|
|
objectlist.SetFromNativeObjectlist(nativeObjectlist);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about database objects.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="objtyp">The type of the object.</param>
|
|
/// <param name="objectName">The object name about which to retrieve information.</param>
|
|
/// <param name="objectinfo">Filled in with information about the objects in the database.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetObjectInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
JET_objtyp objtyp,
|
|
string objectName,
|
|
out JET_OBJECTINFO objectinfo)
|
|
{
|
|
TraceFunctionCall("JetGetObjectInfo");
|
|
objectinfo = new JET_OBJECTINFO();
|
|
|
|
var nativeObjectinfo = new NATIVE_OBJECTINFO();
|
|
nativeObjectinfo.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_OBJECTINFO)));
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetObjectInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
(uint)objtyp,
|
|
null,
|
|
objectName,
|
|
ref nativeObjectinfo,
|
|
nativeObjectinfo.cbStruct,
|
|
(uint)JET_ObjInfo.NoStats));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetObjectInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
(uint)objtyp,
|
|
null,
|
|
objectName,
|
|
ref nativeObjectinfo,
|
|
nativeObjectinfo.cbStruct,
|
|
(uint)JET_ObjInfo.NoStats));
|
|
#endif
|
|
}
|
|
|
|
objectinfo.SetFromNativeObjectinfo(ref nativeObjectinfo);
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// JetGetCurrentIndex function determines the name of the current
|
|
/// index of a given cursor. This name is also used to later re-select
|
|
/// that index as the current index using <see cref="JetSetCurrentIndex"/>. It can
|
|
/// also be used to discover the properties of that index using
|
|
/// JetGetTableIndexInfo.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to get the index name for.</param>
|
|
/// <param name="indexName">Returns the name of the index.</param>
|
|
/// <param name="maxNameLength">
|
|
/// The maximum length of the index name. Index names are no more than
|
|
/// Api.MaxNameLength characters.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetCurrentIndex(JET_SESID sesid, JET_TABLEID tableid, out string indexName, int maxNameLength)
|
|
{
|
|
TraceFunctionCall("JetGetCurrentIndex");
|
|
CheckNotNegative(maxNameLength, "maxNameLength");
|
|
|
|
var name = new StringBuilder(maxNameLength);
|
|
#if MANAGEDESENT_ON_WSA
|
|
int err = Err(NativeMethods.JetGetCurrentIndexW(sesid.Value, tableid.Value, name, checked((uint)maxNameLength)));
|
|
#else
|
|
int err = Err(NativeMethods.JetGetCurrentIndex(sesid.Value, tableid.Value, name, checked((uint)maxNameLength)));
|
|
#endif
|
|
indexName = name.ToString();
|
|
indexName = StringCache.TryToIntern(indexName);
|
|
return err;
|
|
}
|
|
|
|
#region JetGetTableInfo overloads
|
|
|
|
/// <summary>
|
|
/// Retrieves various pieces of information about a table in a database.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This overload is used with <see cref="JET_TblInfo.Default"/>.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve information about.</param>
|
|
/// <param name="result">Retrieved information.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out JET_OBJECTINFO result, JET_TblInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableInfo");
|
|
var nativeResult = new NATIVE_OBJECTINFO();
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(
|
|
NativeMethods.JetGetTableInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
out nativeResult,
|
|
checked((uint)Marshal.SizeOf(typeof(NATIVE_OBJECTINFO))),
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(
|
|
NativeMethods.JetGetTableInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
out nativeResult,
|
|
checked((uint)Marshal.SizeOf(typeof(NATIVE_OBJECTINFO))),
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = new JET_OBJECTINFO();
|
|
result.SetFromNativeObjectinfo(ref nativeResult);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves various pieces of information about a table in a database.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This overload is used with <see cref="JET_TblInfo.Name"/> and
|
|
/// <see cref="JET_TblInfo.TemplateTableName"/>.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve information about.</param>
|
|
/// <param name="result">Retrieved information.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out string result, JET_TblInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableInfo");
|
|
var resultBuffer = new StringBuilder(SystemParameters.NameMost + 1);
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableInfoW(
|
|
sesid.Value, tableid.Value, resultBuffer, (uint)resultBuffer.Capacity * sizeof(char), (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableInfo(
|
|
sesid.Value, tableid.Value, resultBuffer, (uint)resultBuffer.Capacity, (uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = resultBuffer.ToString();
|
|
result = StringCache.TryToIntern(result);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves various pieces of information about a table in a database.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This overload is used with <see cref="JET_TblInfo.Dbid"/>.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve information about.</param>
|
|
/// <param name="result">Retrieved information.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out JET_DBID result, JET_TblInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableInfo");
|
|
result = JET_DBID.Nil;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
return Err(NativeMethods.JetGetTableInfoW(sesid.Value, tableid.Value, out result.Value, sizeof(uint), (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetGetTableInfo(sesid.Value, tableid.Value, out result.Value, sizeof(uint), (uint)infoLevel));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves various pieces of information about a table in a database.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This overload is used with <see cref="JET_TblInfo.SpaceUsage"/> and
|
|
/// <see cref="JET_TblInfo.SpaceAlloc"/>.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve information about.</param>
|
|
/// <param name="result">Retrieved information.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, int[] result, JET_TblInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableInfo");
|
|
CheckNotNull(result, "result");
|
|
|
|
uint bytesResult = checked((uint)(result.Length * sizeof(int)));
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
return Err(NativeMethods.JetGetTableInfoW(sesid.Value, tableid.Value, result, bytesResult, (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
return Err(NativeMethods.JetGetTableInfo(sesid.Value, tableid.Value, result, bytesResult, (uint)infoLevel));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves various pieces of information about a table in a database.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This overload is used with <see cref="JET_TblInfo.SpaceOwned"/> and
|
|
/// <see cref="JET_TblInfo.SpaceAvailable"/>.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve information about.</param>
|
|
/// <param name="result">Retrieved information.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out int result, JET_TblInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableInfo");
|
|
uint nativeResult;
|
|
int err;
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableInfoW(sesid.Value, tableid.Value, out nativeResult, sizeof(uint), (uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
nativeResult = 0;
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableInfo(sesid.Value, tableid.Value, out nativeResult, sizeof(uint), (uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = unchecked((int)nativeResult);
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JetGetIndexInfo overloads
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="tablename">The name of the table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index to retrieve information about.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string indexname,
|
|
out ushort result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetIndexInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetIndexInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
out result,
|
|
sizeof(ushort),
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
result = 0;
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetIndexInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
out result,
|
|
sizeof(ushort),
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="tablename">The name of the table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index to retrieve information about.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string indexname,
|
|
out int result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetIndexInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
|
|
uint nativeResult;
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetIndexInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
out nativeResult,
|
|
sizeof(uint),
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
nativeResult = 0;
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetIndexInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
out nativeResult,
|
|
sizeof(uint),
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = unchecked((int)nativeResult);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="tablename">The name of the table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index to retrieve information about.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string indexname,
|
|
out JET_INDEXID result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetIndexInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetIndexInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
out result,
|
|
JET_INDEXID.SizeOfIndexId,
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
result = new JET_INDEXID();
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetIndexInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
out result,
|
|
JET_INDEXID.SizeOfIndexId,
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="tablename">The name of the table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index to retrieve information about.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string indexname,
|
|
out JET_INDEXLIST result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetIndexInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
int err;
|
|
|
|
var nativeIndexlist = new NATIVE_INDEXLIST();
|
|
nativeIndexlist.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXLIST)));
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetIndexInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
ref nativeIndexlist,
|
|
nativeIndexlist.cbStruct,
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetIndexInfo(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
ref nativeIndexlist,
|
|
nativeIndexlist.cbStruct,
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = new JET_INDEXLIST();
|
|
result.SetFromNativeIndexlist(nativeIndexlist);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to use.</param>
|
|
/// <param name="tablename">The name of the table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index to retrieve information about.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tablename,
|
|
string indexname,
|
|
out string result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetIndexInfo");
|
|
CheckNotNull(tablename, "tablename");
|
|
int err;
|
|
|
|
// Will need to check for Windows 8 Features.
|
|
//
|
|
// Currently only JET_IdxInfo.LocaleName is supported.
|
|
uint bytesMax = checked((uint)SystemParameters.LocaleNameMaxLength * sizeof(char));
|
|
|
|
var stringBuilder = new StringBuilder(SystemParameters.LocaleNameMaxLength);
|
|
err = Err(NativeMethods.JetGetIndexInfoW(
|
|
sesid.Value,
|
|
dbid.Value,
|
|
tablename,
|
|
indexname,
|
|
stringBuilder,
|
|
bytesMax,
|
|
(uint)infoLevel));
|
|
|
|
result = stringBuilder.ToString();
|
|
result = StringCache.TryToIntern(result);
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JetGetTableIndexInfo overloads
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string indexname,
|
|
out ushort result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableIndexInfo");
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableIndexInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
out result,
|
|
sizeof(ushort),
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
result = 0;
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableIndexInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
out result,
|
|
sizeof(ushort),
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string indexname,
|
|
out int result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableIndexInfo");
|
|
|
|
uint nativeResult;
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableIndexInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
out nativeResult,
|
|
sizeof(uint),
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
nativeResult = 0;
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableIndexInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
out nativeResult,
|
|
sizeof(uint),
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = unchecked((int)nativeResult);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string indexname,
|
|
out JET_INDEXID result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableIndexInfo");
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableIndexInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
out result,
|
|
JET_INDEXID.SizeOfIndexId,
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
result = new JET_INDEXID();
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableIndexInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
out result,
|
|
JET_INDEXID.SizeOfIndexId,
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string indexname,
|
|
out JET_INDEXLIST result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableIndexInfo");
|
|
|
|
var nativeIndexlist = new NATIVE_INDEXLIST();
|
|
nativeIndexlist.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXLIST)));
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
err = Err(NativeMethods.JetGetTableIndexInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
ref nativeIndexlist,
|
|
nativeIndexlist.cbStruct,
|
|
(uint)infoLevel));
|
|
}
|
|
else
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
err = Err((int)JET_err.FeatureNotAvailable);
|
|
#else
|
|
err = Err(NativeMethods.JetGetTableIndexInfo(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
ref nativeIndexlist,
|
|
nativeIndexlist.cbStruct,
|
|
(uint)infoLevel));
|
|
#endif
|
|
}
|
|
|
|
result = new JET_INDEXLIST();
|
|
result.SetFromNativeIndexlist(nativeIndexlist);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves information about indexes on a table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to retrieve index information about.</param>
|
|
/// <param name="indexname">The name of the index.</param>
|
|
/// <param name="result">Filled in with information about indexes on the table.</param>
|
|
/// <param name="infoLevel">The type of information to retrieve.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetTableIndexInfo(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string indexname,
|
|
out string result,
|
|
JET_IdxInfo infoLevel)
|
|
{
|
|
TraceFunctionCall("JetGetTableIndexInfo");
|
|
|
|
// Will need to check for Windows 8 Features.
|
|
//
|
|
// Currently only JET_IdxInfo.LocaleName is supported.
|
|
uint bytesMax = checked((uint)SystemParameters.LocaleNameMaxLength * sizeof(char));
|
|
|
|
var stringBuilder = new StringBuilder(SystemParameters.LocaleNameMaxLength);
|
|
int err;
|
|
err = Err(NativeMethods.JetGetTableIndexInfoW(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
indexname,
|
|
stringBuilder,
|
|
bytesMax,
|
|
(uint)infoLevel));
|
|
|
|
result = stringBuilder.ToString();
|
|
result = StringCache.TryToIntern(result);
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Changes the name of an existing table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database containing the table.</param>
|
|
/// <param name="tableName">The name of the table.</param>
|
|
/// <param name="newTableName">The new name of the table.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetRenameTable(JET_SESID sesid, JET_DBID dbid, string tableName, string newTableName)
|
|
{
|
|
TraceFunctionCall("JetRenameTable");
|
|
CheckNotNull(tableName, "tableName");
|
|
CheckNotNull(newTableName, "newTableName");
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetRenameTableW(sesid.Value, dbid.Value, tableName, newTableName));
|
|
#else
|
|
return Err(NativeMethods.JetRenameTable(sesid.Value, dbid.Value, tableName, newTableName));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes the name of an existing column.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table containing the column.</param>
|
|
/// <param name="name">The name of the column.</param>
|
|
/// <param name="newName">The new name of the column.</param>
|
|
/// <param name="grbit">Column rename options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetRenameColumn(JET_SESID sesid, JET_TABLEID tableid, string name, string newName, RenameColumnGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetRenameColumn");
|
|
CheckNotNull(name, "name");
|
|
CheckNotNull(newName, "newName");
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(
|
|
NativeMethods.JetRenameColumnW(sesid.Value, tableid.Value, name, newName, (uint)grbit));
|
|
#else
|
|
return Err(
|
|
NativeMethods.JetRenameColumn(sesid.Value, tableid.Value, name, newName, (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Changes the default value of an existing column.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database containing the column.</param>
|
|
/// <param name="tableName">The name of the table containing the column.</param>
|
|
/// <param name="columnName">The name of the column.</param>
|
|
/// <param name="data">The new default value.</param>
|
|
/// <param name="dataSize">Size of the new default value.</param>
|
|
/// <param name="grbit">Column default value options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetColumnDefaultValue(
|
|
JET_SESID sesid, JET_DBID dbid, string tableName, string columnName, byte[] data, int dataSize, SetColumnDefaultValueGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetSetColumnDefaultValue");
|
|
CheckNotNull(tableName, "tableName");
|
|
CheckNotNull(columnName, "columnName");
|
|
CheckDataSize(data, dataSize, "dataSize");
|
|
return Err(
|
|
NativeMethods.JetSetColumnDefaultValue(
|
|
sesid.Value, dbid.Value, tableName, columnName, data, checked((uint)dataSize), (uint)grbit));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region Navigation
|
|
|
|
/// <summary>
|
|
/// Positions a cursor to an index entry for the record that is associated with
|
|
/// the specified bookmark. The bookmark can be used with any index defined over
|
|
/// a table. The bookmark for a record can be retrieved using <see cref="IJetApi.JetGetBookmark"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to position.</param>
|
|
/// <param name="bookmark">The bookmark used to position the cursor.</param>
|
|
/// <param name="bookmarkSize">The size of the bookmark.</param> /// <returns>An error if the call fails.</returns>
|
|
public int JetGotoBookmark(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize)
|
|
{
|
|
TraceFunctionCall("JetGotoBookmark");
|
|
CheckNotNull(bookmark, "bookmark");
|
|
CheckDataSize(bookmark, bookmarkSize, "bookmarkSize");
|
|
|
|
return
|
|
Err(
|
|
NativeMethods.JetGotoBookmark(
|
|
sesid.Value, tableid.Value, bookmark, checked((uint)bookmarkSize)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Positions a cursor to an index entry that is associated with the
|
|
/// specified secondary index bookmark. The secondary index bookmark
|
|
/// must be used with the same index over the same table from which it
|
|
/// was originally retrieved. The secondary index bookmark for an index
|
|
/// entry can be retrieved using <see cref="JetGotoSecondaryIndexBookmark"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table cursor to position.</param>
|
|
/// <param name="secondaryKey">The buffer that contains the secondary key.</param>
|
|
/// <param name="secondaryKeySize">The size of the secondary key.</param>
|
|
/// <param name="primaryKey">The buffer that contains the primary key.</param>
|
|
/// <param name="primaryKeySize">The size of the primary key.</param>
|
|
/// <param name="grbit">Options for positioning the bookmark.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGotoSecondaryIndexBookmark(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
byte[] secondaryKey,
|
|
int secondaryKeySize,
|
|
byte[] primaryKey,
|
|
int primaryKeySize,
|
|
GotoSecondaryIndexBookmarkGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetGotoSecondaryIndexBookmark");
|
|
CheckNotNull(secondaryKey, "secondaryKey");
|
|
CheckDataSize(secondaryKey, secondaryKeySize, "secondaryKeySize");
|
|
CheckDataSize(primaryKey, primaryKeySize, "primaryKeySize");
|
|
|
|
return
|
|
Err(
|
|
NativeMethods.JetGotoSecondaryIndexBookmark(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
secondaryKey,
|
|
checked((uint)secondaryKeySize),
|
|
primaryKey,
|
|
checked((uint)primaryKeySize),
|
|
(uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructs search keys that may then be used by <see cref="IJetApi.JetSeek"/> and <see cref="IJetApi.JetSetIndexRange"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The MakeKey functions provide datatype-specific make key functionality.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to create the key on.</param>
|
|
/// <param name="data">Column data for the current key column of the current index.</param>
|
|
/// <param name="dataSize">Size of the data.</param>
|
|
/// <param name="grbit">Key options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetMakeKey(JET_SESID sesid, JET_TABLEID tableid, IntPtr data, int dataSize, MakeKeyGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetMakeKey");
|
|
CheckNotNegative(dataSize, "dataSize");
|
|
return Err(NativeMethods.JetMakeKey(sesid.Value, tableid.Value, data, checked((uint)dataSize), unchecked((uint)grbit)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Efficiently positions a cursor to an index entry that matches the search
|
|
/// criteria specified by the search key in that cursor and the specified
|
|
/// inequality. A search key must have been previously constructed using
|
|
/// JetMakeKey.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to position.</param>
|
|
/// <param name="grbit">Seek options.</param>
|
|
/// <returns>An error or warning..</returns>
|
|
public int JetSeek(JET_SESID sesid, JET_TABLEID tableid, SeekGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetSeek");
|
|
return Err(NativeMethods.JetSeek(sesid.Value, tableid.Value, unchecked((uint)grbit)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Navigate through an index. The cursor can be positioned at the start or
|
|
/// end of the index and moved backwards and forwards by a specified number
|
|
/// of index entries.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use for the call.</param>
|
|
/// <param name="tableid">The cursor to position.</param>
|
|
/// <param name="numRows">An offset which indicates how far to move the cursor.</param>
|
|
/// <param name="grbit">Move options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetMove(JET_SESID sesid, JET_TABLEID tableid, int numRows, MoveGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetMove");
|
|
return Err(NativeMethods.JetMove(sesid.Value, tableid.Value, numRows, unchecked((uint)grbit)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Temporarily limits the set of index entries that the cursor can walk using
|
|
/// <see cref="IJetApi.JetMove"/> to those starting
|
|
/// from the current index entry and ending at the index entry that matches the
|
|
/// search criteria specified by the search key in that cursor and the specified
|
|
/// bound criteria. A search key must have been previously constructed using
|
|
/// JetMakeKey.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the index range on.</param>
|
|
/// <param name="grbit">Index range options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetIndexRange(JET_SESID sesid, JET_TABLEID tableid, SetIndexRangeGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetSetIndexRange");
|
|
return Err(NativeMethods.JetSetIndexRange(sesid.Value, tableid.Value, unchecked((uint)grbit)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the intersection between multiple sets of index entries from different secondary
|
|
/// indices over the same table. This operation is useful for finding the set of records in a
|
|
/// table that match two or more criteria that can be expressed using index ranges.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="ranges">
|
|
/// An the index ranges to intersect. The tableids in the ranges
|
|
/// must have index ranges set on them.
|
|
/// </param>
|
|
/// <param name="numRanges">
|
|
/// The number of index ranges.
|
|
/// </param>
|
|
/// <param name="recordlist">
|
|
/// Returns information about the temporary table containing the intersection results.
|
|
/// </param>
|
|
/// <param name="grbit">Intersection options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetIntersectIndexes(
|
|
JET_SESID sesid,
|
|
JET_INDEXRANGE[] ranges,
|
|
int numRanges,
|
|
out JET_RECORDLIST recordlist,
|
|
IntersectIndexesGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetIntersectIndexes");
|
|
CheckNotNull(ranges, "ranges");
|
|
CheckDataSize(ranges, numRanges, "numRanges");
|
|
if (numRanges < 2)
|
|
{
|
|
throw new ArgumentOutOfRangeException(
|
|
"numRanges", numRanges, "JetIntersectIndexes requires at least two index ranges.");
|
|
}
|
|
|
|
var indexRanges = new NATIVE_INDEXRANGE[numRanges];
|
|
for (int i = 0; i < numRanges; ++i)
|
|
{
|
|
indexRanges[i] = ranges[i].GetNativeIndexRange();
|
|
}
|
|
|
|
var nativeRecordlist = new NATIVE_RECORDLIST();
|
|
nativeRecordlist.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_RECORDLIST)));
|
|
|
|
int err = Err(
|
|
NativeMethods.JetIntersectIndexes(
|
|
sesid.Value,
|
|
indexRanges,
|
|
checked((uint)indexRanges.Length),
|
|
ref nativeRecordlist,
|
|
(uint)grbit));
|
|
recordlist = new JET_RECORDLIST();
|
|
recordlist.SetFromNativeRecordlist(nativeRecordlist);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the current index of a cursor.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the index on.</param>
|
|
/// <param name="index">
|
|
/// The name of the index to be selected. If this is null or empty the primary
|
|
/// index will be selected.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetCurrentIndex(JET_SESID sesid, JET_TABLEID tableid, string index)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetSetCurrentIndex4(sesid, tableid, index, IntPtr.Zero, SetCurrentIndexGrbit.MoveFirst, 1);
|
|
#else
|
|
TraceFunctionCall("JetSetCurrentIndex");
|
|
|
|
// A null index name is valid here -- it will set the table to the primary index
|
|
return Err(NativeMethods.JetSetCurrentIndex(sesid.Value, tableid.Value, index));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the current index of a cursor.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the index on.</param>
|
|
/// <param name="index">
|
|
/// The name of the index to be selected. If this is null or empty the primary
|
|
/// index will be selected.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Set index options.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetCurrentIndex2(JET_SESID sesid, JET_TABLEID tableid, string index, SetCurrentIndexGrbit grbit)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetSetCurrentIndex4(sesid, tableid, index, IntPtr.Zero, grbit, 1);
|
|
#else
|
|
TraceFunctionCall("JetSetCurrentIndex2");
|
|
|
|
// A null index name is valid here -- it will set the table to the primary index
|
|
return Err(NativeMethods.JetSetCurrentIndex2(sesid.Value, tableid.Value, index, (uint)grbit));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the current index of a cursor.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the index on.</param>
|
|
/// <param name="index">
|
|
/// The name of the index to be selected. If this is null or empty the primary
|
|
/// index will be selected.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Set index options.
|
|
/// </param>
|
|
/// <param name="itagSequence">
|
|
/// Sequence number of the multi-valued column value which will be used
|
|
/// to position the cursor on the new index. This parameter is only used
|
|
/// in conjunction with <see cref="SetCurrentIndexGrbit.NoMove"/>. When
|
|
/// this parameter is not present or is set to zero, its value is presumed
|
|
/// to be 1.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetCurrentIndex3(JET_SESID sesid, JET_TABLEID tableid, string index, SetCurrentIndexGrbit grbit, int itagSequence)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetSetCurrentIndex4(sesid, tableid, index, IntPtr.Zero, grbit, itagSequence);
|
|
#else
|
|
TraceFunctionCall("JetSetCurrentIndex3");
|
|
|
|
// A null index name is valid here -- it will set the table to the primary index
|
|
return Err(NativeMethods.JetSetCurrentIndex3(sesid.Value, tableid.Value, index, (uint)grbit, checked((uint)itagSequence)));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the current index of a cursor.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the index on.</param>
|
|
/// <param name="index">
|
|
/// The name of the index to be selected. If this is null or empty the primary
|
|
/// index will be selected.
|
|
/// </param>
|
|
/// <param name="indexid">
|
|
/// The id of the index to select. This id can be obtained using JetGetIndexInfo
|
|
/// or JetGetTableIndexInfo with the <see cref="JET_IdxInfo.IndexId"/> option.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Set index options.
|
|
/// </param>
|
|
/// <param name="itagSequence">
|
|
/// Sequence number of the multi-valued column value which will be used
|
|
/// to position the cursor on the new index. This parameter is only used
|
|
/// in conjunction with <see cref="SetCurrentIndexGrbit.NoMove"/>. When
|
|
/// this parameter is not present or is set to zero, its value is presumed
|
|
/// to be 1.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetCurrentIndex4(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string index,
|
|
JET_INDEXID indexid,
|
|
SetCurrentIndexGrbit grbit,
|
|
int itagSequence)
|
|
{
|
|
TraceFunctionCall("JetSetCurrentIndex4");
|
|
|
|
// A null index name is valid here -- it will set the table to the primary index
|
|
#if MANAGEDESENT_ON_WSA
|
|
return Err(NativeMethods.JetSetCurrentIndex4W(sesid.Value, tableid.Value, index, ref indexid, (uint)grbit, checked((uint)itagSequence)));
|
|
#else
|
|
return Err(NativeMethods.JetSetCurrentIndex4(sesid.Value, tableid.Value, index, ref indexid, (uint)grbit, checked((uint)itagSequence)));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Counts the number of entries in the current index from the current position forward.
|
|
/// The current position is included in the count. The count can be greater than the
|
|
/// total number of records in the table if the current index is over a multi-valued
|
|
/// column and instances of the column have multiple-values. If the table is empty,
|
|
/// then 0 will be returned for the count.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to count the records in.</param>
|
|
/// <param name="numRecords">Returns the number of records.</param>
|
|
/// <param name="maxRecordsToCount">
|
|
/// The maximum number of records to count.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetIndexRecordCount(JET_SESID sesid, JET_TABLEID tableid, out int numRecords, int maxRecordsToCount)
|
|
{
|
|
TraceFunctionCall("JetIndexRecordCount");
|
|
CheckNotNegative(maxRecordsToCount, "maxRecordsToCount");
|
|
uint crec = 0;
|
|
int err = Err(NativeMethods.JetIndexRecordCount(sesid.Value, tableid.Value, out crec, unchecked((uint)maxRecordsToCount))); // -1 is allowed
|
|
numRecords = checked((int)crec);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies the database engine that the application is scanning the entire
|
|
/// index that the cursor is positioned on. Consequently, the methods that
|
|
/// are used to access the index data will be tuned to make this scenario as
|
|
/// fast as possible.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor that will be accessing the data.</param>
|
|
/// <param name="grbit">Reserved for future use.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetTableSequential(JET_SESID sesid, JET_TABLEID tableid, SetTableSequentialGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetSetTableSequential");
|
|
return Err(NativeMethods.JetSetTableSequential(sesid.Value, tableid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies the database engine that the application is no longer scanning the
|
|
/// entire index the cursor is positioned on. This call reverses a notification
|
|
/// sent by JetSetTableSequential.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor that was accessing the data.</param>
|
|
/// <param name="grbit">Reserved for future use.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetResetTableSequential(JET_SESID sesid, JET_TABLEID tableid, ResetTableSequentialGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetResetTableSequential");
|
|
return Err(NativeMethods.JetResetTableSequential(sesid.Value, tableid.Value, (uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the fractional position of the current record in the current index
|
|
/// in the form of a JET_RECPOS structure.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor positioned on the record.</param>
|
|
/// <param name="recpos">Returns the approximate fractional position of the record.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetRecordPosition(JET_SESID sesid, JET_TABLEID tableid, out JET_RECPOS recpos)
|
|
{
|
|
TraceFunctionCall("JetGetRecordPosition");
|
|
recpos = new JET_RECPOS();
|
|
NATIVE_RECPOS native = recpos.GetNativeRecpos();
|
|
int err = Err(NativeMethods.JetGetRecordPosition(sesid.Value, tableid.Value, out native, native.cbStruct));
|
|
recpos.SetFromNativeRecpos(native);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moves a cursor to a new location that is a fraction of the way through
|
|
/// the current index.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to position.</param>
|
|
/// <param name="recpos">The approximate position to move to.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGotoPosition(JET_SESID sesid, JET_TABLEID tableid, JET_RECPOS recpos)
|
|
{
|
|
TraceFunctionCall("JetGotoPosition");
|
|
NATIVE_RECPOS native = recpos.GetNativeRecpos();
|
|
return Err(NativeMethods.JetGotoPosition(sesid.Value, tableid.Value, ref native));
|
|
}
|
|
|
|
/// <summary>
|
|
/// If the records with the specified keys 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="keys">
|
|
/// The keys to preread. The keys must be sorted.
|
|
/// </param>
|
|
/// <param name="keyLengths">The lengths of the keys to preread.</param>
|
|
/// <param name="keyIndex">
|
|
/// The index of the first key in the keys array to read.
|
|
/// </param>
|
|
/// <param name="keyCount">
|
|
/// The maximum number of keys to preread.
|
|
/// </param>
|
|
/// <param name="keysPreread">
|
|
/// Returns the number of keys to actually preread.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Preread options. Used to specify the direction of the preread.
|
|
/// </param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetPrereadKeys(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
byte[][] keys,
|
|
int[] keyLengths,
|
|
int keyIndex,
|
|
int keyCount,
|
|
out int keysPreread,
|
|
PrereadKeysGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetPrereadKeys");
|
|
this.CheckSupportsWindows7Features("JetPrereadKeys");
|
|
CheckDataSize(keys, keyIndex, "keyIndex", keyCount, "keyCount");
|
|
CheckDataSize(keyLengths, keyIndex, "keyIndex", keyCount, "keyCount");
|
|
CheckNotNull(keys, "keys");
|
|
CheckNotNull(keyLengths, "keyLengths");
|
|
|
|
int err;
|
|
unsafe
|
|
{
|
|
void** rgpvKeys = stackalloc void*[keyCount]; // [7/21/2010] StyleCop error? You need at least the 4.4 release of StyleCop
|
|
uint* rgcbKeys = stackalloc uint[keyCount];
|
|
using (var gchandlecollection = new GCHandleCollection())
|
|
{
|
|
gchandlecollection.SetCapacity(keyCount);
|
|
|
|
for (int i = 0; i < keyCount; ++i)
|
|
{
|
|
rgpvKeys[i] = (void*)gchandlecollection.Add(keys[keyIndex + i]);
|
|
rgcbKeys[i] = checked((uint)keyLengths[keyIndex + i]);
|
|
}
|
|
|
|
err = Err(NativeMethods.JetPrereadKeys(
|
|
sesid.Value, tableid.Value, rgpvKeys, rgcbKeys, keyCount, out keysPreread, (uint)grbit));
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Data Retrieval
|
|
|
|
/// <summary>
|
|
/// Retrieves the bookmark for the record that is associated with the index entry
|
|
/// at the current position of a cursor. This bookmark can then be used to
|
|
/// reposition that cursor back to the same record using <see cref="IJetApi.JetGotoBookmark"/>.
|
|
/// The bookmark will be no longer than <see cref="SystemParameters.BookmarkMost"/>
|
|
/// bytes.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve the bookmark from.</param>
|
|
/// <param name="bookmark">Buffer to contain the bookmark.</param>
|
|
/// <param name="bookmarkSize">Size of the bookmark buffer.</param>
|
|
/// <param name="actualBookmarkSize">Returns the actual size of the bookmark.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetBookmark(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize)
|
|
{
|
|
TraceFunctionCall("JetGetBookmark");
|
|
CheckDataSize(bookmark, bookmarkSize, "bookmarkSize");
|
|
|
|
uint bytesActual = 0;
|
|
int err = Err(
|
|
NativeMethods.JetGetBookmark(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
bookmark,
|
|
checked((uint)bookmarkSize),
|
|
out bytesActual));
|
|
|
|
actualBookmarkSize = GetActualSize(bytesActual);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a special bookmark for the secondary index entry at the
|
|
/// current position of a cursor. This bookmark can then be used to
|
|
/// efficiently reposition that cursor back to the same index entry
|
|
/// using JetGotoSecondaryIndexBookmark. This is most useful when
|
|
/// repositioning on a secondary index that contains duplicate keys or
|
|
/// that contains multiple index entries for the same record.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve the bookmark from.</param>
|
|
/// <param name="secondaryKey">Output buffer for the secondary key.</param>
|
|
/// <param name="secondaryKeySize">Size of the secondary key buffer.</param>
|
|
/// <param name="actualSecondaryKeySize">Returns the size of the secondary key.</param>
|
|
/// <param name="primaryKey">Output buffer for the primary key.</param>
|
|
/// <param name="primaryKeySize">Size of the primary key buffer.</param>
|
|
/// <param name="actualPrimaryKeySize">Returns the size of the primary key.</param>
|
|
/// <param name="grbit">Options for the call.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetSecondaryIndexBookmark(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
byte[] secondaryKey,
|
|
int secondaryKeySize,
|
|
out int actualSecondaryKeySize,
|
|
byte[] primaryKey,
|
|
int primaryKeySize,
|
|
out int actualPrimaryKeySize,
|
|
GetSecondaryIndexBookmarkGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetGetSecondaryIndexBookmark");
|
|
CheckDataSize(secondaryKey, secondaryKeySize, "secondaryKeySize");
|
|
CheckDataSize(primaryKey, primaryKeySize, "primaryKeySize");
|
|
|
|
uint bytesSecondaryKey = 0;
|
|
uint bytesPrimaryKey = 0;
|
|
int err = Err(
|
|
NativeMethods.JetGetSecondaryIndexBookmark(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
secondaryKey,
|
|
checked((uint)secondaryKeySize),
|
|
out bytesSecondaryKey,
|
|
primaryKey,
|
|
checked((uint)primaryKeySize),
|
|
out bytesPrimaryKey,
|
|
(uint)grbit));
|
|
|
|
actualSecondaryKeySize = GetActualSize(bytesSecondaryKey);
|
|
actualPrimaryKeySize = GetActualSize(bytesPrimaryKey);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the key for the index entry at the current position of a cursor.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve the key from.</param>
|
|
/// <param name="data">The buffer to retrieve the key into.</param>
|
|
/// <param name="dataSize">The size of the buffer.</param>
|
|
/// <param name="actualDataSize">Returns the actual size of the data.</param>
|
|
/// <param name="grbit">Retrieve key options.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetRetrieveKey(JET_SESID sesid, JET_TABLEID tableid, byte[] data, int dataSize, out int actualDataSize, RetrieveKeyGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetRetrieveKey");
|
|
CheckDataSize(data, dataSize, "dataSize");
|
|
|
|
uint bytesActual = 0;
|
|
int err = Err(NativeMethods.JetRetrieveKey(sesid.Value, tableid.Value, data, checked((uint)dataSize), out bytesActual, unchecked((uint)grbit)));
|
|
|
|
actualDataSize = GetActualSize(bytesActual);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a single column value from the current record. The record is that
|
|
/// record associated with the index entry at the current position of the cursor.
|
|
/// Alternatively, this function can retrieve a column from a record being created
|
|
/// in the cursor copy buffer. This function can also retrieve column data from an
|
|
/// index entry that references the current record. In addition to retrieving the
|
|
/// actual column value, JetRetrieveColumn can also be used to retrieve the size
|
|
/// of a column, before retrieving the column data itself so that application
|
|
/// buffers can be sized appropriately.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The RetrieveColumnAs functions provide datatype-specific retrieval functions.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve the column from.</param>
|
|
/// <param name="columnid">The columnid to retrieve.</param>
|
|
/// <param name="data">The data buffer to be retrieved into.</param>
|
|
/// <param name="dataSize">The size of the data buffer.</param>
|
|
/// <param name="actualDataSize">Returns the actual size of the data buffer.</param>
|
|
/// <param name="grbit">Retrieve column options.</param>
|
|
/// <param name="retinfo">
|
|
/// If pretinfo is give as NULL then the function behaves as though an itagSequence
|
|
/// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to
|
|
/// retrieve the first value of a multi-valued column, and to retrieve long data at
|
|
/// offset 0 (zero).
|
|
/// </param>
|
|
/// <returns>An error or warning.</returns>
|
|
public int JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo)
|
|
{
|
|
TraceFunctionCall("JetRetrieveColumn");
|
|
CheckNotNegative(dataSize, "dataSize");
|
|
|
|
int err;
|
|
uint bytesActual = 0;
|
|
if (null != retinfo)
|
|
{
|
|
NATIVE_RETINFO nativeRetinfo = retinfo.GetNativeRetinfo();
|
|
err = Err(NativeMethods.JetRetrieveColumn(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnid.Value,
|
|
data,
|
|
checked((uint)dataSize),
|
|
out bytesActual,
|
|
unchecked((uint)grbit),
|
|
ref nativeRetinfo));
|
|
retinfo.SetFromNativeRetinfo(nativeRetinfo);
|
|
}
|
|
else
|
|
{
|
|
err = Err(NativeMethods.JetRetrieveColumn(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnid.Value,
|
|
data,
|
|
checked((uint)dataSize),
|
|
out bytesActual,
|
|
unchecked((uint)grbit),
|
|
IntPtr.Zero));
|
|
}
|
|
|
|
actualDataSize = checked((int)bytesActual);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The JetRetrieveColumns function retrieves multiple column values
|
|
/// from the current record in a single operation. An array of
|
|
/// <see cref="NATIVE_RETRIEVECOLUMN"/> structures is used to
|
|
/// describe the set of column values to be retrieved, and to describe
|
|
/// output buffers for each column value to be retrieved.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve columns from.</param>
|
|
/// <param name="retrievecolumns">
|
|
/// An array of one or more JET_RETRIEVECOLUMN structures. Each
|
|
/// structure includes descriptions of which column value to retrieve
|
|
/// and where to store returned data.
|
|
/// </param>
|
|
/// <param name="numColumns">
|
|
/// Number of structures in the array given by retrievecolumns.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An error or warning.
|
|
/// </returns>
|
|
public unsafe int JetRetrieveColumns(JET_SESID sesid, JET_TABLEID tableid, NATIVE_RETRIEVECOLUMN* retrievecolumns, int numColumns)
|
|
{
|
|
TraceFunctionCall("JetRetrieveColumns");
|
|
return Err(NativeMethods.JetRetrieveColumns(sesid.Value, tableid.Value, retrievecolumns, checked((uint)numColumns)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Efficiently retrieves a set of columns and their values from the
|
|
/// current record of a cursor or the copy buffer of that cursor. The
|
|
/// columns and values retrieved can be restricted by a list of
|
|
/// column IDs, itagSequence numbers, and other characteristics. This
|
|
/// column retrieval API is unique in that it returns information in
|
|
/// dynamically allocated memory that is obtained using a
|
|
/// user-provided realloc compatible callback. This new flexibility
|
|
/// permits the efficient retrieval of column data with specific
|
|
/// characteristics (such as size and multiplicity) that are unknown
|
|
/// to the caller. This eliminates the need for the use of the discovery
|
|
/// modes of JetRetrieveColumn to determine those
|
|
/// characteristics in order to setup a final call to
|
|
/// JetRetrieveColumn that will successfully retrieve
|
|
/// the desired data.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve data from.</param>
|
|
/// <param name="numColumnids">The numbers of JET_ENUMCOLUMNIDS.</param>
|
|
/// <param name="columnids">
|
|
/// An optional array of column IDs, each with an optional array of itagSequence
|
|
/// numbers to enumerate.
|
|
/// </param>
|
|
/// <param name="numColumnValues">
|
|
/// Returns the number of column values retrieved.
|
|
/// </param>
|
|
/// <param name="columnValues">
|
|
/// Returns the enumerated column values.
|
|
/// </param>
|
|
/// <param name="allocator">
|
|
/// Callback used to allocate memory.
|
|
/// </param>
|
|
/// <param name="allocatorContext">
|
|
/// Context for the allocation callback.
|
|
/// </param>
|
|
/// <param name="maxDataSize">
|
|
/// Sets a cap on the amount of data to return from a long text or long
|
|
/// binary column. This parameter can be used to prevent the enumeration
|
|
/// of an extremely large column value.
|
|
/// </param>
|
|
/// <param name="grbit">Retrieve options.</param>
|
|
/// <returns>A warning, error or success.</returns>
|
|
public int JetEnumerateColumns(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
int numColumnids,
|
|
JET_ENUMCOLUMNID[] columnids,
|
|
out int numColumnValues,
|
|
out JET_ENUMCOLUMN[] columnValues,
|
|
JET_PFNREALLOC allocator,
|
|
IntPtr allocatorContext,
|
|
int maxDataSize,
|
|
EnumerateColumnsGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetEnumerateColumns");
|
|
CheckNotNull(allocator, "allocator");
|
|
CheckNotNegative(maxDataSize, "maxDataSize");
|
|
CheckDataSize(columnids, numColumnids, "numColumnids");
|
|
|
|
unsafe
|
|
{
|
|
// Converting to the native structs is a bit complex because we
|
|
// do not want to allocate heap memory for this operations. We
|
|
// allocate the NATIVE_ENUMCOLUMNID array on the stack and
|
|
// convert the managed objects. During the conversion pass we
|
|
// calculate the total size of the tags. An array for the tags
|
|
// is then allocated and a second pass converts the tags.
|
|
//
|
|
// Because we are using stackalloc all the work has to be done
|
|
// in the same method.
|
|
NATIVE_ENUMCOLUMNID* nativecolumnids = stackalloc NATIVE_ENUMCOLUMNID[numColumnids];
|
|
int totalNumTags = ConvertEnumColumnids(columnids, numColumnids, nativecolumnids);
|
|
|
|
uint* tags = stackalloc uint[totalNumTags];
|
|
ConvertEnumColumnidTags(columnids, numColumnids, nativecolumnids, tags);
|
|
|
|
uint numEnumColumn;
|
|
NATIVE_ENUMCOLUMN* nativeenumcolumns;
|
|
int err = NativeMethods.JetEnumerateColumns(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
checked((uint)numColumnids),
|
|
numColumnids > 0 ? nativecolumnids : null,
|
|
out numEnumColumn,
|
|
out nativeenumcolumns,
|
|
allocator,
|
|
allocatorContext,
|
|
checked((uint)maxDataSize),
|
|
(uint)grbit);
|
|
|
|
ConvertEnumerateColumnsResult(allocator, allocatorContext, numEnumColumn, nativeenumcolumns, out numColumnValues, out columnValues);
|
|
|
|
return Err(err);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Efficiently retrieves a set of columns and their values from the
|
|
/// current record of a cursor or the copy buffer of that cursor.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to retrieve data from.</param>
|
|
/// <param name="grbit">Enumerate options.</param>
|
|
/// <param name="enumeratedColumns">The discovered columns and their values.</param>
|
|
/// <returns>A warning or success.</returns>
|
|
public int JetEnumerateColumns(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
EnumerateColumnsGrbit grbit,
|
|
out IEnumerable<EnumeratedColumn> enumeratedColumns)
|
|
{
|
|
unsafe
|
|
{
|
|
// NOTE: We must never throw an exception up through ESE or it will corrupt its internal state!
|
|
Exception allocatorException = null;
|
|
JET_PFNREALLOC allocator = (c, pv, cb) =>
|
|
{
|
|
try
|
|
{
|
|
if (pv == IntPtr.Zero)
|
|
{
|
|
// NOTE: this will allocate memory if cb == 0 and that is what we want.
|
|
return Marshal.AllocHGlobal(new IntPtr(cb));
|
|
}
|
|
|
|
if (cb == 0)
|
|
{
|
|
Marshal.FreeHGlobal(pv);
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
return Marshal.ReAllocHGlobal(pv, new IntPtr(cb));
|
|
}
|
|
catch (OutOfMemoryException)
|
|
{
|
|
return IntPtr.Zero;
|
|
}
|
|
#if !MANAGEDESENT_ON_WSA // Thread model has changed in windows store apps.
|
|
catch (ThreadAbortException e)
|
|
{
|
|
LibraryHelpers.ThreadResetAbort();
|
|
allocatorException = e;
|
|
return IntPtr.Zero;
|
|
}
|
|
#endif
|
|
catch (Exception e)
|
|
{
|
|
allocatorException = e;
|
|
return IntPtr.Zero;
|
|
}
|
|
};
|
|
|
|
uint nativeEnumColumnCount;
|
|
NATIVE_ENUMCOLUMN* nativeEnumColumns;
|
|
int err = Implementation.NativeMethods.JetEnumerateColumns(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
0,
|
|
null,
|
|
out nativeEnumColumnCount,
|
|
out nativeEnumColumns,
|
|
allocator,
|
|
IntPtr.Zero,
|
|
int.MaxValue,
|
|
(uint)(grbit & ~EnumerateColumnsGrbit.EnumerateCompressOutput));
|
|
|
|
var columns = new EnumeratedColumn[nativeEnumColumnCount];
|
|
for (int i = 0; i < nativeEnumColumnCount; ++i)
|
|
{
|
|
columns[i] = new EnumeratedColumn();
|
|
columns[i].Id = new JET_COLUMNID { Value = nativeEnumColumns[i].columnid };
|
|
columns[i].Error = nativeEnumColumns[i].err < 0 ? (JET_err)nativeEnumColumns[i].err : JET_err.Success;
|
|
columns[i].Warning = nativeEnumColumns[i].err > 0 ? (JET_wrn)nativeEnumColumns[i].err : JET_wrn.Success;
|
|
if ((JET_wrn)nativeEnumColumns[i].err == JET_wrn.Success)
|
|
{
|
|
EnumeratedColumn.Value[] values = new EnumeratedColumn.Value[nativeEnumColumns[i].cEnumColumnValue];
|
|
columns[i].Values = values;
|
|
for (int j = 0; j < nativeEnumColumns[i].cEnumColumnValue; j++)
|
|
{
|
|
values[j] = new EnumeratedColumn.Value();
|
|
values[j].Ordinal = j + 1;
|
|
values[j].Warning = (JET_wrn)nativeEnumColumns[i].rgEnumColumnValue[j].err;
|
|
values[j].Bytes = new byte[(int)nativeEnumColumns[i].rgEnumColumnValue[j].cbData];
|
|
Marshal.Copy(
|
|
nativeEnumColumns[i].rgEnumColumnValue[j].pvData,
|
|
values[j].Bytes,
|
|
0,
|
|
(int)nativeEnumColumns[i].rgEnumColumnValue[j].cbData);
|
|
if (nativeEnumColumns[i].rgEnumColumnValue[j].pvData != IntPtr.Zero)
|
|
{
|
|
allocator(IntPtr.Zero, nativeEnumColumns[i].rgEnumColumnValue[j].pvData, 0);
|
|
}
|
|
}
|
|
|
|
if (nativeEnumColumns[i].rgEnumColumnValue != null)
|
|
{
|
|
allocator(IntPtr.Zero, new IntPtr(nativeEnumColumns[i].rgEnumColumnValue), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nativeEnumColumns != null)
|
|
{
|
|
allocator(IntPtr.Zero, new IntPtr(nativeEnumColumns), 0);
|
|
}
|
|
|
|
if (allocatorException != null)
|
|
{
|
|
#if !MANAGEDESENT_ON_WSA // Thread model has changed in Windows store apps.
|
|
if (allocatorException is ThreadAbortException)
|
|
{
|
|
Thread.CurrentThread.Abort();
|
|
}
|
|
#endif
|
|
throw allocatorException;
|
|
}
|
|
|
|
enumeratedColumns = columns;
|
|
return Err(err);
|
|
}
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Retrieves record size information from the desired location.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">
|
|
/// The cursor that will be used for the API call. The cursor must be
|
|
/// positioned on a record, or have an update prepared.
|
|
/// </param>
|
|
/// <param name="recsize">Returns the size of the record.</param>
|
|
/// <param name="grbit">Call options.</param>
|
|
/// <returns>A warning, error or success.</returns>
|
|
public int JetGetRecordSize(JET_SESID sesid, JET_TABLEID tableid, ref JET_RECSIZE recsize, GetRecordSizeGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetGetRecordSize");
|
|
this.CheckSupportsVistaFeatures("JetGetRecordSize");
|
|
int err;
|
|
|
|
// Use JetGetRecordSize2 if available, otherwise JetGetRecordSize.
|
|
if (this.Capabilities.SupportsWindows7Features)
|
|
{
|
|
var native = recsize.GetNativeRecsize2();
|
|
err = NativeMethods.JetGetRecordSize2(sesid.Value, tableid.Value, ref native, (uint)grbit);
|
|
recsize.SetFromNativeRecsize(native);
|
|
}
|
|
else
|
|
{
|
|
var native = recsize.GetNativeRecsize();
|
|
err = NativeMethods.JetGetRecordSize(sesid.Value, tableid.Value, ref native, (uint)grbit);
|
|
recsize.SetFromNativeRecsize(native);
|
|
}
|
|
|
|
return Err(err);
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region DML
|
|
|
|
/// <summary>
|
|
/// Deletes the current record in a database table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session that opened the cursor.</param>
|
|
/// <param name="tableid">The cursor on a database table. The current row will be deleted.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetDelete(JET_SESID sesid, JET_TABLEID tableid)
|
|
{
|
|
TraceFunctionCall("JetDelete");
|
|
return Err(NativeMethods.JetDelete(sesid.Value, tableid.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepare a cursor for update.
|
|
/// </summary>
|
|
/// <param name="sesid">The session which is starting the update.</param>
|
|
/// <param name="tableid">The cursor to start the update for.</param>
|
|
/// <param name="prep">The type of update to prepare.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetPrepareUpdate(JET_SESID sesid, JET_TABLEID tableid, JET_prep prep)
|
|
{
|
|
TraceFunctionCall("JetPrepareUpdate");
|
|
return Err(NativeMethods.JetPrepareUpdate(sesid.Value, tableid.Value, unchecked((uint)prep)));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The JetUpdate function performs an update operation including inserting a new row into
|
|
/// a table or updating an existing row. Deleting a table row is performed by calling
|
|
/// <see cref="IJetApi.JetDelete"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session which started the update.</param>
|
|
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
|
|
/// <param name="bookmark">Returns the bookmark of the updated record. This can be null.</param>
|
|
/// <param name="bookmarkSize">The size of the bookmark buffer.</param>
|
|
/// <param name="actualBookmarkSize">Returns the actual size of the bookmark.</param>
|
|
/// <remarks>
|
|
/// JetUpdate is the final step in performing an insert or an update. The update is begun by
|
|
/// calling <see cref="IJetApi.JetPrepareUpdate"/> and then by calling
|
|
/// JetSetColumn
|
|
/// one or more times to set the record state. Finally, JetUpdate
|
|
/// is called to complete the update operation. Indexes are updated only by JetUpdate or and not during JetSetColumn.
|
|
/// </remarks>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetUpdate(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize)
|
|
{
|
|
TraceFunctionCall("JetUpdate");
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetUpdate2(sesid, tableid, bookmark, bookmarkSize, out actualBookmarkSize, UpdateGrbit.None);
|
|
#else
|
|
CheckDataSize(bookmark, bookmarkSize, "bookmarkSize");
|
|
|
|
uint bytesActual;
|
|
int err = Err(NativeMethods.JetUpdate(sesid.Value, tableid.Value, bookmark, checked((uint)bookmarkSize), out bytesActual));
|
|
actualBookmarkSize = GetActualSize(bytesActual);
|
|
|
|
return err;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// The JetUpdate2 function performs an update operation including inserting a new row into
|
|
/// a table or updating an existing row. Deleting a table row is performed by calling
|
|
/// <see cref="JetDelete"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session which started the update.</param>
|
|
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
|
|
/// <param name="bookmark">Returns the bookmark of the updated record. This can be null.</param>
|
|
/// <param name="bookmarkSize">The size of the bookmark buffer.</param>
|
|
/// <param name="actualBookmarkSize">Returns the actual size of the bookmark.</param>
|
|
/// <param name="grbit">Update options.</param>
|
|
/// <remarks>
|
|
/// JetUpdate is the final step in performing an insert or an update. The update is begun by
|
|
/// calling <see cref="JetPrepareUpdate"/> and then by calling
|
|
/// JetSetColumn one or more times to set the record state. Finally, JetUpdate
|
|
/// is called to complete the update operation. Indexes are updated only by JetUpdate or and not during JetSetColumn.
|
|
/// </remarks>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetUpdate2(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize, UpdateGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetUpdate2");
|
|
CheckDataSize(bookmark, bookmarkSize, "bookmarkSize");
|
|
this.CheckSupportsServer2003Features("JetUpdate2");
|
|
|
|
uint bytesActual;
|
|
int err = Err(NativeMethods.JetUpdate2(sesid.Value, tableid.Value, bookmark, checked((uint)bookmarkSize), out bytesActual, (uint)grbit));
|
|
actualBookmarkSize = GetActualSize(bytesActual);
|
|
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The JetSetColumn function modifies a single column value in a modified record to be inserted or to
|
|
/// update the current record. It can overwrite an existing value, add a new value to a sequence of
|
|
/// values in a multi-valued column, remove a value from a sequence of values in a multi-valued column,
|
|
/// or update all or part of a long value (a column of type <see cref="JET_coltyp.LongText"/>
|
|
/// or <see cref="JET_coltyp.LongBinary"/>).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The SetColumn methods provide datatype-specific overrides which may be more efficient.
|
|
/// </remarks>
|
|
/// <param name="sesid">The session which is performing the update.</param>
|
|
/// <param name="tableid">The cursor to update. An update should be prepared.</param>
|
|
/// <param name="columnid">The columnid to set.</param>
|
|
/// <param name="data">The data to set.</param>
|
|
/// <param name="dataSize">The size of data to set.</param>
|
|
/// <param name="grbit">SetColumn options.</param>
|
|
/// <param name="setinfo">Used to specify itag or long-value offset.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetSetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, SetColumnGrbit grbit, JET_SETINFO setinfo)
|
|
{
|
|
TraceFunctionCall("JetSetColumn");
|
|
CheckNotNegative(dataSize, "dataSize");
|
|
if (IntPtr.Zero == data)
|
|
{
|
|
if (dataSize > 0 && (SetColumnGrbit.SizeLV != (grbit & SetColumnGrbit.SizeLV)))
|
|
{
|
|
throw new ArgumentOutOfRangeException(
|
|
"dataSize",
|
|
dataSize,
|
|
"cannot be greater than the length of the data (unless the SizeLV option is used)");
|
|
}
|
|
}
|
|
|
|
if (null != setinfo)
|
|
{
|
|
NATIVE_SETINFO nativeSetinfo = setinfo.GetNativeSetinfo();
|
|
return Err(NativeMethods.JetSetColumn(sesid.Value, tableid.Value, columnid.Value, data, checked((uint)dataSize), unchecked((uint)grbit), ref nativeSetinfo));
|
|
}
|
|
|
|
return Err(NativeMethods.JetSetColumn(sesid.Value, tableid.Value, columnid.Value, data, checked((uint)dataSize), unchecked((uint)grbit), IntPtr.Zero));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Allows an application to set multiple column values in a single
|
|
/// operation. An array of <see cref="NATIVE_SETCOLUMN"/> structures is
|
|
/// used to describe the set of column values to be set, and to describe
|
|
/// input buffers for each column value to be set.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the columns on.</param>
|
|
/// <param name="setcolumns">
|
|
/// An array of <see cref="NATIVE_SETCOLUMN"/> structures describing the
|
|
/// data to set.
|
|
/// </param>
|
|
/// <param name="numColumns">
|
|
/// Number of entries in the setcolumns parameter.
|
|
/// </param>
|
|
/// <returns>An error code or warning.</returns>
|
|
public unsafe int JetSetColumns(JET_SESID sesid, JET_TABLEID tableid, NATIVE_SETCOLUMN* setcolumns, int numColumns)
|
|
{
|
|
TraceFunctionCall("JetSetColumns");
|
|
return Err(NativeMethods.JetSetColumns(sesid.Value, tableid.Value, setcolumns, checked((uint)numColumns)));
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Explicitly reserve the ability to update a row, write lock, or to explicitly prevent a row from
|
|
/// being updated by any other session, read lock. Normally, row write locks are acquired implicitly as a
|
|
/// result of updating rows. Read locks are usually not required because of record versioning. However,
|
|
/// in some cases a transaction may desire to explicitly lock a row to enforce serialization, or to ensure
|
|
/// that a subsequent operation will succeed.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to use. A lock will be acquired on the current record.</param>
|
|
/// <param name="grbit">Lock options, use this to specify which type of lock to obtain.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetGetLock(JET_SESID sesid, JET_TABLEID tableid, GetLockGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetGetLock");
|
|
return Err(NativeMethods.JetGetLock(sesid.Value, tableid.Value, unchecked((uint)grbit)));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Performs an atomic addition operation on one column. This function allows
|
|
/// multiple sessions to update the same record concurrently without conflicts.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to update.</param>
|
|
/// <param name="columnid">
|
|
/// The column to update. This must be an escrow updatable column.
|
|
/// </param>
|
|
/// <param name="delta">The buffer containing the addend.</param>
|
|
/// <param name="deltaSize">The size of the addend.</param>
|
|
/// <param name="previousValue">
|
|
/// An output buffer that will recieve the current value of the column. This buffer
|
|
/// can be null.
|
|
/// </param>
|
|
/// <param name="previousValueLength">The size of the previousValue buffer.</param>
|
|
/// <param name="actualPreviousValueLength">Returns the actual size of the previousValue.</param>
|
|
/// <param name="grbit">Escrow update options.</param>
|
|
/// <returns>An error code if the operation fails.</returns>
|
|
public int JetEscrowUpdate(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
JET_COLUMNID columnid,
|
|
byte[] delta,
|
|
int deltaSize,
|
|
byte[] previousValue,
|
|
int previousValueLength,
|
|
out int actualPreviousValueLength,
|
|
EscrowUpdateGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetEscrowUpdate");
|
|
CheckNotNull(delta, "delta");
|
|
CheckDataSize(delta, deltaSize, "deltaSize");
|
|
CheckDataSize(previousValue, previousValueLength, "previousValueLength");
|
|
|
|
uint bytesOldActual = 0;
|
|
int err = Err(NativeMethods.JetEscrowUpdate(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
columnid.Value,
|
|
delta,
|
|
checked((uint)deltaSize),
|
|
previousValue,
|
|
checked((uint)previousValueLength),
|
|
out bytesOldActual,
|
|
unchecked((uint)grbit)));
|
|
actualPreviousValueLength = checked((int)bytesOldActual);
|
|
return err;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Callbacks
|
|
|
|
/// <summary>
|
|
/// Allows the application to configure the database engine to issue
|
|
/// notifications to the application for specific events. These
|
|
/// notifications are associated with a specific table and remain in
|
|
/// effect only until the instance containing the table is shut down
|
|
/// using <see cref="JetTerm"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">
|
|
/// A cursor opened on the table that the callback should be
|
|
/// registered on.
|
|
/// </param>
|
|
/// <param name="cbtyp">
|
|
/// The callback reasons for which the application wishes to receive notifications.
|
|
/// </param>
|
|
/// <param name="callback">The callback function.</param>
|
|
/// <param name="context">A context that will be given to the callback.</param>
|
|
/// <param name="callbackId">
|
|
/// A handle that can later be used to cancel the registration of the given
|
|
/// callback function using <see cref="JetUnregisterCallback"/>.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetRegisterCallback(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
JET_cbtyp cbtyp,
|
|
JET_CALLBACK callback,
|
|
IntPtr context,
|
|
out JET_HANDLE callbackId)
|
|
{
|
|
TraceFunctionCall("JetRegisterCallback");
|
|
CheckNotNull(callback, "callback");
|
|
|
|
callbackId = JET_HANDLE.Nil;
|
|
return Err(NativeMethods.JetRegisterCallback(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
unchecked((uint)cbtyp),
|
|
this.callbackWrappers.Add(callback).NativeCallback,
|
|
context,
|
|
out callbackId.Value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configures the database engine to stop issuing notifications to the
|
|
/// application as previously requested through
|
|
/// <see cref="JetRegisterCallback"/>.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">
|
|
/// A cursor opened on the table that the callback should be
|
|
/// registered on.
|
|
/// </param>
|
|
/// <param name="cbtyp">
|
|
/// The callback reasons for which the application no longer wishes to receive notifications.
|
|
/// </param>
|
|
/// <param name="callbackId">
|
|
/// The handle of the registered callback that was returned by <see cref="JetRegisterCallback"/>.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
public int JetUnregisterCallback(JET_SESID sesid, JET_TABLEID tableid, JET_cbtyp cbtyp, JET_HANDLE callbackId)
|
|
{
|
|
TraceFunctionCall("JetUnregisterCallback");
|
|
this.callbackWrappers.Collect();
|
|
return Err(NativeMethods.JetUnregisterCallback(
|
|
sesid.Value,
|
|
tableid.Value,
|
|
unchecked((uint)cbtyp),
|
|
callbackId.Value));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Online Maintenance
|
|
|
|
/// <summary>
|
|
/// Starts and stops database defragmentation tasks that improves data
|
|
/// organization within a database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use for the call.</param>
|
|
/// <param name="dbid">The database to be defragmented.</param>
|
|
/// <param name="tableName">
|
|
/// Under some options defragmentation is performed for the entire database described by the given
|
|
/// database ID, and other options (such as <see cref="Windows7Grbits.DefragmentBTree"/>) require
|
|
/// the name of the table to defragment.
|
|
/// </param>
|
|
/// <param name="passes">
|
|
/// When starting an online defragmentation task, this parameter sets the maximum number of defragmentation
|
|
/// passes. When stopping an online defragmentation task, this parameter is set to the number of passes
|
|
/// performed. This is not honored in all modes (such as <see cref="Windows7Grbits.DefragmentBTree"/>).
|
|
/// </param>
|
|
/// <param name="seconds">
|
|
/// When starting an online defragmentation task, this parameter sets
|
|
/// the maximum time for defragmentation. When stopping an online
|
|
/// defragmentation task, this output buffer is set to the length of
|
|
/// time used for defragmentation. This is not honored in all modes (such as <see cref="Windows7Grbits.DefragmentBTree"/>).
|
|
/// </param>
|
|
/// <param name="grbit">Defragmentation options.</param>
|
|
/// <returns>An error code.</returns>
|
|
/// <seealso cref="JetApi.Defragment"/>.
|
|
/// <seealso cref="JetApi.JetDefragment2"/>.
|
|
public int JetDefragment(JET_SESID sesid, JET_DBID dbid, string tableName, ref int passes, ref int seconds, DefragGrbit grbit)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.JetDefragment2(sesid, dbid, tableName, ref passes, ref seconds, null, grbit);
|
|
#else
|
|
TraceFunctionCall("JetDefragment");
|
|
uint nativePasses = unchecked((uint)passes);
|
|
uint nativeSeconds = unchecked((uint)seconds);
|
|
int err = Err(NativeMethods.JetDefragment(
|
|
sesid.Value, dbid.Value, tableName, ref nativePasses, ref nativeSeconds, (uint)grbit));
|
|
passes = unchecked((int)nativePasses);
|
|
seconds = unchecked((int)nativeSeconds);
|
|
return err;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts and stops database defragmentation tasks that improves data
|
|
/// organization within a database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use for the call.</param>
|
|
/// <param name="dbid">The database to be defragmented.</param>
|
|
/// <param name="tableName">
|
|
/// Under some options defragmentation is performed for the entire database described by the given
|
|
/// database ID, and other options (such as <see cref="Windows7Grbits.DefragmentBTree"/>) require
|
|
/// the name of the table to defragment.
|
|
/// </param>
|
|
/// <param name="grbit">Defragmentation options.</param>
|
|
/// <returns>An error code.</returns>
|
|
/// <seealso cref="JetApi.JetDefragment"/>.
|
|
public int Defragment(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tableName,
|
|
DefragGrbit grbit)
|
|
{
|
|
#if MANAGEDESENT_ON_WSA
|
|
return this.Defragment2(sesid, dbid, tableName, null, grbit);
|
|
#else
|
|
TraceFunctionCall("Defragment");
|
|
int err = Err(NativeMethods.JetDefragment(
|
|
sesid.Value, dbid.Value, tableName, IntPtr.Zero, IntPtr.Zero, (uint)grbit));
|
|
return err;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts and stops database defragmentation tasks that improves data
|
|
/// organization within a database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use for the call.</param>
|
|
/// <param name="dbid">The database to be defragmented.</param>
|
|
/// <param name="tableName">
|
|
/// Under some options defragmentation is performed for the entire database described by the given
|
|
/// database ID, and other options (such as <see cref="Windows7Grbits.DefragmentBTree"/>) require
|
|
/// the name of the table to defragment.
|
|
/// </param>
|
|
/// <param name="passes">
|
|
/// When starting an online defragmentation task, this parameter sets the maximum number of defragmentation
|
|
/// passes. When stopping an online defragmentation task, this parameter is set to the number of passes
|
|
/// performed. This is not honored in all modes (such as <see cref="Windows7Grbits.DefragmentBTree"/>).
|
|
/// </param>
|
|
/// <param name="seconds">
|
|
/// When starting an online defragmentation task, this parameter sets
|
|
/// the maximum time for defragmentation. When stopping an online
|
|
/// defragmentation task, this output buffer is set to the length of
|
|
/// time used for defragmentation. This is not honored in all modes (such as <see cref="Windows7Grbits.DefragmentBTree"/>).
|
|
/// </param>
|
|
/// <param name="callback">Callback function that defrag uses to report progress.</param>
|
|
/// <param name="grbit">Defragmentation options.</param>
|
|
/// <returns>An error code or warning.</returns>
|
|
/// <seealso cref="JetApi.JetDefragment"/>.
|
|
public int JetDefragment2(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tableName,
|
|
ref int passes,
|
|
ref int seconds,
|
|
JET_CALLBACK callback,
|
|
DefragGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetDefragment2");
|
|
uint nativePasses = unchecked((uint)passes);
|
|
uint nativeSeconds = unchecked((uint)seconds);
|
|
|
|
IntPtr functionPointer;
|
|
if (null == callback)
|
|
{
|
|
functionPointer = IntPtr.Zero;
|
|
}
|
|
else
|
|
{
|
|
JetCallbackWrapper callbackWrapper = this.callbackWrappers.Add(callback);
|
|
functionPointer = Marshal.GetFunctionPointerForDelegate(callbackWrapper.NativeCallback);
|
|
#if DEBUG
|
|
GC.Collect();
|
|
#endif
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
int err = Err(NativeMethods.JetDefragment2W(
|
|
sesid.Value, dbid.Value, tableName, ref nativePasses, ref nativeSeconds, functionPointer, (uint)grbit));
|
|
#else
|
|
int err = Err(NativeMethods.JetDefragment2(
|
|
sesid.Value, dbid.Value, tableName, ref nativePasses, ref nativeSeconds, functionPointer, (uint)grbit));
|
|
#endif
|
|
passes = unchecked((int)nativePasses);
|
|
seconds = unchecked((int)nativeSeconds);
|
|
this.callbackWrappers.Collect();
|
|
return err;
|
|
}
|
|
|
|
//// Currently, this overload of JetDefragment2() is not used outside of WSA.
|
|
#if MANAGEDESENT_ON_WSA
|
|
/// <summary>
|
|
/// Starts and stops database defragmentation tasks that improves data
|
|
/// organization within a database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use for the call.</param>
|
|
/// <param name="dbid">The database to be defragmented.</param>
|
|
/// <param name="tableName">
|
|
/// Under some options defragmentation is performed for the entire database described by the given
|
|
/// database ID, and other options (such as <see cref="Windows7Grbits.DefragmentBTree"/>) require
|
|
/// the name of the table to defragment.
|
|
/// </param>
|
|
/// <param name="callback">Callback function that defrag uses to report progress.</param>
|
|
/// <param name="grbit">Defragmentation options.</param>
|
|
/// <returns>An error code or warning.</returns>
|
|
/// <seealso cref="JetApi.JetDefragment2"/>.
|
|
public int Defragment2(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
string tableName,
|
|
JET_CALLBACK callback,
|
|
DefragGrbit grbit)
|
|
{
|
|
TraceFunctionCall("Defragment2");
|
|
|
|
IntPtr functionPointer;
|
|
if (null == callback)
|
|
{
|
|
functionPointer = IntPtr.Zero;
|
|
}
|
|
else
|
|
{
|
|
JetCallbackWrapper callbackWrapper = this.callbackWrappers.Add(callback);
|
|
functionPointer = Marshal.GetFunctionPointerForDelegate(callbackWrapper.NativeCallback);
|
|
#if DEBUG
|
|
GC.Collect();
|
|
#endif
|
|
}
|
|
|
|
#if MANAGEDESENT_ON_WSA
|
|
int err = Err(NativeMethods.JetDefragment2W(
|
|
sesid.Value, dbid.Value, tableName, IntPtr.Zero, IntPtr.Zero, functionPointer, (uint)grbit));
|
|
#else
|
|
int err = Err(NativeMethods.JetDefragment2(
|
|
sesid.Value, dbid.Value, tableName, IntPtr.Zero, IntPtr.Zero, functionPointer, (uint)grbit));
|
|
#endif
|
|
this.callbackWrappers.Collect();
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Performs idle cleanup tasks or checks the version store status in ESE.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="grbit">A combination of JetIdleGrbit flags.</param>
|
|
/// <returns>An error code if the operation fails.</returns>
|
|
public int JetIdle(JET_SESID sesid, IdleGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetIdle");
|
|
return Err(NativeMethods.JetIdle(sesid.Value, (uint)grbit));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region Misc
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Crash dump options for Watson.
|
|
/// </summary>
|
|
/// <param name="grbit">Crash dump options.</param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetConfigureProcessForCrashDump(CrashDumpGrbit grbit)
|
|
{
|
|
TraceFunctionCall("JetConfigureProcessForCrashDump");
|
|
this.CheckSupportsWindows7Features("JetConfigureProcessForCrashDump");
|
|
return Err(NativeMethods.JetConfigureProcessForCrashDump((uint)grbit));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Frees memory that was allocated by a database engine call.
|
|
/// </summary>
|
|
/// <param name="buffer">
|
|
/// The buffer allocated by a call to the database engine.
|
|
/// <see cref="IntPtr.Zero"/> is acceptable, and will be ignored.
|
|
/// </param>
|
|
/// <returns>An error code.</returns>
|
|
public int JetFreeBuffer(IntPtr buffer)
|
|
{
|
|
TraceFunctionCall("JetFreeBuffer");
|
|
return Err(NativeMethods.JetFreeBuffer(buffer));
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region Internal Helper Methods
|
|
|
|
/// <summary>
|
|
/// Given the size returned by ESENT, get the size
|
|
/// to return to the user.
|
|
/// </summary>
|
|
/// <param name="numBytesActual">The size returned by ESENT.</param>
|
|
/// <returns>The bookmark size to return to the user.</returns>
|
|
internal static int GetActualSize(uint numBytesActual)
|
|
{
|
|
// BUG: debug builds of ESENT can fill numBytesActual with this value in case of failure.
|
|
const uint CbActualDebugFill = 0xDDDDDDDD;
|
|
int actualSize;
|
|
if (CbActualDebugFill == numBytesActual)
|
|
{
|
|
actualSize = 0;
|
|
}
|
|
else
|
|
{
|
|
actualSize = checked((int)numBytesActual);
|
|
}
|
|
|
|
return actualSize;
|
|
}
|
|
|
|
#endregion Internal Helper Methods
|
|
|
|
#region Parameter Checking and Tracing
|
|
|
|
/// <summary>
|
|
/// Make sure the data, dataOffset and dataSize arguments match.
|
|
/// </summary>
|
|
/// <param name="data">The data buffer.</param>
|
|
/// <param name="dataOffset">The offset into the data.</param>
|
|
/// <param name="offsetArgumentName">The name of the offset argument.</param>
|
|
/// <param name="dataSize">The size of the data.</param>
|
|
/// <param name="sizeArgumentName">The name of the size argument.</param>
|
|
/// <typeparam name="T">The type of the data.</typeparam>
|
|
private static void CheckDataSize<T>(ICollection<T> data, int dataOffset, string offsetArgumentName, int dataSize, string sizeArgumentName)
|
|
{
|
|
CheckNotNegative(dataSize, sizeArgumentName);
|
|
CheckNotNegative(dataOffset, offsetArgumentName);
|
|
|
|
if ((null == data && 0 != dataOffset) || (null != data && dataOffset > data.Count))
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceError, "CheckDataSize failed");
|
|
throw new ArgumentOutOfRangeException(
|
|
offsetArgumentName,
|
|
dataOffset,
|
|
"cannot be greater than the length of the buffer");
|
|
}
|
|
|
|
if ((null == data && 0 != dataSize) || (null != data && dataSize > data.Count - dataOffset))
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceError, "CheckDataSize failed");
|
|
throw new ArgumentOutOfRangeException(
|
|
sizeArgumentName,
|
|
dataSize,
|
|
"cannot be greater than the length of the buffer");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make sure the data and dataSize arguments match.
|
|
/// </summary>
|
|
/// <param name="data">The data buffer.</param>
|
|
/// <param name="dataSize">The size of the data.</param>
|
|
/// <param name="argumentName">The name of the size argument.</param>
|
|
/// <typeparam name="T">The type of the data.</typeparam>
|
|
private static void CheckDataSize<T>(ICollection<T> data, int dataSize, string argumentName)
|
|
{
|
|
CheckDataSize(data, 0, string.Empty, dataSize, argumentName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make sure the given object isn't null. If it is
|
|
/// then throw an ArgumentNullException.
|
|
/// </summary>
|
|
/// <param name="o">The object to check.</param>
|
|
/// <param name="paramName">The name of the parameter.</param>
|
|
private static void CheckNotNull(object o, string paramName)
|
|
{
|
|
if (null == o)
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceError, "CheckNotNull failed");
|
|
throw new ArgumentNullException(paramName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make sure the given integer isn't negative. If it is
|
|
/// then throw an ArgumentOutOfRangeException.
|
|
/// </summary>
|
|
/// <param name="i">The integer to check.</param>
|
|
/// <param name="paramName">The name of the parameter.</param>
|
|
private static void CheckNotNegative(int i, string paramName)
|
|
{
|
|
if (i < 0)
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceError, "CheckNotNegative failed");
|
|
throw new ArgumentOutOfRangeException(paramName, i, "cannot be negative");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used when an unsupported API method is called. This
|
|
/// logs an error and returns an InvalidOperationException.
|
|
/// </summary>
|
|
/// <param name="method">The name of the method.</param>
|
|
/// <returns>The exception to throw.</returns>
|
|
private static Exception UnsupportedApiException(string method)
|
|
{
|
|
string error = string.Format(CultureInfo.InvariantCulture, "Method {0} is not supported by this version of ESENT", method);
|
|
Trace.WriteLineIf(TraceSwitch.TraceError, error);
|
|
return new InvalidOperationException(error);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Trace a call to an ESENT function.
|
|
/// </summary>
|
|
/// <param name="function">The name of the function being called.</param>
|
|
[Conditional("TRACE")]
|
|
#if DEBUG
|
|
// Disallow inlining so we can always get the name of the calling function.
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
#endif
|
|
private static void TraceFunctionCall(string function)
|
|
{
|
|
#if DEBUG && !MANAGEDESENT_ON_WSA
|
|
// Make sure the name of the calling function is correct.
|
|
var stackTrace = new StackTrace();
|
|
Debug.Assert(
|
|
stackTrace.GetFrame(1).GetMethod().Name == function,
|
|
"Incorrect function name",
|
|
function);
|
|
#endif // DEBUG && !MANAGEDESENT_ON_WSA
|
|
|
|
Trace.WriteLineIf(TraceSwitch.TraceInfo, function);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Can be used to trap ESENT errors.
|
|
/// </summary>
|
|
/// <param name="err">The error being returned.</param>
|
|
/// <returns>The error.</returns>
|
|
private static int Err(int err)
|
|
{
|
|
TraceErr(err);
|
|
return err;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Trace an error generated by a call to ESENT.
|
|
/// </summary>
|
|
/// <param name="err">The error to trace.</param>
|
|
[Conditional("TRACE")]
|
|
private static void TraceErr(int err)
|
|
{
|
|
if (0 == err)
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceVerbose, "JET_err.Success");
|
|
}
|
|
else if (err > 0)
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceWarning, unchecked((JET_wrn)err));
|
|
}
|
|
else
|
|
{
|
|
Trace.WriteLineIf(TraceSwitch.TraceError, unchecked((JET_err)err));
|
|
}
|
|
}
|
|
|
|
#endregion Parameter Checking and Tracing
|
|
|
|
#region Helper Methods
|
|
|
|
/// <summary>
|
|
/// Convert managed JET_ENUMCOLUMNID objects to NATIVE_ENUMCOLUMNID
|
|
/// structures.
|
|
/// </summary>
|
|
/// <param name="columnids">The columnids to convert.</param>
|
|
/// <param name="numColumnids">The number of columnids to convert.</param>
|
|
/// <param name="nativecolumnids">The array to store the converted columnids.</param>
|
|
/// <returns>The total number of tag entries in the converted structures.</returns>
|
|
private static unsafe int ConvertEnumColumnids(IList<JET_ENUMCOLUMNID> columnids, int numColumnids, NATIVE_ENUMCOLUMNID* nativecolumnids)
|
|
{
|
|
int totalNumTags = 0;
|
|
for (int i = 0; i < numColumnids; ++i)
|
|
{
|
|
nativecolumnids[i] = columnids[i].GetNativeEnumColumnid();
|
|
checked
|
|
{
|
|
totalNumTags += columnids[i].ctagSequence;
|
|
}
|
|
}
|
|
|
|
return totalNumTags;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert managed rgtagSequence to unmanaged rgtagSequence.
|
|
/// </summary>
|
|
/// <param name="columnids">The columnids to convert.</param>
|
|
/// <param name="numColumnids">The number of columnids to covert.</param>
|
|
/// <param name="nativecolumnids">The unmanaged columnids to add the tags to.</param>
|
|
/// <param name="tags">
|
|
/// Memory to use for converted rgtagSequence. This should be large enough to
|
|
/// hold all columnids.
|
|
/// </param>
|
|
private static unsafe void ConvertEnumColumnidTags(IList<JET_ENUMCOLUMNID> columnids, int numColumnids, NATIVE_ENUMCOLUMNID* nativecolumnids, uint* tags)
|
|
{
|
|
for (int i = 0; i < numColumnids; ++i)
|
|
{
|
|
nativecolumnids[i].rgtagSequence = tags;
|
|
for (int j = 0; j < columnids[i].ctagSequence; ++j)
|
|
{
|
|
nativecolumnids[i].rgtagSequence[j] = checked((uint)columnids[i].rgtagSequence[j]);
|
|
}
|
|
|
|
tags += columnids[i].ctagSequence;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert the native (unmanaged) results of JetEnumerateColumns to
|
|
/// managed objects. This uses the allocator callback to free some
|
|
/// memory as the data is converted.
|
|
/// </summary>
|
|
/// <param name="allocator">The allocator callback used.</param>
|
|
/// <param name="allocatorContext">The allocator callback context.</param>
|
|
/// <param name="numEnumColumn">Number of NATIVE_ENUMCOLUMN structures returned.</param>
|
|
/// <param name="nativeenumcolumns">NATIVE_ENUMCOLUMN structures.</param>
|
|
/// <param name="numColumnValues">Returns the number of converted JET_ENUMCOLUMN objects.</param>
|
|
/// <param name="columnValues">Returns the convertd column values.</param>
|
|
private static unsafe void ConvertEnumerateColumnsResult(JET_PFNREALLOC allocator, IntPtr allocatorContext, uint numEnumColumn, NATIVE_ENUMCOLUMN* nativeenumcolumns, out int numColumnValues, out JET_ENUMCOLUMN[] columnValues)
|
|
{
|
|
numColumnValues = checked((int)numEnumColumn);
|
|
columnValues = new JET_ENUMCOLUMN[numColumnValues];
|
|
for (int i = 0; i < numColumnValues; ++i)
|
|
{
|
|
columnValues[i] = new JET_ENUMCOLUMN();
|
|
columnValues[i].SetFromNativeEnumColumn(nativeenumcolumns[i]);
|
|
if (JET_wrn.ColumnSingleValue != columnValues[i].err)
|
|
{
|
|
columnValues[i].rgEnumColumnValue = new JET_ENUMCOLUMNVALUE[columnValues[i].cEnumColumnValue];
|
|
for (int j = 0; j < columnValues[i].cEnumColumnValue; ++j)
|
|
{
|
|
columnValues[i].rgEnumColumnValue[j] = new JET_ENUMCOLUMNVALUE();
|
|
columnValues[i].rgEnumColumnValue[j].SetFromNativeEnumColumnValue(nativeenumcolumns[i].rgEnumColumnValue[j]);
|
|
}
|
|
|
|
// the NATIVE_ENUMCOLUMNVALUES have been converted
|
|
// free their memory
|
|
allocator(allocatorContext, new IntPtr(nativeenumcolumns[i].rgEnumColumnValue), 0);
|
|
nativeenumcolumns[i].rgEnumColumnValue = null;
|
|
}
|
|
}
|
|
|
|
// Now we have converted all the NATIVE_ENUMCOLUMNS we can
|
|
// free the memory they use
|
|
allocator(allocatorContext, new IntPtr(nativeenumcolumns), 0);
|
|
nativeenumcolumns = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make an array of native columndefs from JET_COLUMNDEFs.
|
|
/// </summary>
|
|
/// <param name="columns">Columndefs to convert.</param>
|
|
/// <param name="numColumns">Number of columndefs to convert.</param>
|
|
/// <returns>An array of native columndefs.</returns>
|
|
private static NATIVE_COLUMNDEF[] GetNativecolumndefs(IList<JET_COLUMNDEF> columns, int numColumns)
|
|
{
|
|
var nativecolumndefs = new NATIVE_COLUMNDEF[numColumns];
|
|
for (int i = 0; i < numColumns; ++i)
|
|
{
|
|
nativecolumndefs[i] = columns[i].GetNativeColumndef();
|
|
}
|
|
|
|
return nativecolumndefs;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make native conditionalcolumn structures from the managed ones.
|
|
/// </summary>
|
|
/// <param name="conditionalColumns">The conditional columns to convert.</param>
|
|
/// <param name="useUnicodeData">Wehether to convert the strings with UTF-16.</param>
|
|
/// <param name="handles">The handle collection used to pin the data.</param>
|
|
/// <returns>Pinned native versions of the conditional columns.</returns>
|
|
private static IntPtr GetNativeConditionalColumns(
|
|
IList<JET_CONDITIONALCOLUMN> conditionalColumns,
|
|
bool useUnicodeData,
|
|
ref GCHandleCollection handles)
|
|
{
|
|
if (null == conditionalColumns)
|
|
{
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
var nativeConditionalcolumns = new NATIVE_CONDITIONALCOLUMN[conditionalColumns.Count];
|
|
for (int i = 0; i < conditionalColumns.Count; ++i)
|
|
{
|
|
nativeConditionalcolumns[i] = conditionalColumns[i].GetNativeConditionalColumn();
|
|
if (useUnicodeData)
|
|
{
|
|
nativeConditionalcolumns[i].szColumnName = handles.Add(Util.ConvertToNullTerminatedUnicodeByteArray(conditionalColumns[i].szColumnName));
|
|
}
|
|
else
|
|
{
|
|
nativeConditionalcolumns[i].szColumnName = handles.Add(Util.ConvertToNullTerminatedAsciiByteArray(conditionalColumns[i].szColumnName));
|
|
}
|
|
}
|
|
|
|
return handles.Add(nativeConditionalcolumns);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make native columncreate structures from the managed ones.
|
|
/// </summary>
|
|
/// <param name="managedColumnCreates">Column create structures to convert.</param>
|
|
/// <param name="useUnicodeData">Wehether to convert the strings with UTF-16.</param>
|
|
/// <param name="handles">The handle collection used to pin the data.</param>
|
|
/// <returns>Pinned native versions of the column creates.</returns>
|
|
private static IntPtr GetNativeColumnCreates(
|
|
IList<JET_COLUMNCREATE> managedColumnCreates,
|
|
bool useUnicodeData,
|
|
ref GCHandleCollection handles)
|
|
{
|
|
IntPtr nativeBuffer = IntPtr.Zero;
|
|
|
|
if (managedColumnCreates != null && managedColumnCreates.Count > 0)
|
|
{
|
|
var nativeColumns = new NATIVE_COLUMNCREATE[managedColumnCreates.Count];
|
|
|
|
for (int i = 0; i < managedColumnCreates.Count; ++i)
|
|
{
|
|
if (managedColumnCreates[i] != null)
|
|
{
|
|
JET_COLUMNCREATE managedColumn = managedColumnCreates[i];
|
|
nativeColumns[i] = managedColumn.GetNativeColumnCreate();
|
|
|
|
if (useUnicodeData)
|
|
{
|
|
nativeColumns[i].szColumnName = handles.Add(Util.ConvertToNullTerminatedUnicodeByteArray(managedColumn.szColumnName));
|
|
}
|
|
else
|
|
{
|
|
nativeColumns[i].szColumnName = handles.Add(Util.ConvertToNullTerminatedAsciiByteArray(managedColumn.szColumnName));
|
|
}
|
|
|
|
if (managedColumn.cbDefault > 0)
|
|
{
|
|
nativeColumns[i].pvDefault = handles.Add(managedColumn.pvDefault);
|
|
}
|
|
}
|
|
}
|
|
|
|
nativeBuffer = handles.Add(nativeColumns);
|
|
}
|
|
|
|
return nativeBuffer;
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Make native indexcreate structures from the managed ones.
|
|
/// Only supports Ascii data, since it could be used on XP.
|
|
/// </summary>
|
|
/// <param name="managedIndexCreates">Index create structures to convert.</param>
|
|
/// <param name="handles">The handle collection used to pin the data.</param>
|
|
/// <returns>Pinned native versions of the index creates.</returns>
|
|
private static unsafe JET_INDEXCREATE.NATIVE_INDEXCREATE[] GetNativeIndexCreates(
|
|
IList<JET_INDEXCREATE> managedIndexCreates,
|
|
ref GCHandleCollection handles)
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE[] nativeIndices = null;
|
|
|
|
if (managedIndexCreates != null && managedIndexCreates.Count > 0)
|
|
{
|
|
nativeIndices = new JET_INDEXCREATE.NATIVE_INDEXCREATE[managedIndexCreates.Count];
|
|
|
|
for (int i = 0; i < managedIndexCreates.Count; ++i)
|
|
{
|
|
nativeIndices[i] = managedIndexCreates[i].GetNativeIndexcreate();
|
|
|
|
if (null != managedIndexCreates[i].pidxUnicode)
|
|
{
|
|
NATIVE_UNICODEINDEX unicode = managedIndexCreates[i].pidxUnicode.GetNativeUnicodeIndex();
|
|
nativeIndices[i].pidxUnicode = (NATIVE_UNICODEINDEX*)handles.Add(unicode);
|
|
nativeIndices[i].grbit |= (uint)VistaGrbits.IndexUnicode;
|
|
}
|
|
|
|
nativeIndices[i].szKey = handles.Add(Util.ConvertToNullTerminatedAsciiByteArray(managedIndexCreates[i].szKey));
|
|
nativeIndices[i].szIndexName = handles.Add(Util.ConvertToNullTerminatedAsciiByteArray(managedIndexCreates[i].szIndexName));
|
|
nativeIndices[i].rgconditionalcolumn = GetNativeConditionalColumns(managedIndexCreates[i].rgconditionalcolumn, false, ref handles);
|
|
}
|
|
}
|
|
|
|
return nativeIndices;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make native indexcreate structures from the managed ones.
|
|
/// Only supports Unicode data, since it was introduced in Vista.
|
|
/// </summary>
|
|
/// <param name="managedIndexCreates">Index create structures to convert.</param>
|
|
/// <param name="handles">The handle collection used to pin the data.</param>
|
|
/// <returns>Pinned native versions of the index creates.</returns>
|
|
private static unsafe JET_INDEXCREATE.NATIVE_INDEXCREATE1[] GetNativeIndexCreate1s(
|
|
IList<JET_INDEXCREATE> managedIndexCreates,
|
|
ref GCHandleCollection handles)
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE1[] nativeIndices = null;
|
|
|
|
if (managedIndexCreates != null && managedIndexCreates.Count > 0)
|
|
{
|
|
nativeIndices = new JET_INDEXCREATE.NATIVE_INDEXCREATE1[managedIndexCreates.Count];
|
|
|
|
for (int i = 0; i < managedIndexCreates.Count; ++i)
|
|
{
|
|
nativeIndices[i] = managedIndexCreates[i].GetNativeIndexcreate1();
|
|
|
|
if (null != managedIndexCreates[i].pidxUnicode)
|
|
{
|
|
NATIVE_UNICODEINDEX unicode = managedIndexCreates[i].pidxUnicode.GetNativeUnicodeIndex();
|
|
nativeIndices[i].indexcreate.pidxUnicode = (NATIVE_UNICODEINDEX*)handles.Add(unicode);
|
|
nativeIndices[i].indexcreate.grbit |= (uint)VistaGrbits.IndexUnicode;
|
|
}
|
|
|
|
nativeIndices[i].indexcreate.szKey = handles.Add(Util.ConvertToNullTerminatedUnicodeByteArray(managedIndexCreates[i].szKey));
|
|
nativeIndices[i].indexcreate.cbKey *= sizeof(char);
|
|
nativeIndices[i].indexcreate.szIndexName = handles.Add(Util.ConvertToNullTerminatedUnicodeByteArray(managedIndexCreates[i].szIndexName));
|
|
nativeIndices[i].indexcreate.rgconditionalcolumn = GetNativeConditionalColumns(managedIndexCreates[i].rgconditionalcolumn, false, ref handles);
|
|
}
|
|
}
|
|
|
|
return nativeIndices;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make native indexcreate structures from the managed ones.
|
|
/// Only supports Unicode data, since it was introduced in Win7.
|
|
/// </summary>
|
|
/// <param name="managedIndexCreates">Index create structures to convert.</param>
|
|
/// <param name="handles">The handle collection used to pin the data.</param>
|
|
/// <returns>Pinned native versions of the index creates.</returns>
|
|
private static unsafe JET_INDEXCREATE.NATIVE_INDEXCREATE2[] GetNativeIndexCreate2s(
|
|
IList<JET_INDEXCREATE> managedIndexCreates,
|
|
ref GCHandleCollection handles)
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE2[] nativeIndices = null;
|
|
|
|
if (managedIndexCreates != null && managedIndexCreates.Count > 0)
|
|
{
|
|
nativeIndices = new JET_INDEXCREATE.NATIVE_INDEXCREATE2[managedIndexCreates.Count];
|
|
|
|
for (int i = 0; i < managedIndexCreates.Count; ++i)
|
|
{
|
|
nativeIndices[i] = managedIndexCreates[i].GetNativeIndexcreate2();
|
|
|
|
if (null != managedIndexCreates[i].pidxUnicode)
|
|
{
|
|
NATIVE_UNICODEINDEX unicode = managedIndexCreates[i].pidxUnicode.GetNativeUnicodeIndex();
|
|
nativeIndices[i].indexcreate1.indexcreate.pidxUnicode = (NATIVE_UNICODEINDEX*)handles.Add(unicode);
|
|
nativeIndices[i].indexcreate1.indexcreate.grbit |= (uint)VistaGrbits.IndexUnicode;
|
|
}
|
|
|
|
nativeIndices[i].indexcreate1.indexcreate.szKey = handles.Add(Util.ConvertToNullTerminatedUnicodeByteArray(managedIndexCreates[i].szKey));
|
|
nativeIndices[i].indexcreate1.indexcreate.cbKey *= sizeof(char);
|
|
nativeIndices[i].indexcreate1.indexcreate.szIndexName = handles.Add(Util.ConvertToNullTerminatedUnicodeByteArray(managedIndexCreates[i].szIndexName));
|
|
nativeIndices[i].indexcreate1.indexcreate.rgconditionalcolumn = GetNativeConditionalColumns(managedIndexCreates[i].rgconditionalcolumn, true, ref handles);
|
|
|
|
// Convert pSpaceHints.
|
|
if (managedIndexCreates[i].pSpaceHints != null)
|
|
{
|
|
NATIVE_SPACEHINTS nativeSpaceHints = managedIndexCreates[i].pSpaceHints.GetNativeSpaceHints();
|
|
|
|
nativeIndices[i].pSpaceHints = handles.Add(nativeSpaceHints);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nativeIndices;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
/// <summary>
|
|
/// Set managed columnids from unmanaged columnids. This also sets the columnids
|
|
/// in the columndefs.
|
|
/// </summary>
|
|
/// <param name="columns">The column definitions.</param>
|
|
/// <param name="columnids">The columnids to set.</param>
|
|
/// <param name="nativecolumnids">The native columnids.</param>
|
|
/// <param name="numColumns">The number of columnids to set.</param>
|
|
private static void SetColumnids(IList<JET_COLUMNDEF> columns, IList<JET_COLUMNID> columnids, IList<uint> nativecolumnids, int numColumns)
|
|
{
|
|
for (int i = 0; i < numColumns; ++i)
|
|
{
|
|
columnids[i] = new JET_COLUMNID { Value = nativecolumnids[i] };
|
|
columns[i].columnid = columnids[i];
|
|
}
|
|
}
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Creates indexes over data in an ESE database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to create the index on.</param>
|
|
/// <param name="indexcreates">Array of objects describing the indexes to be created.</param>
|
|
/// <param name="numIndexCreates">Number of index description objects.</param>
|
|
/// <returns>An error code.</returns>
|
|
private static int CreateIndexes(JET_SESID sesid, JET_TABLEID tableid, IList<JET_INDEXCREATE> indexcreates, int numIndexCreates)
|
|
{
|
|
// pin the memory
|
|
var handles = new GCHandleCollection();
|
|
try
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE[] nativeIndexcreates = GetNativeIndexCreates(indexcreates, ref handles);
|
|
return Err(NativeMethods.JetCreateIndex2(sesid.Value, tableid.Value, nativeIndexcreates, checked((uint)numIndexCreates)));
|
|
}
|
|
finally
|
|
{
|
|
handles.Dispose();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates indexes over data in an ESE database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to create the index on.</param>
|
|
/// <param name="indexcreates">Array of objects describing the indexes to be created.</param>
|
|
/// <param name="numIndexCreates">Number of index description objects.</param>
|
|
/// <returns>An error code.</returns>
|
|
private static int CreateIndexes1(JET_SESID sesid, JET_TABLEID tableid, IList<JET_INDEXCREATE> indexcreates, int numIndexCreates)
|
|
{
|
|
// pin the memory
|
|
var handles = new GCHandleCollection();
|
|
try
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE1[] nativeIndexcreates = GetNativeIndexCreate1s(indexcreates, ref handles);
|
|
return Err(NativeMethods.JetCreateIndex2W(sesid.Value, tableid.Value, nativeIndexcreates, checked((uint)numIndexCreates)));
|
|
}
|
|
finally
|
|
{
|
|
handles.Dispose();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates indexes over data in an ESE database.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The table to create the index on.</param>
|
|
/// <param name="indexcreates">Array of objects describing the indexes to be created.</param>
|
|
/// <param name="numIndexCreates">Number of index description objects.</param>
|
|
/// <returns>An error code.</returns>
|
|
private static int CreateIndexes2(JET_SESID sesid, JET_TABLEID tableid, IList<JET_INDEXCREATE> indexcreates, int numIndexCreates)
|
|
{
|
|
// pin the memory
|
|
var handles = new GCHandleCollection();
|
|
try
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE2[] nativeIndexcreates = GetNativeIndexCreate2s(indexcreates, ref handles);
|
|
return Err(NativeMethods.JetCreateIndex3W(sesid.Value, tableid.Value, nativeIndexcreates, checked((uint)numIndexCreates)));
|
|
}
|
|
finally
|
|
{
|
|
handles.Dispose();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a table, adds columns, and indices on that table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to which to add the new table.</param>
|
|
/// <param name="tablecreate">Object describing the table to create.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
private static int CreateTableColumnIndex3(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
JET_TABLECREATE tablecreate)
|
|
{
|
|
JET_TABLECREATE.NATIVE_TABLECREATE3 nativeTableCreate = tablecreate.GetNativeTableCreate3();
|
|
|
|
unsafe
|
|
{
|
|
var handles = new GCHandleCollection();
|
|
try
|
|
{
|
|
// Convert/pin the column definitions.
|
|
nativeTableCreate.rgcolumncreate = (NATIVE_COLUMNCREATE*)GetNativeColumnCreates(tablecreate.rgcolumncreate, true, ref handles);
|
|
|
|
// Convert/pin the index definitions.
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE2[] nativeIndexCreates = GetNativeIndexCreate2s(tablecreate.rgindexcreate, ref handles);
|
|
nativeTableCreate.rgindexcreate = handles.Add(nativeIndexCreates);
|
|
|
|
// Convert/pin the space hints.
|
|
if (tablecreate.pSeqSpacehints != null)
|
|
{
|
|
NATIVE_SPACEHINTS nativeSpaceHints = tablecreate.pSeqSpacehints.GetNativeSpaceHints();
|
|
nativeTableCreate.pSeqSpacehints = (NATIVE_SPACEHINTS*)handles.Add(nativeSpaceHints);
|
|
}
|
|
|
|
if (tablecreate.pLVSpacehints != null)
|
|
{
|
|
NATIVE_SPACEHINTS nativeSpaceHints = tablecreate.pLVSpacehints.GetNativeSpaceHints();
|
|
nativeTableCreate.pLVSpacehints = (NATIVE_SPACEHINTS*)handles.Add(nativeSpaceHints);
|
|
}
|
|
|
|
int err = NativeMethods.JetCreateTableColumnIndex3W(sesid.Value, dbid.Value, ref nativeTableCreate);
|
|
|
|
// Modified fields.
|
|
tablecreate.tableid = new JET_TABLEID
|
|
{
|
|
Value = nativeTableCreate.tableid
|
|
};
|
|
|
|
tablecreate.cCreated = checked((int)nativeTableCreate.cCreated);
|
|
|
|
if (tablecreate.rgcolumncreate != null)
|
|
{
|
|
for (int i = 0; i < tablecreate.rgcolumncreate.Length; ++i)
|
|
{
|
|
tablecreate.rgcolumncreate[i].SetFromNativeColumnCreate(nativeTableCreate.rgcolumncreate[i]);
|
|
}
|
|
}
|
|
|
|
if (tablecreate.rgindexcreate != null)
|
|
{
|
|
for (int i = 0; i < tablecreate.rgindexcreate.Length; ++i)
|
|
{
|
|
tablecreate.rgindexcreate[i].SetFromNativeIndexCreate(nativeIndexCreates[i]);
|
|
}
|
|
}
|
|
|
|
return Err(err);
|
|
}
|
|
finally
|
|
{
|
|
handles.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert native instance info structures to managed, treating the
|
|
/// unmanaged strings as Unicode.
|
|
/// </summary>
|
|
/// <param name="nativeNumInstance">The number of native structures.</param>
|
|
/// <param name="nativeInstanceInfos">
|
|
/// A pointer to the native structures. This pointer will be freed with JetFreeBuffer.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An array of JET_INSTANCE_INFO structures created from the unmanaged.
|
|
/// </returns>
|
|
private unsafe JET_INSTANCE_INFO[] ConvertInstanceInfosUnicode(uint nativeNumInstance, NATIVE_INSTANCE_INFO* nativeInstanceInfos)
|
|
{
|
|
int numInstances = checked((int)nativeNumInstance);
|
|
var instances = new JET_INSTANCE_INFO[numInstances];
|
|
for (int i = 0; i < numInstances; ++i)
|
|
{
|
|
instances[i] = new JET_INSTANCE_INFO();
|
|
instances[i].SetFromNativeUnicode(nativeInstanceInfos[i]);
|
|
}
|
|
|
|
this.JetFreeBuffer(new IntPtr(nativeInstanceInfos));
|
|
|
|
return instances;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert native instance info structures to managed, treating the
|
|
/// unmanaged string as Unicode.
|
|
/// </summary>
|
|
/// <param name="nativeNumInstance">The number of native structures.</param>
|
|
/// <param name="nativeInstanceInfos">
|
|
/// A pointer to the native structures. This pointer will be freed with JetFreeBuffer.
|
|
/// </param>
|
|
/// <returns>
|
|
/// An array of JET_INSTANCE_INFO structures created from the unmanaged.
|
|
/// </returns>
|
|
private unsafe JET_INSTANCE_INFO[] ConvertInstanceInfosAscii(uint nativeNumInstance, NATIVE_INSTANCE_INFO* nativeInstanceInfos)
|
|
{
|
|
int numInstances = checked((int)nativeNumInstance);
|
|
var instances = new JET_INSTANCE_INFO[numInstances];
|
|
for (int i = 0; i < numInstances; ++i)
|
|
{
|
|
instances[i] = new JET_INSTANCE_INFO();
|
|
instances[i].SetFromNativeAscii(nativeInstanceInfos[i]);
|
|
}
|
|
|
|
this.JetFreeBuffer(new IntPtr(nativeInstanceInfos));
|
|
|
|
return instances;
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region Capability Checking
|
|
|
|
/// <summary>
|
|
/// Check that ESENT supports Server 2003 features. Throws an exception if Server 2003 features
|
|
/// aren't supported.
|
|
/// </summary>
|
|
/// <param name="api">The API that is being called.</param>
|
|
private void CheckSupportsServer2003Features(string api)
|
|
{
|
|
if (!this.Capabilities.SupportsServer2003Features)
|
|
{
|
|
throw UnsupportedApiException(api);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check that ESENT supports Vista features. Throws an exception if Vista features
|
|
/// aren't supported.
|
|
/// </summary>
|
|
/// <param name="api">The API that is being called.</param>
|
|
private void CheckSupportsVistaFeatures(string api)
|
|
{
|
|
if (!this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
throw UnsupportedApiException(api);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check that ESENT supports Windows7 features. Throws an exception if Windows7 features
|
|
/// aren't supported.
|
|
/// </summary>
|
|
/// <param name="api">The API that is being called.</param>
|
|
private void CheckSupportsWindows7Features(string api)
|
|
{
|
|
if (!this.Capabilities.SupportsWindows7Features)
|
|
{
|
|
throw UnsupportedApiException(api);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check that ESENT supports Windows8 features. Throws an exception if Windows8 features
|
|
/// aren't supported.
|
|
/// </summary>
|
|
/// <param name="api">The API that is being called.</param>
|
|
private void CheckSupportsWindows8Features(string api)
|
|
{
|
|
if (!this.Capabilities.SupportsWindows8Features)
|
|
{
|
|
throw UnsupportedApiException(api);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check that ESENT supports Windows10 features. Throws an exception if Windows10 features
|
|
/// aren't supported.
|
|
/// </summary>
|
|
/// <param name="api">The API that is being called.</param>
|
|
private void CheckSupportsWindows10Features(string api)
|
|
{
|
|
if (!this.Capabilities.SupportsWindows10Features)
|
|
{
|
|
throw UnsupportedApiException(api);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Non-static Helper Methods
|
|
|
|
// This overload takes an IntPtr rather than a JET_INDEXID. It's meant to only be called by
|
|
// our JetSetCurrentIndex1-3, to 'up-cast' to JetSetCurrentIndex4().
|
|
#if MANAGEDESENT_ON_WSA
|
|
/// <summary>
|
|
/// Set the current index of a cursor.
|
|
/// This overload takes an IntPtr rather than a JET_INDEXID. It's meant to only be called by
|
|
/// our JetSetCurrentIndex1-3, to 'up-cast' to JetSetCurrentIndex4().
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="tableid">The cursor to set the index on.</param>
|
|
/// <param name="index">
|
|
/// The name of the index to be selected. If this is null or empty the primary
|
|
/// index will be selected.
|
|
/// </param>
|
|
/// <param name="indexid">
|
|
/// Reserved. Must be IntPtr.Zero.
|
|
/// </param>
|
|
/// <param name="grbit">
|
|
/// Set index options.
|
|
/// </param>
|
|
/// <param name="itagSequence">
|
|
/// Sequence number of the multi-valued column value which will be used
|
|
/// to position the cursor on the new index. This parameter is only used
|
|
/// in conjunction with <see cref="SetCurrentIndexGrbit.NoMove"/>. When
|
|
/// this parameter is not present or is set to zero, its value is presumed
|
|
/// to be 1.
|
|
/// </param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
private int JetSetCurrentIndex4(
|
|
JET_SESID sesid,
|
|
JET_TABLEID tableid,
|
|
string index,
|
|
IntPtr indexid,
|
|
SetCurrentIndexGrbit grbit,
|
|
int itagSequence)
|
|
{
|
|
TraceFunctionCall("JetSetCurrentIndex4");
|
|
|
|
if (indexid != IntPtr.Zero)
|
|
{
|
|
// If you have a valid indexid, you should be using the other overload!
|
|
throw new ArgumentException("indexid must be IntPtr.Zero.", "indexid");
|
|
}
|
|
|
|
// A null index name is valid here -- it will set the table to the primary index
|
|
return Err(NativeMethods.JetSetCurrentIndex4W(sesid.Value, tableid.Value, index, indexid, (uint)grbit, checked((uint)itagSequence)));
|
|
}
|
|
#endif // MANAGEDESENT_ON_WSA
|
|
|
|
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
|
|
/// <summary>
|
|
/// Creates a table, adds columns, and indices on that table.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database to which to add the new table.</param>
|
|
/// <param name="tablecreate">Object describing the table to create.</param>
|
|
/// <returns>An error if the call fails.</returns>
|
|
private int CreateTableColumnIndex2(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
JET_TABLECREATE tablecreate)
|
|
{
|
|
JET_TABLECREATE.NATIVE_TABLECREATE2 nativeTableCreate = tablecreate.GetNativeTableCreate2();
|
|
|
|
unsafe
|
|
{
|
|
var handles = new GCHandleCollection();
|
|
try
|
|
{
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE1[] nativeIndexCreate1s = null;
|
|
JET_INDEXCREATE.NATIVE_INDEXCREATE[] nativeIndexCreates = null;
|
|
int err;
|
|
|
|
if (this.Capabilities.SupportsVistaFeatures)
|
|
{
|
|
// Convert/pin the column definitions.
|
|
nativeTableCreate.rgcolumncreate = (NATIVE_COLUMNCREATE*)GetNativeColumnCreates(tablecreate.rgcolumncreate, true, ref handles);
|
|
|
|
// Convert/pin the index definitions.
|
|
nativeIndexCreate1s = GetNativeIndexCreate1s(tablecreate.rgindexcreate, ref handles);
|
|
nativeTableCreate.rgindexcreate = handles.Add(nativeIndexCreate1s);
|
|
err = NativeMethods.JetCreateTableColumnIndex2W(sesid.Value, dbid.Value, ref nativeTableCreate);
|
|
}
|
|
else
|
|
{
|
|
// Convert/pin the column definitions.
|
|
nativeTableCreate.rgcolumncreate = (NATIVE_COLUMNCREATE*)GetNativeColumnCreates(tablecreate.rgcolumncreate, false, ref handles);
|
|
|
|
// Convert/pin the index definitions.
|
|
nativeIndexCreates = GetNativeIndexCreates(tablecreate.rgindexcreate, ref handles);
|
|
nativeTableCreate.rgindexcreate = handles.Add(nativeIndexCreates);
|
|
err = NativeMethods.JetCreateTableColumnIndex2(sesid.Value, dbid.Value, ref nativeTableCreate);
|
|
}
|
|
|
|
// Modified fields.
|
|
tablecreate.tableid = new JET_TABLEID
|
|
{
|
|
Value = nativeTableCreate.tableid
|
|
};
|
|
|
|
tablecreate.cCreated = checked((int)nativeTableCreate.cCreated);
|
|
|
|
if (tablecreate.rgcolumncreate != null)
|
|
{
|
|
for (int i = 0; i < tablecreate.rgcolumncreate.Length; ++i)
|
|
{
|
|
tablecreate.rgcolumncreate[i].SetFromNativeColumnCreate(nativeTableCreate.rgcolumncreate[i]);
|
|
}
|
|
}
|
|
|
|
if (tablecreate.rgindexcreate != null)
|
|
{
|
|
for (int i = 0; i < tablecreate.rgindexcreate.Length; ++i)
|
|
{
|
|
if (null != nativeIndexCreate1s)
|
|
{
|
|
tablecreate.rgindexcreate[i].SetFromNativeIndexCreate(nativeIndexCreate1s[i]);
|
|
}
|
|
else
|
|
{
|
|
tablecreate.rgindexcreate[i].SetFromNativeIndexCreate(nativeIndexCreates[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Err(err);
|
|
}
|
|
finally
|
|
{
|
|
handles.Dispose();
|
|
}
|
|
}
|
|
}
|
|
#endif // !MANAGEDESENT_ON_WSA
|
|
|
|
#endregion
|
|
|
|
#region Hooks for not-yet-published APIs.
|
|
/// <summary>
|
|
/// Provides a hook to allow population of additional fields in
|
|
/// a different file. These additonal fields are not yet published
|
|
/// on MSDN.
|
|
/// </summary>
|
|
/// <param name="databaseName">The name of the database about which to retrieve information.</param>
|
|
/// <param name="dbinfomisc">The output structure to populate.</param>
|
|
/// <param name="infoLevel">Specifies which information to retrieve.</param>
|
|
/// <param name="notYetPublishedSupported">Whether the additional fields specified by in <paramref name="infoLevel"/>
|
|
/// are populated.</param>
|
|
/// <param name="err">The <see cref="JET_err"/> error code returned.</param>
|
|
partial void NotYetPublishedGetDbinfomisc(
|
|
string databaseName,
|
|
ref JET_DBINFOMISC dbinfomisc,
|
|
JET_DbInfo infoLevel,
|
|
ref bool notYetPublishedSupported,
|
|
ref int err);
|
|
|
|
/// <summary>
|
|
/// Provides a hook to allow population of additional fields in
|
|
/// a different file. These additonal fields are not yet published
|
|
/// on MSDN.
|
|
/// </summary>
|
|
/// <param name="sesid">The session to use.</param>
|
|
/// <param name="dbid">The database identifier.</param>
|
|
/// <param name="dbinfomisc">The output structure to populate.</param>
|
|
/// <param name="infoLevel">Specifies which information to retrieve.</param>
|
|
/// <param name="notYetPublishedSupported">Whether the additional fields specified by in <paramref name="infoLevel"/>
|
|
/// are populated.</param>
|
|
/// <param name="err">The <see cref="JET_err"/> error code returned.</param>
|
|
partial void NotYetPublishedGetDbinfomisc(
|
|
JET_SESID sesid,
|
|
JET_DBID dbid,
|
|
ref JET_DBINFOMISC dbinfomisc,
|
|
JET_DbInfo infoLevel,
|
|
ref bool notYetPublishedSupported,
|
|
ref int err);
|
|
|
|
#endregion
|
|
}
|
|
}
|