//-----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation.
//
//-----------------------------------------------------------------------
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;
///
/// Calls to the ESENT interop layer. These calls take the managed types (e.g. JET_SESID) and
/// return errors.
///
internal sealed partial class JetApi : IJetApi
{
///
/// API call tracing.
///
private static readonly TraceSwitch TraceSwitch = new TraceSwitch("ESENT P/Invoke", "P/Invoke calls to ESENT");
///
/// The version of esent. If this is zero then it is looked up
/// with JetGetVersion.
///
private readonly uint versionOverride;
///
/// 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.
///
private readonly CallbackWrappers callbackWrappers = new CallbackWrappers();
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
///
/// Initializes static members of the JetApi class.
///
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
///
/// Initializes a new instance of the JetApi class. This allows the version
/// to be set.
///
///
/// The version of Esent. This is used to override the results of
/// JetGetVersion.
///
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();
}
///
/// Initializes a new instance of the JetApi class.
///
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();
}
///
/// Gets the capabilities of this implementation of ESENT.
///
public JetCapabilities Capabilities { get; private set; }
#region Init/Term
///
/// Allocates a new instance of the database engine.
///
/// Returns the new instance.
/// The name of the instance. Names must be unique.
/// An error if the call fails.
public int JetCreateInstance(out JET_INSTANCE instance, string name)
{
#if MANAGEDESENT_ON_WSA
return this.JetCreateInstance2(out instance, name, null, CreateInstanceGrbit.None);
#else
TraceFunctionCall();
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
}
///
/// Allocate a new instance of the database engine for use in a single
/// process, with a display name specified.
///
/// Returns the newly create instance.
///
/// Specifies a unique string identifier for the instance to be created.
/// This string must be unique within a given process hosting the
/// database engine.
///
///
/// A display name for the instance to be created. This will be used
/// in eventlog entries.
///
/// Creation options.
/// An error if the call fails.
public int JetCreateInstance2(out JET_INSTANCE instance, string name, string displayName, CreateInstanceGrbit grbit)
{
TraceFunctionCall();
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
}
///
/// Initialize the ESENT database engine.
///
///
/// 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.
///
/// An error if the call fails.
public int JetInit(ref JET_INSTANCE instance)
{
#if MANAGEDESENT_ON_WSA
return this.JetInit3(ref instance, null, InitGrbit.None);
#else
TraceFunctionCall();
return Err(NativeMethods.JetInit(ref instance.Value));
#endif // MANAGEDESENT_ON_WSA
}
///
/// Initialize the ESENT database engine.
///
///
/// 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.
///
///
/// Initialization options.
///
/// An error or a warning.
public int JetInit2(ref JET_INSTANCE instance, InitGrbit grbit)
{
#if MANAGEDESENT_ON_WSA
return this.JetInit3(ref instance, null, grbit);
#else
TraceFunctionCall();
return Err(NativeMethods.JetInit2(ref instance.Value, (uint)grbit));
#endif // MANAGEDESENT_ON_WSA
}
///
/// Initialize the ESENT database engine.
///
///
/// 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.
///
///
/// Additional recovery parameters for remapping databases during
/// recovery, position where to stop recovery at, or recovery status.
///
///
/// Initialization options.
///
/// An error code or warning.
public int JetInit3(ref JET_INSTANCE instance, JET_RSTINFO recoveryOptions, InitGrbit grbit)
{
TraceFunctionCall();
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
///
/// Retrieves information about the instances that are running.
///
///
/// Returns the number of instances.
///
///
/// Returns an array of instance info objects, one for each running
/// instance.
///
/// An error code if the call fails.
public int JetGetInstanceInfo(out int numInstances, out JET_INSTANCE_INFO[] instances)
{
TraceFunctionCall();
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);
}
}
///
/// Retrieves information about an instance.
///
/// The instance to get information about.
/// Retrieved information.
/// The type of information to retrieve.
/// An error code if the call fails.
public int JetGetInstanceMiscInfo(JET_INSTANCE instance, out JET_SIGNATURE signature, JET_InstanceMiscInfo infoLevel)
{
TraceFunctionCall();
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);
}
///
/// Prevents streaming backup-related activity from continuing on a
/// specific running instance, thus ending the streaming backup in
/// a predictable way.
///
/// The instance to use.
/// An error code.
public int JetStopBackupInstance(JET_INSTANCE instance)
{
TraceFunctionCall();
return Err(NativeMethods.JetStopBackupInstance(instance.Value));
}
///
/// Prepares an instance for termination.
///
/// The (running) instance to use.
/// An error code.
public int JetStopServiceInstance(JET_INSTANCE instance)
{
TraceFunctionCall();
return Err(NativeMethods.JetStopServiceInstance(instance.Value));
}
#endif // !MANAGEDESENT_ON_WSA
///
/// Prepares an instance for termination. Can also be used to resume a previous quiescing.
///
/// The (running) instance to use.
/// The options to stop or resume the instance.
/// An error code.
public int JetStopServiceInstance2(
JET_INSTANCE instance,
StopServiceGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsWindows8Features("JetStopServiceInstance2");
return Err(NativeMethods.JetStopServiceInstance2(instance.Value, unchecked((uint)grbit)));
}
///
/// Terminate an instance that was created with or
/// .
///
/// The instance to terminate.
/// An error or warning.
public int JetTerm(JET_INSTANCE instance)
{
#if MANAGEDESENT_ON_WSA
return this.JetTerm2(instance, TermGrbit.None);
#else
TraceFunctionCall();
this.callbackWrappers.Collect();
if (!instance.IsInvalid)
{
return Err(NativeMethods.JetTerm(instance.Value));
}
return (int)JET_err.Success;
#endif // MANAGEDESENT_ON_WSA
}
///
/// Terminate an instance that was created with or
/// .
///
/// The instance to terminate.
/// Termination options.
/// An error or warning.
public int JetTerm2(JET_INSTANCE instance, TermGrbit grbit)
{
TraceFunctionCall();
this.callbackWrappers.Collect();
if (!instance.IsInvalid)
{
return Err(NativeMethods.JetTerm2(instance.Value, (uint)grbit));
}
return (int)JET_err.Success;
}
///
/// Sets database configuration options.
///
///
/// The instance to set the option on or
/// to set the option on all instances.
///
/// The session to use.
/// The parameter to set.
/// The value of the parameter to set, if the parameter is an integer type.
/// The value of the parameter to set, if the parameter is a string type.
/// An error or warning.
public int JetSetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, IntPtr paramValue, string paramString)
{
TraceFunctionCall();
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
}
}
///
/// Sets database configuration options. This overload is used when the
/// parameter being set is of type JET_CALLBACK.
///
///
/// The instance to set the option on or
/// to set the option on all instances.
///
/// The session to use.
/// The parameter to set.
/// The value of the parameter to set.
/// The value of the string parameter to set.
/// An error or warning.
public int JetSetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, JET_CALLBACK paramValue, string paramString)
{
TraceFunctionCall();
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
}
}
///
/// Gets database configuration options.
///
/// The instance to retrieve the options from.
/// The session to use.
/// The parameter to get.
/// Returns the value of the parameter, if the value is an integer.
/// Returns the value of the parameter, if the value is a string.
/// The maximum size of the parameter string.
/// An ESENT warning code.
///
/// passes in the error number in the paramValue, which is why it is
/// a ref parameter and not an out parameter.
///
/// An error or warning.
public int JetGetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, JET_param paramid, ref IntPtr paramValue, out string paramString, int maxParam)
{
TraceFunctionCall();
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
///
/// Retrieves the version of the database engine.
///
/// The session to use.
/// Returns the version number of the database engine.
/// An error code if the call fails.
public int JetGetVersion(JET_SESID sesid, out uint version)
{
TraceFunctionCall();
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
///
/// Creates and attaches a database file.
///
/// The session to use.
/// The path to the database file to create.
/// The parameter is not used.
/// Returns the dbid of the new database.
/// Database creation options.
/// An error or warning.
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();
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
}
///
/// Creates and attaches a database file with a maximum database size specified.
/// .
///
/// The session to use.
/// The path to the database file to create.
///
/// The maximum size, in database pages, of the database. Passing 0 means there is
/// no enforced maximum.
///
/// Returns the dbid of the new database.
/// Database creation options.
/// An error or warning.
public int JetCreateDatabase2(JET_SESID sesid, string database, int maxPages, out JET_DBID dbid, CreateDatabaseGrbit grbit)
{
TraceFunctionCall();
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
}
///
/// Attaches a database file for use with a database instance. In order to use the
/// database, it will need to be subsequently opened with .
///
/// The session to use.
/// The database to attach.
/// Attach options.
/// An error or warning.
public int JetAttachDatabase(JET_SESID sesid, string database, AttachDatabaseGrbit grbit)
{
#if MANAGEDESENT_ON_WSA
return this.JetAttachDatabase2(sesid, database, 0, grbit);
#else
TraceFunctionCall();
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
}
///
/// Attaches a database file for use with a database instance. In order to use the
/// database, it will need to be subsequently opened with .
/// .
///
/// The session to use.
/// The database to attach.
///
/// The maximum size, in database pages, of the database. Passing 0 means there is
/// no enforced maximum.
///
/// Attach options.
/// An error or warning.
public int JetAttachDatabase2(JET_SESID sesid, string database, int maxPages, AttachDatabaseGrbit grbit)
{
TraceFunctionCall();
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
}
///
/// Opens a database previously attached with ,
/// for use with a database session. This function can be called multiple times
/// for the same database.
///
/// The session that is opening the database.
/// The database to open.
/// Reserved for future use.
/// Returns the dbid of the attached database.
/// Open database options.
/// An error or warning.
public int JetOpenDatabase(JET_SESID sesid, string database, string connect, out JET_DBID dbid, OpenDatabaseGrbit grbit)
{
TraceFunctionCall();
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
}
///
/// Closes a database file that was previously opened with or
/// created with .
///
/// The session to use.
/// The database to close.
/// Close options.
/// An error or warning.
public int JetCloseDatabase(JET_SESID sesid, JET_DBID dbid, CloseDatabaseGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetCloseDatabase(sesid.Value, dbid.Value, (uint)grbit));
}
///
/// Releases a database file that was previously attached to a database session.
///
/// The database session to use.
/// The database to detach.
/// An error or warning.
public int JetDetachDatabase(JET_SESID sesid, string database)
{
TraceFunctionCall();
#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
}
///
/// Releases a database file that was previously attached to a database session.
///
/// The database session to use.
/// The database to detach.
/// Detach options.
/// An error or warning.
public int JetDetachDatabase2(JET_SESID sesid, string database, DetachDatabaseGrbit grbit)
{
TraceFunctionCall();
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
///
/// 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.
///
/// The session to use for the call.
/// The source database that will be compacted.
/// The name to use for the compacted database.
///
/// A callback function that can be called periodically through the
/// database compact operation to report progress.
///
///
/// This parameter is ignored and should be null.
///
/// Compact options.
/// An error code.
public int JetCompact(
JET_SESID sesid,
string sourceDatabase,
string destinationDatabase,
JET_PFNSTATUS statusCallback,
object ignored,
CompactGrbit grbit)
{
TraceFunctionCall();
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;
}
///
/// Extends the size of a database that is currently open.
///
/// The session to use.
/// The database to grow.
/// The desired size of the database, in pages.
///
/// The size of the database, in pages, after the call.
///
/// An error if the call fails.
public int JetGrowDatabase(JET_SESID sesid, JET_DBID dbid, int desiredPages, out int actualPages)
{
TraceFunctionCall();
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;
}
///
/// Extends the size of a database that is currently open.
///
/// The session to use.
/// The name of the database to grow.
/// The desired size of the database, in pages.
///
/// The size of the database, in pages, after the call.
///
/// An error if the call fails.
public int JetSetDatabaseSize(JET_SESID sesid, string database, int desiredPages, out int actualPages)
{
TraceFunctionCall();
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
///
/// Retrieves certain information about the given database.
///
/// The session to use.
/// The database identifier.
/// The value to be retrieved.
/// The specific data to retrieve.
/// An error if the call fails.
public int JetGetDatabaseInfo(
JET_SESID sesid,
JET_DBID dbid,
out int value,
JET_DbInfo infoLevel)
{
TraceFunctionCall();
#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
}
///
/// Retrieves certain information about the given database.
///
/// The session to use.
/// The database identifier.
/// The value to be retrieved.
/// The specific data to retrieve.
/// An error if the call fails.
public int JetGetDatabaseInfo(
JET_SESID sesid,
JET_DBID dbid,
out JET_DBINFOMISC dbinfomisc,
JET_DbInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves certain information about the given database.
///
/// The session to use.
/// The database identifier.
/// The value to be retrieved.
/// The specific data to retrieve.
/// An error if the call fails.
public int JetGetDatabaseInfo(
JET_SESID sesid,
JET_DBID dbid,
out string value,
JET_DbInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves certain information about the given database.
///
/// The file name of the database.
/// The value to be retrieved.
/// The specific data to retrieve.
/// An error if the call fails.
public int JetGetDatabaseFileInfo(
string databaseName,
out int value,
JET_DbInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves certain information about the given database.
///
/// The file name of the database.
/// The value to be retrieved.
/// The specific data to retrieve.
/// An error if the call fails.
public int JetGetDatabaseFileInfo(
string databaseName,
out long value,
JET_DbInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves certain information about the given database.
///
/// The file name of the database.
/// The value to be retrieved.
/// The specific data to retrieve.
/// An error if the call fails.
public int JetGetDatabaseFileInfo(
string databaseName,
out JET_DBINFOMISC dbinfomisc,
JET_DbInfo infoLevel)
{
TraceFunctionCall();
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
///
/// 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.
///
/// The instance to backup.
///
/// 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.
///
/// Backup options.
///
/// Optional status notification callback.
///
/// An error code.
public int JetBackupInstance(
JET_INSTANCE instance, string destination, BackupGrbit grbit, JET_PFNSTATUS statusCallback)
{
TraceFunctionCall();
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;
}
///
/// 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 function. This is the
/// simplest and most encapsulated restore function.
///
/// The instance to use.
///
/// Location of the backup. The backup should have been created with
/// .
///
///
/// 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.
///
///
/// Optional status notification callback.
///
/// An error code.
public int JetRestoreInstance(JET_INSTANCE instance, string source, string destination, JET_PFNSTATUS statusCallback)
{
TraceFunctionCall();
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
///
/// 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).
///
/// Returns the ID of the snapshot session.
/// Snapshot options.
/// An error code if the call fails.
public int JetOSSnapshotPrepare(out JET_OSSNAPID snapid, SnapshotPrepareGrbit grbit)
{
TraceFunctionCall();
snapid = JET_OSSNAPID.Nil;
return Err(NativeMethods.JetOSSnapshotPrepare(out snapid.Value, (uint)grbit));
}
///
/// Selects a specific instance to be part of the snapshot session.
///
/// The snapshot identifier.
/// The instance to add to the snapshot.
/// Options for this call.
/// An error code if the call fails.
public int JetOSSnapshotPrepareInstance(JET_OSSNAPID snapshot, JET_INSTANCE instance, SnapshotPrepareInstanceGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsVistaFeatures("JetOSSnapshotPrepareInstance");
return Err(NativeMethods.JetOSSnapshotPrepareInstance(snapshot.Value, instance.Value, (uint)grbit));
}
///
/// Starts a snapshot. While the snapshot is in progress, no
/// write-to-disk activity by the engine can take place.
///
/// The snapshot session.
///
/// Returns the number of instances that are part of the snapshot session.
///
///
/// Returns information about the instances that are part of the snapshot session.
///
///
/// Snapshot freeze options.
///
/// An error code if the call fails.
public int JetOSSnapshotFreeze(JET_OSSNAPID snapshot, out int numInstances, out JET_INSTANCE_INFO[] instances, SnapshotFreezeGrbit grbit)
{
TraceFunctionCall();
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);
}
}
///
/// Retrieves the list of instances and databases that are part of the
/// snapshot session at any given moment.
///
/// The identifier of the snapshot session.
/// Returns the number of instances.
/// Returns information about the instances.
/// Options for this call.
/// An error code if the call fails.
public int JetOSSnapshotGetFreezeInfo(
JET_OSSNAPID snapshot,
out int numInstances,
out JET_INSTANCE_INFO[] instances,
SnapshotGetFreezeInfoGrbit grbit)
{
TraceFunctionCall();
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);
}
}
///
/// Notifies the engine that it can resume normal IO operations after a
/// freeze period and a successful snapshot.
///
/// The ID of the snapshot.
/// Thaw options.
/// An error code if the call fails.
public int JetOSSnapshotThaw(JET_OSSNAPID snapid, SnapshotThawGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetOSSnapshotThaw(snapid.Value, (uint)grbit));
}
///
/// Enables log truncation for all instances that are part of the snapshot session.
///
///
/// This function should be called only if the snapshot was created with the
/// option. Otherwise, the snapshot
/// session ends after the call to .
///
/// The snapshot identifier.
/// Options for this call.
/// An error code if the call fails.
public int JetOSSnapshotTruncateLog(JET_OSSNAPID snapshot, SnapshotTruncateLogGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsVistaFeatures("JetOSSnapshotTruncateLog");
return Err(NativeMethods.JetOSSnapshotTruncateLog(snapshot.Value, (uint)grbit));
}
///
/// Truncates the log for a specified instance during a snapshot session.
///
///
/// This function should be called only if the snapshot was created with the
/// option. Otherwise, the snapshot
/// session ends after the call to .
///
/// The snapshot identifier.
/// The instance to truncat the log for.
/// Options for this call.
/// An error code if the call fails.
public int JetOSSnapshotTruncateLogInstance(JET_OSSNAPID snapshot, JET_INSTANCE instance, SnapshotTruncateLogGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsVistaFeatures("JetOSSnapshotTruncateLogInstance");
return Err(NativeMethods.JetOSSnapshotTruncateLogInstance(snapshot.Value, instance.Value, (uint)grbit));
}
///
/// Notifies the engine that the snapshot session finished.
///
/// The identifier of the snapshot session.
/// Snapshot end options.
/// An error code.
public int JetOSSnapshotEnd(JET_OSSNAPID snapid, SnapshotEndGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsVistaFeatures("JetOSSnapshotEnd");
return Err(NativeMethods.JetOSSnapshotEnd(snapid.Value, (uint)grbit));
}
///
/// Notifies the engine that it can resume normal IO operations after a
/// freeze period ended with a failed snapshot.
///
/// Identifier of the snapshot session.
/// Options for this call.
/// An error code.
public int JetOSSnapshotAbort(JET_OSSNAPID snapid, SnapshotAbortGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsServer2003Features("JetOSSnapshotAbort");
return Err(NativeMethods.JetOSSnapshotAbort(snapid.Value, (uint)grbit));
}
#endif // !MANAGEDESENT_ON_WSA
#endregion
#region Streaming Backup/Restore
#if !MANAGEDESENT_ON_WSA
///
/// Initiates an external backup while the engine and database are online and active.
///
/// The instance prepare for backup.
/// Backup options.
/// An error code if the call fails.
public int JetBeginExternalBackupInstance(JET_INSTANCE instance, BeginExternalBackupGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetBeginExternalBackupInstance(instance.Value, (uint)grbit));
}
///
/// Closes a file that was opened with JetOpenFileInstance after the
/// data from that file has been extracted using JetReadFileInstance.
///
/// The instance to use.
/// The handle to close.
/// An error code if the call fails.
public int JetCloseFileInstance(JET_INSTANCE instance, JET_HANDLE handle)
{
TraceFunctionCall();
return Err(NativeMethods.JetCloseFileInstance(instance.Value, handle.Value));
}
///
/// 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.
///
/// The instance to end the backup for.
/// An error code if the call fails.
public int JetEndExternalBackupInstance(JET_INSTANCE instance)
{
TraceFunctionCall();
return Err(NativeMethods.JetEndExternalBackupInstance(instance.Value));
}
///
/// 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.
///
/// The instance to end the backup for.
/// Options that specify how the backup ended.
/// An error code if the call fails.
public int JetEndExternalBackupInstance2(JET_INSTANCE instance, EndExternalBackupGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetEndExternalBackupInstance2(instance.Value, (uint)grbit));
}
///
/// Used during a backup initiated by
/// 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 will be considered. These files may
/// subsequently be opened using and read
/// using .
///
///
/// 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.
///
/// The instance to get the information for.
///
/// 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.
///
///
/// Maximum number of characters to retrieve.
///
///
/// Actual size of the file list. If this is greater than maxChars
/// then the list has been truncated.
///
/// An error code if the call fails.
public int JetGetAttachInfoInstance(JET_INSTANCE instance, out string files, int maxChars, out int actualChars)
{
TraceFunctionCall();
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;
}
///
/// Used during a backup initiated by
/// 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 and read using .
///
///
/// 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.
///
/// The instance to get the information for.
///
/// 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.
///
///
/// Maximum number of characters to retrieve.
///
///
/// Actual size of the file list. If this is greater than maxChars
/// then the list has been truncated.
///
/// An error code if the call fails.
public int JetGetLogInfoInstance(JET_INSTANCE instance, out string files, int maxChars, out int actualChars)
{
TraceFunctionCall();
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;
}
///
/// Used during a backup initiated by
/// to query an instance for the names of the transaction log files that can be safely
/// deleted after the backup has successfully completed.
///
///
/// 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.
///
/// The instance to get the information for.
///
/// 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.
///
///
/// Maximum number of characters to retrieve.
///
///
/// Actual size of the file list. If this is greater than maxChars
/// then the list has been truncated.
///
/// An error code if the call fails.
public int JetGetTruncateLogInfoInstance(JET_INSTANCE instance, out string files, int maxChars, out int actualChars)
{
TraceFunctionCall();
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;
}
///
/// 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.
///
/// The instance to use.
/// The file to open.
/// Returns a handle to the file.
/// Returns the least significant 32 bits of the file size.
/// Returns the most significant 32 bits of the file size.
/// An error code if the call fails.
public int JetOpenFileInstance(JET_INSTANCE instance, string file, out JET_HANDLE handle, out long fileSizeLow, out long fileSizeHigh)
{
TraceFunctionCall();
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;
}
///
/// Retrieves the contents of a file opened with .
///
/// The instance to use.
/// The file to read from.
/// The buffer to read into.
/// The size of the buffer.
/// Returns the amount of data read into the buffer.
/// An error code if the call fails.
public int JetReadFileInstance(JET_INSTANCE instance, JET_HANDLE file, byte[] buffer, int bufferSize, out int bytesRead)
{
TraceFunctionCall();
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");
}
}
///
/// 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.
///
/// The instance to truncate.
/// An error code if the call fails.
public int JetTruncateLogInstance(JET_INSTANCE instance)
{
TraceFunctionCall();
return Err(NativeMethods.JetTruncateLogInstance(instance.Value));
}
#endif // !MANAGEDESENT_ON_WSA
#endregion
#region Sessions
///
/// Initialize a new ESENT session.
///
/// The initialized instance to create the session in.
/// Returns the created session.
/// The parameter is not used.
/// The parameter is not used.
/// An error if the call fails.
public int JetBeginSession(JET_INSTANCE instance, out JET_SESID sesid, string username, string password)
{
TraceFunctionCall();
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
}
///
/// 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.
///
/// The session to set the context on.
/// The context to set.
/// An error if the call fails.
public int JetSetSessionContext(JET_SESID sesid, IntPtr context)
{
TraceFunctionCall();
return Err(NativeMethods.JetSetSessionContext(sesid.Value, context));
}
///
/// Disassociates a session from the current thread. This should be
/// used in conjunction with JetSetSessionContext.
///
/// The session to use.
/// An error if the call fails.
public int JetResetSessionContext(JET_SESID sesid)
{
TraceFunctionCall();
return Err(NativeMethods.JetResetSessionContext(sesid.Value));
}
///
/// Ends a session.
///
/// The session to end.
/// This parameter is not used.
/// An error if the call fails.
public int JetEndSession(JET_SESID sesid, EndSessionGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetEndSession(sesid.Value, (uint)grbit));
}
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
///
/// Initialize a new ESE session in the same instance as the given sesid.
///
/// The session to duplicate.
/// Returns the new session.
/// An error if the call fails.
public int JetDupSession(JET_SESID sesid, out JET_SESID newSesid)
{
TraceFunctionCall();
newSesid = JET_SESID.Nil;
return Err(NativeMethods.JetDupSession(sesid.Value, out newSesid.Value));
}
#endif // !MANAGEDESENT_ON_WSA
///
/// 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.
///
///
/// Returns the thread statistics..
///
/// An error code if the operation fails.
public int JetGetThreadStats(out JET_THREADSTATS threadstats)
{
TraceFunctionCall();
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
///
/// Opens a cursor on a previously created table.
///
/// The database session to use.
/// The database to open the table in.
/// The name of the table to open.
/// The parameter is not used.
/// The parameter is not used.
/// Table open options.
/// Returns the opened table.
/// An error if the call fails.
public int JetOpenTable(JET_SESID sesid, JET_DBID dbid, string tablename, byte[] parameters, int parametersLength, OpenTableGrbit grbit, out JET_TABLEID tableid)
{
TraceFunctionCall();
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
}
///
/// Close an open table.
///
/// The session which opened the table.
/// The table to close.
/// An error if the call fails.
public int JetCloseTable(JET_SESID sesid, JET_TABLEID tableid)
{
TraceFunctionCall();
return Err(NativeMethods.JetCloseTable(sesid.Value, tableid.Value));
}
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
///
/// 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.
///
/// The session to use.
/// The cursor to duplicate.
/// The duplicated cursor.
/// Reserved for future use.
/// An error if the call fails.
public int JetDupCursor(JET_SESID sesid, JET_TABLEID tableid, out JET_TABLEID newTableid, DupCursorGrbit grbit)
{
TraceFunctionCall();
newTableid = JET_TABLEID.Nil;
return Err(NativeMethods.JetDupCursor(sesid.Value, tableid.Value, out newTableid.Value, (uint)grbit));
}
///
/// 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.
///
/// The session to use.
/// The table that the statistics will be computed on.
/// An error if the call fails.
public int JetComputeStats(JET_SESID sesid, JET_TABLEID tableid)
{
TraceFunctionCall();
return Err(NativeMethods.JetComputeStats(sesid.Value, tableid.Value));
}
///
/// 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.
///
/// The session to use.
/// The cursor to use.
/// The context handle to be associated with the session or cursor.
/// Set options.
/// An error if the call fails.
public int JetSetLS(JET_SESID sesid, JET_TABLEID tableid, JET_LS ls, LsGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetSetLS(sesid.Value, tableid.Value, ls.Value, (uint)grbit));
}
///
/// 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 . JetGetLS can also
/// be used to simultaneously fetch the current context handle for
/// a cursor or table and reset that context handle.
///
/// The session to use.
/// The cursor to use.
/// Returns the retrieved context handle.
/// Retrieve options.
/// An error if the call fails.
public int JetGetLS(JET_SESID sesid, JET_TABLEID tableid, out JET_LS ls, LsGrbit grbit)
{
TraceFunctionCall();
IntPtr native;
int err = NativeMethods.JetGetLS(sesid.Value, tableid.Value, out native, (uint)grbit);
ls = new JET_LS { Value = native };
return Err(err);
}
///
/// 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.
///
/// The session to use.
/// The cursor to check.
/// An error if the call fails.
public int JetGetCursorInfo(JET_SESID sesid, JET_TABLEID tableid)
{
TraceFunctionCall();
return Err(NativeMethods.JetGetCursorInfo(sesid.Value, tableid.Value, IntPtr.Zero, 0, 0));
}
#endif // !MANAGEDESENT_ON_WSA
#endregion
#region Transactions
///
/// Causes a session to enter a transaction or create a new save point in an existing
/// transaction.
///
/// The session to begin the transaction for.
/// An error if the call fails.
public int JetBeginTransaction(JET_SESID sesid)
{
TraceFunctionCall();
#if MANAGEDESENT_ON_WSA
// 19513 is an arbitrary number.
return this.JetBeginTransaction3(sesid, 19513, BeginTransactionGrbit.None);
#else
return Err(NativeMethods.JetBeginTransaction(sesid.Value));
#endif
}
///
/// Causes a session to enter a transaction or create a new save point in an existing
/// transaction.
///
/// The session to begin the transaction for.
/// Transaction options.
/// An error if the call fails.
public int JetBeginTransaction2(JET_SESID sesid, BeginTransactionGrbit grbit)
{
TraceFunctionCall();
#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
}
///
/// 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.
///
/// The session to commit the transaction for.
/// Commit options.
/// An error if the call fails.
public int JetCommitTransaction(JET_SESID sesid, CommitTransactionGrbit grbit)
{
TraceFunctionCall();
#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
}
///
/// 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.
///
/// The session to rollback the transaction for.
/// Rollback options.
/// An error if the call fails.
public int JetRollback(JET_SESID sesid, RollbackTransactionGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetRollback(sesid.Value, unchecked((uint)grbit)));
}
#endregion
#region DDL
///
/// Create an empty table. The newly created table is opened exclusively.
///
/// The session to use.
/// The database to create the table in.
/// The name of the table to create.
/// Initial number of pages in the table.
///
/// The default density of the table. This is used when doing sequential inserts.
///
/// Returns the tableid of the new table.
/// An error if the call fails.
public int JetCreateTable(JET_SESID sesid, JET_DBID dbid, string table, int pages, int density, out JET_TABLEID tableid)
{
TraceFunctionCall();
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
}
///
/// Deletes a table from a database.
///
/// The session to use.
/// The database to delete the table from.
/// The name of the table to delete.
/// An error if the call fails.
public int JetDeleteTable(JET_SESID sesid, JET_DBID dbid, string table)
{
TraceFunctionCall();
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
}
///
/// Add a new column to an existing table.
///
/// The session to use.
/// The table to add the column to.
/// The name of the column.
/// The definition of the column.
/// The default value of the column.
/// The size of the default value.
/// Returns the columnid of the new column.
/// An error if the call fails.
public int JetAddColumn(JET_SESID sesid, JET_TABLEID tableid, string column, JET_COLUMNDEF columndef, byte[] defaultValue, int defaultValueSize, out JET_COLUMNID columnid)
{
TraceFunctionCall();
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;
}
///
/// Deletes a column from a database table.
///
/// The session to use.
/// A cursor on the table to delete the column from.
/// The name of the column to be deleted.
/// An error if the call fails.
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();
CheckNotNull(column, "column");
return Err(NativeMethods.JetDeleteColumn(sesid.Value, tableid.Value, column));
#endif
}
///
/// Deletes a column from a database table.
///
/// The session to use.
/// A cursor on the table to delete the column from.
/// The name of the column to be deleted.
/// Column deletion options.
/// An error if the call fails.
public int JetDeleteColumn2(JET_SESID sesid, JET_TABLEID tableid, string column, DeleteColumnGrbit grbit)
{
TraceFunctionCall();
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
}
///
/// Creates an index over data in an ESE database. An index can be used to locate
/// specific data quickly.
///
/// The session to use.
/// The table to create the index on.
///
/// Pointer to a null-terminated string that specifies the name of the index to create.
///
/// Index creation options.
///
/// Pointer to a double null-terminated string of null-delimited tokens.
///
///
/// The length, in characters, of szKey including the two terminating nulls.
///
/// Initial B+ tree density.
/// An error if the call fails.
public int JetCreateIndex(
JET_SESID sesid,
JET_TABLEID tableid,
string indexName,
CreateIndexGrbit grbit,
string keyDescription,
int keyDescriptionLength,
int density)
{
TraceFunctionCall();
#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
}
///
/// Creates indexes over data in an ESE database.
///
/// The session to use.
/// The table to create the index on.
/// Array of objects describing the indexes to be created.
/// Number of index description objects.
/// An error code.
public int JetCreateIndex2(
JET_SESID sesid,
JET_TABLEID tableid,
JET_INDEXCREATE[] indexcreates,
int numIndexCreates)
{
TraceFunctionCall();
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
}
///
/// Deletes an index from a database table.
///
/// The session to use.
/// A cursor on the table to delete the index from.
/// The name of the index to be deleted.
/// An error if the call fails.
public int JetDeleteIndex(JET_SESID sesid, JET_TABLEID tableid, string index)
{
TraceFunctionCall();
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
}
///
/// 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.
///
/// The session to use.
///
/// Column definitions for the columns created in the temporary table.
///
/// Number of column definitions.
/// Table creation options.
///
/// Returns the tableid of the temporary table. Closing this tableid
/// frees the resources associated with the temporary table.
///
///
/// 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.
///
/// An error code.
public int JetOpenTempTable(
JET_SESID sesid,
JET_COLUMNDEF[] columns,
int numColumns,
TempTableGrbit grbit,
out JET_TABLEID tableid,
JET_COLUMNID[] columnids)
{
TraceFunctionCall();
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
///
/// 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.
///
/// The session to use.
///
/// Column definitions for the columns created in the temporary table.
///
/// Number of column definitions.
///
/// 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.
///
/// Table creation options.
///
/// Returns the tableid of the temporary table. Closing this tableid
/// frees the resources associated with the temporary table.
///
///
/// 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.
///
/// An error code.
public int JetOpenTempTable2(
JET_SESID sesid,
JET_COLUMNDEF[] columns,
int numColumns,
int lcid,
TempTableGrbit grbit,
out JET_TABLEID tableid,
JET_COLUMNID[] columnids)
{
TraceFunctionCall();
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
///
/// 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.
///
/// The session to use.
///
/// Column definitions for the columns created in the temporary table.
///
/// Number of column definitions.
///
/// 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.
///
/// Table creation options.
///
/// Returns the tableid of the temporary table. Closing this tableid
/// frees the resources associated with the temporary table.
///
///
/// 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.
///
/// An error code.
public int JetOpenTempTable3(
JET_SESID sesid,
JET_COLUMNDEF[] columns,
int numColumns,
JET_UNICODEINDEX unicodeindex,
TempTableGrbit grbit,
out JET_TABLEID tableid,
JET_COLUMNID[] columnids)
{
TraceFunctionCall();
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;
}
///
/// 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.
///
///
/// Introduced in Windows Vista.
///
/// The session to use.
///
/// 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.
///
/// An error code.
public int JetOpenTemporaryTable(JET_SESID sesid, JET_OPENTEMPORARYTABLE temporarytable)
{
TraceFunctionCall();
#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
}
///
/// Creates a table, adds columns, and indices on that table.
///
/// The session to use.
/// The database to which to add the new table.
/// Object describing the table to create.
/// An error if the call fails.
public int JetCreateTableColumnIndex3(
JET_SESID sesid,
JET_DBID dbid,
JET_TABLECREATE tablecreate)
{
TraceFunctionCall();
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
///
/// Retrieves information about a table column.
///
/// The session to use.
/// The table containing the column.
/// The name of the column.
/// Filled in with information about the column.
/// An error if the call fails.
public int JetGetTableColumnInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string columnName,
out JET_COLUMNDEF columndef)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about a table column.
///
/// The session to use.
/// The table containing the column.
/// The columnid of the column.
/// Filled in with information about the column.
/// An error if the call fails.
public int JetGetTableColumnInfo(
JET_SESID sesid,
JET_TABLEID tableid,
JET_COLUMNID columnid,
out JET_COLUMNDEF columndef)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about a table column, given its and name.
///
/// The session to use.
/// The table containing the column.
/// The name of the column.
/// Filled in with information about the column.
/// An error if the call fails.
public int JetGetTableColumnInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string columnName,
out JET_COLUMNBASE columnbase)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about a table column, given its and .
///
/// The session to use.
/// The table containing the column.
/// The columnid of the column.
/// Filled in with information about the column.
/// An error if the call fails.
public int JetGetTableColumnInfo(
JET_SESID sesid,
JET_TABLEID tableid,
JET_COLUMNID columnid,
out JET_COLUMNBASE columnbase)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about all columns in the table.
///
/// The session to use.
/// The table containing the column.
/// The parameter is ignored.
/// Additional options for JetGetTableColumnInfo.
/// Filled in with information about the columns in the table.
/// An error if the call fails.
public int JetGetTableColumnInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string ignored,
ColInfoGrbit grbit,
out JET_COLUMNLIST columnlist)
{
TraceFunctionCall();
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
///
/// Retrieves information about a table column.
///
/// The session to use.
/// The database that contains the table.
/// The name of the table containing the column.
/// The name of the column.
/// Filled in with information about the column.
/// An error if the call fails.
public int JetGetColumnInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string columnName,
out JET_COLUMNDEF columndef)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about all columns in a table.
///
/// The session to use.
/// The database that contains the table.
/// The name of the table containing the column.
/// This parameter is ignored.
/// Filled in with information about the columns in the table.
/// An error if the call fails.
public int JetGetColumnInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string ignored,
out JET_COLUMNLIST columnlist)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about a column in a table.
///
/// The session to use.
/// The database that contains the table.
/// The name of the table containing the column.
/// The name of the column.
/// Filled in with information about the columns in the table.
/// An error if the call fails.
public int JetGetColumnInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string columnName,
out JET_COLUMNBASE columnbase)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about a column.
///
/// The session to use.
/// The database that contains the table.
/// The name of the table containing the column.
/// The columnid of the column.
/// Filled in with information about the columns in the table.
/// An error if the call fails.
public int JetGetColumnInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
JET_COLUMNID columnid,
out JET_COLUMNBASE columnbase)
{
TraceFunctionCall();
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
///
/// Retrieves information about database objects.
///
/// The session to use.
/// The database to use.
/// Filled in with information about the objects in the database.
/// An error if the call fails.
public int JetGetObjectInfo(JET_SESID sesid, JET_DBID dbid, out JET_OBJECTLIST objectlist)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about database objects.
///
/// The session to use.
/// The database to use.
/// The type of the object.
/// The object name about which to retrieve information.
/// Filled in with information about the objects in the database.
/// An error if the call fails.
public int JetGetObjectInfo(
JET_SESID sesid,
JET_DBID dbid,
JET_objtyp objtyp,
string objectName,
out JET_OBJECTINFO objectinfo)
{
TraceFunctionCall();
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
///
/// 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 . It can
/// also be used to discover the properties of that index using
/// JetGetTableIndexInfo.
///
/// The session to use.
/// The cursor to get the index name for.
/// Returns the name of the index.
///
/// The maximum length of the index name. Index names are no more than
/// Api.MaxNameLength characters.
///
/// An error if the call fails.
public int JetGetCurrentIndex(JET_SESID sesid, JET_TABLEID tableid, out string indexName, int maxNameLength)
{
TraceFunctionCall();
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
///
/// Retrieves various pieces of information about a table in a database.
///
///
/// This overload is used with .
///
/// The session to use.
/// The table to retrieve information about.
/// Retrieved information.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out JET_OBJECTINFO result, JET_TblInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves various pieces of information about a table in a database.
///
///
/// This overload is used with and
/// .
///
/// The session to use.
/// The table to retrieve information about.
/// Retrieved information.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out string result, JET_TblInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves various pieces of information about a table in a database.
///
///
/// This overload is used with .
///
/// The session to use.
/// The table to retrieve information about.
/// Retrieved information.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out JET_DBID result, JET_TblInfo infoLevel)
{
TraceFunctionCall();
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
}
}
///
/// Retrieves various pieces of information about a table in a database.
///
///
/// This overload is used with and
/// .
///
/// The session to use.
/// The table to retrieve information about.
/// Retrieved information.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, int[] result, JET_TblInfo infoLevel)
{
TraceFunctionCall();
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
}
}
///
/// Retrieves various pieces of information about a table in a database.
///
///
/// This overload is used with and
/// .
///
/// The session to use.
/// The table to retrieve information about.
/// Retrieved information.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid, out int result, JET_TblInfo infoLevel)
{
TraceFunctionCall();
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
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The database to use.
/// The name of the table to retrieve index information about.
/// The name of the index to retrieve information about.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetIndexInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string indexname,
out ushort result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The database to use.
/// The name of the table to retrieve index information about.
/// The name of the index to retrieve information about.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetIndexInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string indexname,
out int result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The database to use.
/// The name of the table to retrieve index information about.
/// The name of the index to retrieve information about.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetIndexInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string indexname,
out JET_INDEXID result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The database to use.
/// The name of the table to retrieve index information about.
/// The name of the index to retrieve information about.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetIndexInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string indexname,
out JET_INDEXLIST result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The database to use.
/// The name of the table to retrieve index information about.
/// The name of the index to retrieve information about.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetIndexInfo(
JET_SESID sesid,
JET_DBID dbid,
string tablename,
string indexname,
out string result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The table to retrieve index information about.
/// The name of the index.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out ushort result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The table to retrieve index information about.
/// The name of the index.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out int result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The table to retrieve index information about.
/// The name of the index.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out JET_INDEXID result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The table to retrieve index information about.
/// The name of the index.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out JET_INDEXLIST result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
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;
}
///
/// Retrieves information about indexes on a table.
///
/// The session to use.
/// The table to retrieve index information about.
/// The name of the index.
/// Filled in with information about indexes on the table.
/// The type of information to retrieve.
/// An error if the call fails.
public int JetGetTableIndexInfo(
JET_SESID sesid,
JET_TABLEID tableid,
string indexname,
out string result,
JET_IdxInfo infoLevel)
{
TraceFunctionCall();
// 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
///
/// Changes the name of an existing table.
///
/// The session to use.
/// The database containing the table.
/// The name of the table.
/// The new name of the table.
/// An error if the call fails.
public int JetRenameTable(JET_SESID sesid, JET_DBID dbid, string tableName, string newTableName)
{
TraceFunctionCall();
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
}
///
/// Changes the name of an existing column.
///
/// The session to use.
/// The table containing the column.
/// The name of the column.
/// The new name of the column.
/// Column rename options.
/// An error if the call fails.
public int JetRenameColumn(JET_SESID sesid, JET_TABLEID tableid, string name, string newName, RenameColumnGrbit grbit)
{
TraceFunctionCall();
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
///
/// Changes the default value of an existing column.
///
/// The session to use.
/// The database containing the column.
/// The name of the table containing the column.
/// The name of the column.
/// The new default value.
/// Size of the new default value.
/// Column default value options.
/// An error if the call fails.
public int JetSetColumnDefaultValue(
JET_SESID sesid, JET_DBID dbid, string tableName, string columnName, byte[] data, int dataSize, SetColumnDefaultValueGrbit grbit)
{
TraceFunctionCall();
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
///
/// 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 .
///
/// The session to use.
/// The cursor to position.
/// The bookmark used to position the cursor.
/// The size of the bookmark. /// An error if the call fails.
public int JetGotoBookmark(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize)
{
TraceFunctionCall();
CheckNotNull(bookmark, "bookmark");
CheckDataSize(bookmark, bookmarkSize, "bookmarkSize");
return
Err(
NativeMethods.JetGotoBookmark(
sesid.Value, tableid.Value, bookmark, checked((uint)bookmarkSize)));
}
///
/// 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 .
///
/// The session to use.
/// The table cursor to position.
/// The buffer that contains the secondary key.
/// The size of the secondary key.
/// The buffer that contains the primary key.
/// The size of the primary key.
/// Options for positioning the bookmark.
/// An error if the call fails.
public int JetGotoSecondaryIndexBookmark(
JET_SESID sesid,
JET_TABLEID tableid,
byte[] secondaryKey,
int secondaryKeySize,
byte[] primaryKey,
int primaryKeySize,
GotoSecondaryIndexBookmarkGrbit grbit)
{
TraceFunctionCall();
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));
}
///
/// Constructs search keys that may then be used by and .
///
///
/// The MakeKey functions provide datatype-specific make key functionality.
///
/// The session to use.
/// The cursor to create the key on.
/// Column data for the current key column of the current index.
/// Size of the data.
/// Key options.
/// An error if the call fails.
public int JetMakeKey(JET_SESID sesid, JET_TABLEID tableid, IntPtr data, int dataSize, MakeKeyGrbit grbit)
{
TraceFunctionCall();
CheckNotNegative(dataSize, "dataSize");
return Err(NativeMethods.JetMakeKey(sesid.Value, tableid.Value, data, checked((uint)dataSize), unchecked((uint)grbit)));
}
///
/// 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.
///
/// The session to use.
/// The cursor to position.
/// Seek options.
/// An error or warning..
public int JetSeek(JET_SESID sesid, JET_TABLEID tableid, SeekGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetSeek(sesid.Value, tableid.Value, unchecked((uint)grbit)));
}
///
/// 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.
///
/// The session to use for the call.
/// The cursor to position.
/// An offset which indicates how far to move the cursor.
/// Move options.
/// An error if the call fails.
public int JetMove(JET_SESID sesid, JET_TABLEID tableid, int numRows, MoveGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetMove(sesid.Value, tableid.Value, numRows, unchecked((uint)grbit)));
}
///
/// Temporarily limits the set of index entries that the cursor can walk using
/// 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.
///
/// The session to use.
/// The cursor to set the index range on.
/// Index range options.
/// An error if the call fails.
public int JetSetIndexRange(JET_SESID sesid, JET_TABLEID tableid, SetIndexRangeGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetSetIndexRange(sesid.Value, tableid.Value, unchecked((uint)grbit)));
}
///
/// 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.
///
/// The session to use.
///
/// An the index ranges to intersect. The tableids in the ranges
/// must have index ranges set on them.
///
///
/// The number of index ranges.
///
///
/// Returns information about the temporary table containing the intersection results.
///
/// Intersection options.
/// An error if the call fails.
public int JetIntersectIndexes(
JET_SESID sesid,
JET_INDEXRANGE[] ranges,
int numRanges,
out JET_RECORDLIST recordlist,
IntersectIndexesGrbit grbit)
{
TraceFunctionCall();
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;
}
///
/// Set the current index of a cursor.
///
/// The session to use.
/// The cursor to set the index on.
///
/// The name of the index to be selected. If this is null or empty the primary
/// index will be selected.
///
/// An error if the call fails.
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();
// 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
}
///
/// Set the current index of a cursor.
///
/// The session to use.
/// The cursor to set the index on.
///
/// The name of the index to be selected. If this is null or empty the primary
/// index will be selected.
///
///
/// Set index options.
///
/// An error if the call fails.
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();
// 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
}
///
/// Set the current index of a cursor.
///
/// The session to use.
/// The cursor to set the index on.
///
/// The name of the index to be selected. If this is null or empty the primary
/// index will be selected.
///
///
/// Set index options.
///
///
/// 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 . When
/// this parameter is not present or is set to zero, its value is presumed
/// to be 1.
///
/// An error if the call fails.
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();
// 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
}
///
/// Set the current index of a cursor.
///
/// The session to use.
/// The cursor to set the index on.
///
/// The name of the index to be selected. If this is null or empty the primary
/// index will be selected.
///
///
/// The id of the index to select. This id can be obtained using JetGetIndexInfo
/// or JetGetTableIndexInfo with the option.
///
///
/// Set index options.
///
///
/// 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 . When
/// this parameter is not present or is set to zero, its value is presumed
/// to be 1.
///
/// An error if the call fails.
public int JetSetCurrentIndex4(
JET_SESID sesid,
JET_TABLEID tableid,
string index,
JET_INDEXID indexid,
SetCurrentIndexGrbit grbit,
int itagSequence)
{
TraceFunctionCall();
// 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
}
///
/// 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.
///
/// The session to use.
/// The cursor to count the records in.
/// Returns the number of records.
///
/// The maximum number of records to count.
///
/// An error if the call fails.
public int JetIndexRecordCount(JET_SESID sesid, JET_TABLEID tableid, out int numRecords, int maxRecordsToCount)
{
TraceFunctionCall();
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;
}
///
/// 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.
///
/// The session to use.
/// The cursor to count the records in.
/// Returns the number of records.
///
/// The maximum number of records to count.
///
/// An error if the call fails.
public int JetIndexRecordCount2(JET_SESID sesid, JET_TABLEID tableid, out long numRecords, long maxRecordsToCount)
{
TraceFunctionCall();
CheckNotNegative(maxRecordsToCount, "maxRecordsToCount");
ulong crec = 0;
int err = Err(NativeMethods.JetIndexRecordCount2(sesid.Value, tableid.Value, out crec, unchecked((ulong)maxRecordsToCount)));
numRecords = checked((long)crec);
return err;
}
///
/// 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.
///
/// The session to use.
/// The cursor that will be accessing the data.
/// Reserved for future use.
/// An error if the call fails.
public int JetSetTableSequential(JET_SESID sesid, JET_TABLEID tableid, SetTableSequentialGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetSetTableSequential(sesid.Value, tableid.Value, (uint)grbit));
}
///
/// 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.
///
/// The session to use.
/// The cursor that was accessing the data.
/// Reserved for future use.
/// An error if the call fails.
public int JetResetTableSequential(JET_SESID sesid, JET_TABLEID tableid, ResetTableSequentialGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetResetTableSequential(sesid.Value, tableid.Value, (uint)grbit));
}
///
/// Returns the fractional position of the current record in the current index
/// in the form of a JET_RECPOS structure.
///
/// The session to use.
/// The cursor positioned on the record.
/// Returns the approximate fractional position of the record.
/// An error if the call fails.
public int JetGetRecordPosition(JET_SESID sesid, JET_TABLEID tableid, out JET_RECPOS recpos)
{
TraceFunctionCall();
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;
}
///
/// Moves a cursor to a new location that is a fraction of the way through
/// the current index.
///
/// The session to use.
/// The cursor to position.
/// The approximate position to move to.
/// An error if the call fails.
public int JetGotoPosition(JET_SESID sesid, JET_TABLEID tableid, JET_RECPOS recpos)
{
TraceFunctionCall();
NATIVE_RECPOS native = recpos.GetNativeRecpos();
return Err(NativeMethods.JetGotoPosition(sesid.Value, tableid.Value, ref native));
}
///
/// 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.
///
/// The session to use.
/// The table to issue the prereads against.
///
/// The keys to preread. The keys must be sorted.
///
/// The lengths of the keys to preread.
///
/// The index of the first key in the keys array to read.
///
///
/// The maximum number of keys to preread.
///
///
/// Returns the number of keys to actually preread.
///
///
/// Preread options. Used to specify the direction of the preread.
///
/// An error or warning.
public int JetPrereadKeys(
JET_SESID sesid,
JET_TABLEID tableid,
byte[][] keys,
int[] keyLengths,
int keyIndex,
int keyCount,
out int keysPreread,
PrereadKeysGrbit grbit)
{
TraceFunctionCall();
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
///
/// 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 .
/// The bookmark will be no longer than
/// bytes.
///
/// The session to use.
/// The cursor to retrieve the bookmark from.
/// Buffer to contain the bookmark.
/// Size of the bookmark buffer.
/// Returns the actual size of the bookmark.
/// An error if the call fails.
public int JetGetBookmark(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize)
{
TraceFunctionCall();
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;
}
///
/// 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.
///
/// The session to use.
/// The cursor to retrieve the bookmark from.
/// Output buffer for the secondary key.
/// Size of the secondary key buffer.
/// Returns the size of the secondary key.
/// Output buffer for the primary key.
/// Size of the primary key buffer.
/// Returns the size of the primary key.
/// Options for the call.
/// An error if the call fails.
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();
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;
}
///
/// Retrieves the key for the index entry at the current position of a cursor.
///
/// The session to use.
/// The cursor to retrieve the key from.
/// The buffer to retrieve the key into.
/// The size of the buffer.
/// Returns the actual size of the data.
/// Retrieve key options.
/// An error if the call fails.
public int JetRetrieveKey(JET_SESID sesid, JET_TABLEID tableid, byte[] data, int dataSize, out int actualDataSize, RetrieveKeyGrbit grbit)
{
TraceFunctionCall();
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;
}
///
/// 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.
///
///
/// The RetrieveColumnAs functions provide datatype-specific retrieval functions.
///
/// The session to use.
/// The cursor to retrieve the column from.
/// The columnid to retrieve.
/// The data buffer to be retrieved into.
/// The size of the data buffer.
/// Returns the actual size of the data buffer.
/// Retrieve column options.
///
/// 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).
///
/// An error or warning.
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();
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;
}
///
/// The JetRetrieveColumns function retrieves multiple column values
/// from the current record in a single operation. An array of
/// 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.
///
/// The session to use.
/// The cursor to retrieve columns from.
///
/// 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.
///
///
/// Number of structures in the array given by retrievecolumns.
///
///
/// An error or warning.
///
public unsafe int JetRetrieveColumns(JET_SESID sesid, JET_TABLEID tableid, NATIVE_RETRIEVECOLUMN* retrievecolumns, int numColumns)
{
TraceFunctionCall();
return Err(NativeMethods.JetRetrieveColumns(sesid.Value, tableid.Value, retrievecolumns, checked((uint)numColumns)));
}
///
/// 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.
///
/// The session to use.
/// The cursor to retrieve data from.
/// The numbers of JET_ENUMCOLUMNIDS.
///
/// An optional array of column IDs, each with an optional array of itagSequence
/// numbers to enumerate.
///
///
/// Returns the number of column values retrieved.
///
///
/// Returns the enumerated column values.
///
///
/// Callback used to allocate memory.
///
///
/// Context for the allocation callback.
///
///
/// 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.
///
/// Retrieve options.
/// A warning, error or success.
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();
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);
}
}
///
/// Efficiently retrieves a set of columns and their values from the
/// current record of a cursor or the copy buffer of that cursor.
///
/// The session to use.
/// The cursor to retrieve data from.
/// Enumerate options.
/// The discovered columns and their values.
/// A warning or success.
public int JetEnumerateColumns(
JET_SESID sesid,
JET_TABLEID tableid,
EnumerateColumnsGrbit grbit,
out IEnumerable 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
///
/// Retrieves record size information from the desired location.
///
/// The session to use.
///
/// The cursor that will be used for the API call. The cursor must be
/// positioned on a record, or have an update prepared.
///
/// Returns the size of the record.
/// Call options.
/// A warning, error or success.
public int JetGetRecordSize(JET_SESID sesid, JET_TABLEID tableid, ref JET_RECSIZE recsize, GetRecordSizeGrbit grbit)
{
TraceFunctionCall();
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
///
/// Deletes the current record in a database table.
///
/// The session that opened the cursor.
/// The cursor on a database table. The current row will be deleted.
/// An error if the call fails.
public int JetDelete(JET_SESID sesid, JET_TABLEID tableid)
{
TraceFunctionCall();
return Err(NativeMethods.JetDelete(sesid.Value, tableid.Value));
}
///
/// Prepare a cursor for update.
///
/// The session which is starting the update.
/// The cursor to start the update for.
/// The type of update to prepare.
/// An error if the call fails.
public int JetPrepareUpdate(JET_SESID sesid, JET_TABLEID tableid, JET_prep prep)
{
TraceFunctionCall();
return Err(NativeMethods.JetPrepareUpdate(sesid.Value, tableid.Value, unchecked((uint)prep)));
}
///
/// 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
/// .
///
/// The session which started the update.
/// The cursor to update. An update should be prepared.
/// Returns the bookmark of the updated record. This can be null.
/// The size of the bookmark buffer.
/// Returns the actual size of the bookmark.
///
/// JetUpdate is the final step in performing an insert or an update. The update is begun by
/// calling 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.
///
/// An error if the call fails.
public int JetUpdate(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize)
{
TraceFunctionCall();
#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
}
///
/// 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
/// .
///
/// The session which started the update.
/// The cursor to update. An update should be prepared.
/// Returns the bookmark of the updated record. This can be null.
/// The size of the bookmark buffer.
/// Returns the actual size of the bookmark.
/// Update options.
///
/// JetUpdate is the final step in performing an insert or an update. The update is begun by
/// calling 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.
///
/// An error if the call fails.
public int JetUpdate2(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize, out int actualBookmarkSize, UpdateGrbit grbit)
{
TraceFunctionCall();
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;
}
///
/// 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
/// or ).
///
///
/// The SetColumn methods provide datatype-specific overrides which may be more efficient.
///
/// The session which is performing the update.
/// The cursor to update. An update should be prepared.
/// The columnid to set.
/// The data to set.
/// The size of data to set.
/// SetColumn options.
/// Used to specify itag or long-value offset.
/// An error if the call fails.
public int JetSetColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, SetColumnGrbit grbit, JET_SETINFO setinfo)
{
TraceFunctionCall();
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));
}
///
/// Allows an application to set multiple column values in a single
/// operation. An array of 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.
///
/// The session to use.
/// The cursor to set the columns on.
///
/// An array of structures describing the
/// data to set.
///
///
/// Number of entries in the setcolumns parameter.
///
/// An error code or warning.
public unsafe int JetSetColumns(JET_SESID sesid, JET_TABLEID tableid, NATIVE_SETCOLUMN* setcolumns, int numColumns)
{
TraceFunctionCall();
return Err(NativeMethods.JetSetColumns(sesid.Value, tableid.Value, setcolumns, checked((uint)numColumns)));
}
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
///
/// 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.
///
/// The session to use.
/// The cursor to use. A lock will be acquired on the current record.
/// Lock options, use this to specify which type of lock to obtain.
/// An error if the call fails.
public int JetGetLock(JET_SESID sesid, JET_TABLEID tableid, GetLockGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetGetLock(sesid.Value, tableid.Value, unchecked((uint)grbit)));
}
#endif // !MANAGEDESENT_ON_WSA
///
/// Performs an atomic addition operation on one column. This function allows
/// multiple sessions to update the same record concurrently without conflicts.
///
/// The session to use.
/// The cursor to update.
///
/// The column to update. This must be an escrow updatable column.
///
/// The buffer containing the addend.
/// The size of the addend.
///
/// An output buffer that will recieve the current value of the column. This buffer
/// can be null.
///
/// The size of the previousValue buffer.
/// Returns the actual size of the previousValue.
/// Escrow update options.
/// An error code if the operation fails.
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();
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
///
/// 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 .
///
/// The session to use.
///
/// A cursor opened on the table that the callback should be
/// registered on.
///
///
/// The callback reasons for which the application wishes to receive notifications.
///
/// The callback function.
/// A context that will be given to the callback.
///
/// A handle that can later be used to cancel the registration of the given
/// callback function using .
///
/// An error if the call fails.
public int JetRegisterCallback(
JET_SESID sesid,
JET_TABLEID tableid,
JET_cbtyp cbtyp,
JET_CALLBACK callback,
IntPtr context,
out JET_HANDLE callbackId)
{
TraceFunctionCall();
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));
}
///
/// Configures the database engine to stop issuing notifications to the
/// application as previously requested through
/// .
///
/// The session to use.
///
/// A cursor opened on the table that the callback should be
/// registered on.
///
///
/// The callback reasons for which the application no longer wishes to receive notifications.
///
///
/// The handle of the registered callback that was returned by .
///
/// An error if the call fails.
public int JetUnregisterCallback(JET_SESID sesid, JET_TABLEID tableid, JET_cbtyp cbtyp, JET_HANDLE callbackId)
{
TraceFunctionCall();
this.callbackWrappers.Collect();
return Err(NativeMethods.JetUnregisterCallback(
sesid.Value,
tableid.Value,
unchecked((uint)cbtyp),
callbackId.Value));
}
#endregion
#region Online Maintenance
///
/// Starts and stops database defragmentation tasks that improves data
/// organization within a database.
///
/// The session to use for the call.
/// The database to be defragmented.
///
/// Under some options defragmentation is performed for the entire database described by the given
/// database ID, and other options (such as ) require
/// the name of the table to defragment.
///
///
/// 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 ).
///
///
/// 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 ).
///
/// Defragmentation options.
/// An error code.
/// .
/// .
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();
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
}
///
/// Starts and stops database defragmentation tasks that improves data
/// organization within a database.
///
/// The session to use for the call.
/// The database to be defragmented.
///
/// Under some options defragmentation is performed for the entire database described by the given
/// database ID, and other options (such as ) require
/// the name of the table to defragment.
///
/// Defragmentation options.
/// An error code.
/// .
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();
int err = Err(NativeMethods.JetDefragment(
sesid.Value, dbid.Value, tableName, IntPtr.Zero, IntPtr.Zero, (uint)grbit));
return err;
#endif
}
///
/// Starts and stops database defragmentation tasks that improves data
/// organization within a database.
///
/// The session to use for the call.
/// The database to be defragmented.
///
/// Under some options defragmentation is performed for the entire database described by the given
/// database ID, and other options (such as ) require
/// the name of the table to defragment.
///
///
/// 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 ).
///
///
/// 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 ).
///
/// Callback function that defrag uses to report progress.
/// Defragmentation options.
/// An error code or warning.
/// .
public int JetDefragment2(
JET_SESID sesid,
JET_DBID dbid,
string tableName,
ref int passes,
ref int seconds,
JET_CALLBACK callback,
DefragGrbit grbit)
{
TraceFunctionCall();
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
///
/// Starts and stops database defragmentation tasks that improves data
/// organization within a database.
///
/// The session to use for the call.
/// The database to be defragmented.
///
/// Under some options defragmentation is performed for the entire database described by the given
/// database ID, and other options (such as ) require
/// the name of the table to defragment.
///
/// Callback function that defrag uses to report progress.
/// Defragmentation options.
/// An error code or warning.
/// .
public int Defragment2(
JET_SESID sesid,
JET_DBID dbid,
string tableName,
JET_CALLBACK callback,
DefragGrbit grbit)
{
TraceFunctionCall();
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
///
/// Performs idle cleanup tasks or checks the version store status in ESE.
///
/// The session to use.
/// A combination of JetIdleGrbit flags.
/// An error code if the operation fails.
public int JetIdle(JET_SESID sesid, IdleGrbit grbit)
{
TraceFunctionCall();
return Err(NativeMethods.JetIdle(sesid.Value, (uint)grbit));
}
#endif // !MANAGEDESENT_ON_WSA
#endregion
#region Misc
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
///
/// Crash dump options for Watson.
///
/// Crash dump options.
/// An error code.
public int JetConfigureProcessForCrashDump(CrashDumpGrbit grbit)
{
TraceFunctionCall();
this.CheckSupportsWindows7Features("JetConfigureProcessForCrashDump");
return Err(NativeMethods.JetConfigureProcessForCrashDump((uint)grbit));
}
///
/// Frees memory that was allocated by a database engine call.
///
///
/// The buffer allocated by a call to the database engine.
/// is acceptable, and will be ignored.
///
/// An error code.
public int JetFreeBuffer(IntPtr buffer)
{
TraceFunctionCall();
return Err(NativeMethods.JetFreeBuffer(buffer));
}
#endif // !MANAGEDESENT_ON_WSA
#endregion
#region Internal Helper Methods
///
/// Given the size returned by ESENT, get the size
/// to return to the user.
///
/// The size returned by ESENT.
/// The bookmark size to return to the user.
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
///
/// Make sure the data, dataOffset and dataSize arguments match.
///
/// The data buffer.
/// The offset into the data.
/// The name of the offset argument.
/// The size of the data.
/// The name of the size argument.
/// The type of the data.
private static void CheckDataSize(ICollection 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");
}
}
///
/// Make sure the data and dataSize arguments match.
///
/// The data buffer.
/// The size of the data.
/// The name of the size argument.
/// The type of the data.
private static void CheckDataSize(ICollection data, int dataSize, string argumentName)
{
CheckDataSize(data, 0, string.Empty, dataSize, argumentName);
}
///
/// Make sure the given object isn't null. If it is
/// then throw an ArgumentNullException.
///
/// The object to check.
/// The name of the parameter.
private static void CheckNotNull(object o, string paramName)
{
if (null == o)
{
Trace.WriteLineIf(TraceSwitch.TraceError, "CheckNotNull failed");
throw new ArgumentNullException(paramName);
}
}
///
/// Make sure the given integer isn't negative. If it is
/// then throw an ArgumentOutOfRangeException.
///
/// The integer to check.
/// The name of the parameter.
private static void CheckNotNegative(long i, string paramName)
{
if (i < 0)
{
Trace.WriteLineIf(TraceSwitch.TraceError, "CheckNotNegative failed");
throw new ArgumentOutOfRangeException(paramName, i, "cannot be negative");
}
}
///
/// Used when an unsupported API method is called. This
/// logs an error and returns an InvalidOperationException.
///
/// The name of the method.
/// The exception to throw.
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);
}
///
/// Trace a call to an ESENT function.
///
/// The name of the function being called.
[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([System.Runtime.CompilerServices.CallerMemberName] string function = null)
{
Trace.WriteLineIf(TraceSwitch.TraceInfo, function);
}
///
/// Can be used to trap ESENT errors.
///
/// The error being returned.
/// The error.
private static int Err(int err)
{
TraceErr(err);
return err;
}
///
/// Trace an error generated by a call to ESENT.
///
/// The error to trace.
[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
///
/// Convert managed JET_ENUMCOLUMNID objects to NATIVE_ENUMCOLUMNID
/// structures.
///
/// The columnids to convert.
/// The number of columnids to convert.
/// The array to store the converted columnids.
/// The total number of tag entries in the converted structures.
private static unsafe int ConvertEnumColumnids(IList 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;
}
///
/// Convert managed rgtagSequence to unmanaged rgtagSequence.
///
/// The columnids to convert.
/// The number of columnids to covert.
/// The unmanaged columnids to add the tags to.
///
/// Memory to use for converted rgtagSequence. This should be large enough to
/// hold all columnids.
///
private static unsafe void ConvertEnumColumnidTags(IList 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;
}
}
///
/// Convert the native (unmanaged) results of JetEnumerateColumns to
/// managed objects. This uses the allocator callback to free some
/// memory as the data is converted.
///
/// The allocator callback used.
/// The allocator callback context.
/// Number of NATIVE_ENUMCOLUMN structures returned.
/// NATIVE_ENUMCOLUMN structures.
/// Returns the number of converted JET_ENUMCOLUMN objects.
/// Returns the convertd column values.
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;
}
///
/// Make an array of native columndefs from JET_COLUMNDEFs.
///
/// Columndefs to convert.
/// Number of columndefs to convert.
/// An array of native columndefs.
private static NATIVE_COLUMNDEF[] GetNativecolumndefs(IList columns, int numColumns)
{
var nativecolumndefs = new NATIVE_COLUMNDEF[numColumns];
for (int i = 0; i < numColumns; ++i)
{
nativecolumndefs[i] = columns[i].GetNativeColumndef();
}
return nativecolumndefs;
}
///
/// Make native conditionalcolumn structures from the managed ones.
///
/// The conditional columns to convert.
/// Wehether to convert the strings with UTF-16.
/// The handle collection used to pin the data.
/// Pinned native versions of the conditional columns.
private static IntPtr GetNativeConditionalColumns(
IList 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);
}
///
/// Make native columncreate structures from the managed ones.
///
/// Column create structures to convert.
/// Wehether to convert the strings with UTF-16.
/// The handle collection used to pin the data.
/// Pinned native versions of the column creates.
private static IntPtr GetNativeColumnCreates(
IList 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
///
/// Make native indexcreate structures from the managed ones.
/// Only supports Ascii data, since it could be used on XP.
///
/// Index create structures to convert.
/// The handle collection used to pin the data.
/// Pinned native versions of the index creates.
private static unsafe JET_INDEXCREATE.NATIVE_INDEXCREATE[] GetNativeIndexCreates(
IList 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;
}
///
/// Make native indexcreate structures from the managed ones.
/// Only supports Unicode data, since it was introduced in Vista.
///
/// Index create structures to convert.
/// The handle collection used to pin the data.
/// Pinned native versions of the index creates.
private static unsafe JET_INDEXCREATE.NATIVE_INDEXCREATE1[] GetNativeIndexCreate1s(
IList 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;
}
///
/// Make native indexcreate structures from the managed ones.
/// Only supports Unicode data, since it was introduced in Win7.
///
/// Index create structures to convert.
/// The handle collection used to pin the data.
/// Pinned native versions of the index creates.
private static unsafe JET_INDEXCREATE.NATIVE_INDEXCREATE2[] GetNativeIndexCreate2s(
IList 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
///
/// Set managed columnids from unmanaged columnids. This also sets the columnids
/// in the columndefs.
///
/// The column definitions.
/// The columnids to set.
/// The native columnids.
/// The number of columnids to set.
private static void SetColumnids(IList columns, IList columnids, IList 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
///
/// Creates indexes over data in an ESE database.
///
/// The session to use.
/// The table to create the index on.
/// Array of objects describing the indexes to be created.
/// Number of index description objects.
/// An error code.
private static int CreateIndexes(JET_SESID sesid, JET_TABLEID tableid, IList 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();
}
}
///
/// Creates indexes over data in an ESE database.
///
/// The session to use.
/// The table to create the index on.
/// Array of objects describing the indexes to be created.
/// Number of index description objects.
/// An error code.
private static int CreateIndexes1(JET_SESID sesid, JET_TABLEID tableid, IList 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();
}
}
///
/// Creates indexes over data in an ESE database.
///
/// The session to use.
/// The table to create the index on.
/// Array of objects describing the indexes to be created.
/// Number of index description objects.
/// An error code.
private static int CreateIndexes2(JET_SESID sesid, JET_TABLEID tableid, IList 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();
}
}
///
/// Creates a table, adds columns, and indices on that table.
///
/// The session to use.
/// The database to which to add the new table.
/// Object describing the table to create.
/// An error if the call fails.
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(ref 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();
}
}
}
///
/// Convert native instance info structures to managed, treating the
/// unmanaged strings as Unicode.
///
/// The number of native structures.
///
/// A pointer to the native structures. This pointer will be freed with JetFreeBuffer.
///
///
/// An array of JET_INSTANCE_INFO structures created from the unmanaged.
///
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;
}
///
/// Convert native instance info structures to managed, treating the
/// unmanaged string as Unicode.
///
/// The number of native structures.
///
/// A pointer to the native structures. This pointer will be freed with JetFreeBuffer.
///
///
/// An array of JET_INSTANCE_INFO structures created from the unmanaged.
///
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
///
/// Check that ESENT supports Server 2003 features. Throws an exception if Server 2003 features
/// aren't supported.
///
/// The API that is being called.
private void CheckSupportsServer2003Features(string api)
{
if (!this.Capabilities.SupportsServer2003Features)
{
throw UnsupportedApiException(api);
}
}
///
/// Check that ESENT supports Vista features. Throws an exception if Vista features
/// aren't supported.
///
/// The API that is being called.
private void CheckSupportsVistaFeatures(string api)
{
if (!this.Capabilities.SupportsVistaFeatures)
{
throw UnsupportedApiException(api);
}
}
///
/// Check that ESENT supports Windows7 features. Throws an exception if Windows7 features
/// aren't supported.
///
/// The API that is being called.
private void CheckSupportsWindows7Features(string api)
{
if (!this.Capabilities.SupportsWindows7Features)
{
throw UnsupportedApiException(api);
}
}
///
/// Check that ESENT supports Windows8 features. Throws an exception if Windows8 features
/// aren't supported.
///
/// The API that is being called.
private void CheckSupportsWindows8Features(string api)
{
if (!this.Capabilities.SupportsWindows8Features)
{
throw UnsupportedApiException(api);
}
}
///
/// Check that ESENT supports Windows10 features. Throws an exception if Windows10 features
/// aren't supported.
///
/// The API that is being called.
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
///
/// 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().
///
/// The session to use.
/// The cursor to set the index on.
///
/// The name of the index to be selected. If this is null or empty the primary
/// index will be selected.
///
///
/// Reserved. Must be IntPtr.Zero.
///
///
/// Set index options.
///
///
/// 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 . When
/// this parameter is not present or is set to zero, its value is presumed
/// to be 1.
///
/// An error if the call fails.
private int JetSetCurrentIndex4(
JET_SESID sesid,
JET_TABLEID tableid,
string index,
IntPtr indexid,
SetCurrentIndexGrbit grbit,
int itagSequence)
{
TraceFunctionCall();
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
///
/// Creates a table, adds columns, and indices on that table.
///
/// The session to use.
/// The database to which to add the new table.
/// Object describing the table to create.
/// An error if the call fails.
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(ref 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.
///
/// Provides a hook to allow population of additional fields in
/// a different file. These additonal fields are not yet published
/// on MSDN.
///
/// The name of the database about which to retrieve information.
/// The output structure to populate.
/// Specifies which information to retrieve.
/// Whether the additional fields specified by in
/// are populated.
/// The error code returned.
partial void NotYetPublishedGetDbinfomisc(
string databaseName,
ref JET_DBINFOMISC dbinfomisc,
JET_DbInfo infoLevel,
ref bool notYetPublishedSupported,
ref int err);
///
/// Provides a hook to allow population of additional fields in
/// a different file. These additonal fields are not yet published
/// on MSDN.
///
/// The session to use.
/// The database identifier.
/// The output structure to populate.
/// Specifies which information to retrieve.
/// Whether the additional fields specified by in
/// are populated.
/// The error code returned.
partial void NotYetPublishedGetDbinfomisc(
JET_SESID sesid,
JET_DBID dbid,
ref JET_DBINFOMISC dbinfomisc,
JET_DbInfo infoLevel,
ref bool notYetPublishedSupported,
ref int err);
#endregion
}
}