in isam/IndexDefinition.cs [292:479]
internal static IndexDefinition Load(IsamDatabase database, string tableName, JET_INDEXLIST indexList)
{
lock (database.IsamSession)
{
JET_SESID sesid = database.IsamSession.Sesid;
using (IsamTransaction trx = new IsamTransaction(database.IsamSession))
{
// load info for the index
IndexDefinition indexDefinition = new IndexDefinition();
indexDefinition.name = Api.RetrieveColumnAsString(
sesid,
indexList.tableid,
indexList.columnidindexname);
CreateIndexGrbit grbitIndex = (CreateIndexGrbit)Api.RetrieveColumnAsUInt32(sesid, indexList.tableid, indexList.columnidgrbitIndex);
indexDefinition.flags = IndexFlagsFromGrbits(grbitIndex);
Api.JetGetIndexInfo(
sesid,
database.Dbid,
tableName,
indexDefinition.name,
out indexDefinition.density,
JET_IdxInfo.SpaceAlloc);
int lcid;
Api.JetGetIndexInfo(
database.IsamSession.Sesid,
database.Dbid,
tableName,
indexDefinition.name,
out lcid,
JET_IdxInfo.LCID);
indexDefinition.cultureInfo = new CultureInfo(lcid);
indexDefinition.compareOptions =
Conversions.CompareOptionsFromLCMapFlags(
Api.RetrieveColumnAsUInt32(
database.IsamSession.Sesid,
indexList.tableid,
indexList.columnidLCMapFlags).GetValueOrDefault());
// CONSIDER: move this workaround into Isam.Interop
try
{
ushort maxKeyLength;
Api.JetGetIndexInfo(
database.IsamSession.Sesid,
database.Dbid,
tableName,
indexDefinition.name,
out maxKeyLength,
JET_IdxInfo.KeyMost);
indexDefinition.maxKeyLength = maxKeyLength;
}
catch (EsentInvalidParameterException)
{
indexDefinition.maxKeyLength = 255;
}
catch (EsentColumnNotFoundException)
{
indexDefinition.maxKeyLength = 255;
}
// load info for each key column in the index
int currentColumn = 0;
int totalNumberColumns = Api.RetrieveColumnAsInt32(sesid, indexList.tableid, indexList.columnidcColumn).GetValueOrDefault();
indexDefinition.keyColumnCollection = new KeyColumnCollection();
do
{
// load info for this key column
IndexKeyGrbit grbitColumn = (IndexKeyGrbit)Api.RetrieveColumnAsUInt32(sesid, indexList.tableid, indexList.columnidgrbitColumn);
bool isAscending = (grbitColumn & IndexKeyGrbit.Descending) == 0;
string columnName = Api.RetrieveColumnAsString(
sesid,
indexList.tableid,
indexList.columnidcolumnname);
JET_COLUMNBASE columnbase;
Api.JetGetColumnInfo(sesid, database.Dbid, tableName, columnName, out columnbase);
indexDefinition.keyColumnCollection.Add(new KeyColumn(new Columnid(columnbase), isAscending));
// move onto the next key column definition, unless it is
// the last key column
if (currentColumn != totalNumberColumns - 1)
{
Api.TryMoveNext(sesid, indexList.tableid);
}
}
while (++currentColumn < totalNumberColumns);
indexDefinition.keyColumnCollection.ReadOnly = true;
// Vista: There is currently no efficient means to retrieve the
// conditional columns for an index from JET. so, we are
// going to reach into the catalog and fetch them directly.
//
// FUTURE: Windows 7 introduced Windows7IdxInfo.CreateIndex and Windows7IdxInfo.CreateIndex2 (and
// Win8 has Windows8IdxInfo.CreateIndex3). Consider retrieving the conditional columns with that
// API and converting the results. But that does not solve the problem for Vista.
indexDefinition.conditionalColumnCollection = new ConditionalColumnCollection();
JET_TABLEID tableidCatalog;
Api.JetOpenTable(
database.IsamSession.Sesid,
database.Dbid,
"MSysObjects",
null,
0,
OpenTableGrbit.ReadOnly,
out tableidCatalog);
Api.JetSetCurrentIndex(sesid, tableidCatalog, "RootObjects");
Api.MakeKey(sesid, tableidCatalog, true, MakeKeyGrbit.NewKey);
Api.MakeKey(sesid, tableidCatalog, tableName, Encoding.ASCII, MakeKeyGrbit.None);
Api.JetSeek(sesid, tableidCatalog, SeekGrbit.SeekEQ);
JET_COLUMNID columnidTemp = Api.GetTableColumnid(sesid, tableidCatalog, "ObjidTable");
int objidTable = Api.RetrieveColumnAsInt32(sesid, tableidCatalog, columnidTemp).GetValueOrDefault();
Api.JetSetCurrentIndex(sesid, tableidCatalog, "Name");
Api.MakeKey(sesid, tableidCatalog, objidTable, MakeKeyGrbit.NewKey);
Api.MakeKey(sesid, tableidCatalog, (short)3, MakeKeyGrbit.None);
Api.MakeKey(sesid, tableidCatalog, indexDefinition.name, Encoding.ASCII, MakeKeyGrbit.None);
Api.JetSeek(sesid, tableidCatalog, SeekGrbit.SeekEQ);
columnidTemp = Api.GetTableColumnid(sesid, tableidCatalog, "Flags");
int indexFlagsBytes = Api.RetrieveColumnAsInt32(sesid, tableidCatalog, columnidTemp).GetValueOrDefault();
columnidTemp = Api.GetTableColumnid(sesid, tableidCatalog, "ConditionalColumns");
byte[] conditionalColumnsBytes = Api.RetrieveColumn(sesid, tableidCatalog, columnidTemp);
for (int ib = 0; conditionalColumnsBytes != null && ib < conditionalColumnsBytes.Length; ib += 4)
{
uint colid;
bool mustBeNull;
JET_COLUMNBASE columnBase;
// fIDXExtendedColumns
if ((indexFlagsBytes & 0xffff0000) == 0x00010000)
{
// fIDXSEGTemplateColumn
if ((conditionalColumnsBytes[ib + 0] & 0x80) != 0)
{
// fCOLUMNIDTemplate
colid = 0x80000000 | (uint)(conditionalColumnsBytes[ib + 3] << 8) | (uint)conditionalColumnsBytes[ib + 2];
}
else
{
colid = (uint)(conditionalColumnsBytes[ib + 3] << 8) | (uint)conditionalColumnsBytes[ib + 2];
}
// fIDXSEGMustBeNull
if ((conditionalColumnsBytes[ib + 0] & 0x20) != 0)
{
mustBeNull = true;
}
else
{
mustBeNull = false;
}
}
else
{
// do not load conditional columns from an unknown format
continue;
}
JET_COLUMNID castedColid = JET_COLUMNID.CreateColumnidFromNativeValue(unchecked((int)colid));
VistaApi.JetGetColumnInfo(
database.IsamSession.Sesid,
database.Dbid,
tableName,
castedColid,
out columnBase);
indexDefinition.conditionalColumnCollection.Add(new ConditionalColumn(new Columnid(columnBase), mustBeNull));
}
indexDefinition.conditionalColumnCollection.ReadOnly = true;
indexDefinition.ReadOnly = true;
return indexDefinition;
}
}
}