public void Setup() { this.native = new NATIVE_INDEXLIST() { tableid = (IntPtr)0x1000, cRecord = 100, columnidindexname = 0, columnidgrbitIndex = 1, columnidcKey = 2, columnidcEntry = 3, columnidcPage = 4, columnidcColumn = 5, columnidiColumn = 6, columnidcolumnid = 7, columnidcoltyp = 8, columnidCountry = 9, columnidLangid = 10, columnidCp = 11, columnidCollate = 12, columnidgrbitColumn = 13, columnidcolumnname = 14, columnidLCMapFlags = 15, }; this.converted = new JET_INDEXLIST(); this.converted.SetFromNativeIndexlist(this.native); }
/// <summary> /// Create an array of IndexSegment objects from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An array of IndexSegment objects containing the information for the current index.</returns> private static IndexSegment[] GetIndexSegmentsFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { var numSegments = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcColumn); Debug.Assert(numSegments > 0, "Index has zero index segments"); var segments = new IndexSegment[numSegments]; for (int i = 0; i < numSegments; ++i) { string columnName = Api.RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidcolumnname, NativeMethods.Encoding, RetrieveColumnGrbit.None); columnName = StringCache.TryToIntern(columnName); var coltyp = (JET_coltyp)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcoltyp); var grbit = (IndexKeyGrbit)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidgrbitColumn); bool isAscending = IndexKeyGrbit.Ascending == grbit; var cp = (JET_CP)Api.RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidCp); bool isASCII = JET_CP.ASCII == cp; segments[i] = new IndexSegment(columnName, coltyp, isAscending, isASCII); if (i < numSegments - 1) { Api.JetMove(sesid, indexlist.tableid, JET_Move.Next, MoveGrbit.None); } } return(segments); }
/// <summary> /// Create an IndexInfo object from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An IndexInfo object containing the information from that record.</returns> private static IndexInfo GetIndexInfoFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { string name = Api.RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidindexname, NativeMethods.Encoding, RetrieveColumnGrbit.None); name = StringCache.TryToIntern(name); int lcid = (int)Api.RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidLangid); var cultureInfo = new CultureInfo(lcid); uint lcmapFlags = (uint)Api.RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidLCMapFlags); CompareOptions compareOptions = Conversions.CompareOptionsFromLCMapFlags(lcmapFlags); uint grbit = (uint)Api.RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidgrbitIndex); int keys = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcKey); int entries = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcEntry); int pages = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcPage); IndexSegment[] segments = GetIndexSegmentsFromIndexlist(sesid, indexlist); return(new IndexInfo( name, cultureInfo, compareOptions, segments, (CreateIndexGrbit)grbit, keys, entries, pages)); }
public static void JetGetTableIndexInfo( JET_SESID sesid, JET_TABLEID tableid, string indexname, out JET_INDEXLIST indexlist) { Api.JetGetTableIndexInfo(sesid, tableid, indexname, out indexlist, JET_IdxInfo.List); }
public static void JetGetIndexInfo( JET_SESID sesid, JET_DBID dbid, string tablename, string ignored, out JET_INDEXLIST indexlist) { Api.JetGetIndexInfo(sesid, dbid, tablename, ignored, out indexlist, JET_IdxInfo.List); }
/// <summary> /// Create an IndexInfo object from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An IndexInfo object containing the information from that record.</returns> private IndexInfo GetIndexInfoFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { // If we use the wide API (Vista+), then the temp table will be in UTF-16. Encoding encodingOfTextColumns = EsentVersion.SupportsVistaFeatures ? Encoding.Unicode : LibraryHelpers.EncodingASCII; string name = Api.RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidindexname, encodingOfTextColumns, RetrieveColumnGrbit.None); name = StringCache.TryToIntern(name); CultureInfo cultureInfo = null; if (EsentVersion.SupportsWindows8Features) { string localeName; this.GetIndexInfo(sesid, name, out localeName, Windows8IdxInfo.LocaleName); cultureInfo = new CultureInfo(localeName); } else { #if !MANAGEDESENT_ON_CORECLR // This probably won't work on platforms that don't support LCIDs. Newer environments have dropped // LCIDs in favour of locale names. But currently JET_INDEXLIST doesn't expose columnidLocale. int lcid = (int)Api.RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidLangid); cultureInfo = LibraryHelpers.CreateCultureInfoByLcid(lcid); #endif // !MANAGEDESENT_ON_CORECLR } uint lcmapFlags = (uint)Api.RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidLCMapFlags); CompareOptions compareOptions = Conversions.CompareOptionsFromLCMapFlags(lcmapFlags); uint grbit = (uint)Api.RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidgrbitIndex); int keys = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcKey); int entries = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcEntry); int pages = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcPage); IndexSegment[] segments = GetIndexSegmentsFromIndexlist(sesid, indexlist); return(new IndexInfo( name, cultureInfo, compareOptions, segments, (CreateIndexGrbit)grbit, keys, entries, pages)); }
/// <summary> /// Iterates over the information in the JET_INDEXLIST, returning information about each index. /// The table in the indexlist is closed when finished. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to iterate over.</param> /// <returns>An iterator over IndexInfo for each index described in the JET_INDEXLIST.</returns> private static IEnumerable <IndexInfo> EnumerateIndexInfos(JET_SESID sesid, JET_INDEXLIST indexlist) { try { if (Api.TryMoveFirst(sesid, indexlist.tableid)) { do { yield return(GetIndexInfoFromIndexlist(sesid, indexlist)); }while (Api.TryMoveNext(sesid, indexlist.tableid)); } } finally { // Close the temporary table used to return the results JetCloseTable(sesid, indexlist.tableid); } }
/// <summary> /// Create an IndexInfo object from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An IndexInfo object containing the information from that record.</returns> private static IndexInfo GetIndexInfoFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { string name = RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidindexname, NativeMethods.Encoding, RetrieveColumnGrbit.None); var lcid = (int)RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidLangid); var cultureInfo = new CultureInfo(lcid); var lcmapFlags = (uint)RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidLCMapFlags); CompareOptions compareOptions = Conversions.CompareOptionsFromLCMapFlags(lcmapFlags); var grbit = (uint)RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidgrbitIndex); IndexSegment[] segments = GetIndexSegmentsFromIndexlist(sesid, indexlist); return(new IndexInfo( name, cultureInfo, compareOptions, segments, (CreateIndexGrbit)grbit)); }
/// <summary> /// Create an array of IndexSegment objects from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An array of IndexSegment objects containing the information for the current index.</returns> private static IndexSegment[] GetIndexSegmentsFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { var numSegments = (int)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcColumn); Debug.Assert(numSegments > 0, "Index has zero index segments"); // If we use the wide API (Vista+), then the temp table will be in UTF-16. Encoding encodingOfTextColumns = EsentVersion.SupportsVistaFeatures ? Encoding.Unicode : LibraryHelpers.EncodingASCII; var segments = new IndexSegment[numSegments]; for (int i = 0; i < numSegments; ++i) { string columnName = Api.RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidcolumnname, encodingOfTextColumns, RetrieveColumnGrbit.None); columnName = StringCache.TryToIntern(columnName); var coltyp = (JET_coltyp)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcoltyp); var grbit = (IndexKeyGrbit)Api.RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidgrbitColumn); bool isAscending = IndexKeyGrbit.Ascending == grbit; var cp = (JET_CP)Api.RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidCp); bool isASCII = JET_CP.ASCII == cp; segments[i] = new IndexSegment(columnName, coltyp, isAscending, isASCII); if (i < numSegments - 1) { Api.JetMove(sesid, indexlist.tableid, JET_Move.Next, MoveGrbit.None); } } return(segments); }
/// <summary> /// Creates an <see cref="IndexDefinition"/> object from the specified <paramref name="indexList"/>. /// </summary> /// <param name="database">The database.</param> /// <param name="tableName">Name of the table.</param> /// <param name="indexList">The index list.</param> /// <returns>An <see cref="IndexDefinition"/> object represting the specified index.</returns> 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; } } }
/// <summary> /// Retrieves information about indexes on a table. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="dbid">The database to use.</param> /// <param name="tablename">The name of the table to retrieve index information about.</param> /// <param name="indexname">The name of the index to retrieve information about.</param> /// <param name="result">Filled in with information about indexes on the table.</param> /// <param name="infoLevel">The type of information to retrieve.</param> public static void JetGetIndexInfo( JET_SESID sesid, JET_DBID dbid, string tablename, string indexname, out JET_INDEXLIST result, JET_IdxInfo infoLevel) { Api.Check(Impl.JetGetIndexInfo(sesid, dbid, tablename, indexname, out result, infoLevel)); }
/// <summary> /// Retrieves information about indexes on a table. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The table to retrieve index information about.</param> /// <param name="ignored">This parameter is ignored.</param> /// <param name="indexlist">Filled in with information about indexes on the table.</param> public static void JetGetTableIndexInfo( JET_SESID sesid, JET_TABLEID tableid, string ignored, out JET_INDEXLIST indexlist) { Api.Check(Impl.JetGetTableIndexInfo(sesid, tableid, ignored, out indexlist)); }
/// <summary> /// Retrieves information about indexes on a table. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The table to retrieve index information about.</param> /// <param name="indexname">The name of the index.</param> /// <param name="result">Filled in with information about indexes on the table.</param> /// <param name="infoLevel">The type of information to retrieve.</param> public static void JetGetTableIndexInfo( JET_SESID sesid, JET_TABLEID tableid, string indexname, out JET_INDEXLIST result, JET_IdxInfo infoLevel) { Api.Check(Impl.JetGetTableIndexInfo(sesid, tableid, indexname, out result, infoLevel)); }
public void JetIndexlistToString() { var value = new JET_INDEXLIST { cRecord = 3, tableid = new JET_TABLEID { Value = (IntPtr)0x1a } }; Assert.AreEqual("JET_INDEXLIST(0x1a,3 records)", value.ToString()); }
/// <summary> /// Create an array of IndexSegment objects from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An array of IndexSegment objects containing the information for the current index.</returns> private static IndexSegment[] GetIndexSegmentsFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { var numSegments = (int) RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcColumn); Debug.Assert(numSegments > 0, "Index has zero index segments"); var segments = new IndexSegment[numSegments]; for (int i = 0; i < numSegments; ++i) { string columnName = RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidcolumnname, NativeMethods.Encoding, RetrieveColumnGrbit.None); var coltyp = (JET_coltyp) RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidcoltyp); var grbit = (IndexKeyGrbit) RetrieveColumnAsInt32(sesid, indexlist.tableid, indexlist.columnidgrbitColumn); bool isAscending = IndexKeyGrbit.Ascending == grbit; var cp = (JET_CP) RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidCp); bool isASCII = JET_CP.ASCII == cp; segments[i] = new IndexSegment(columnName, coltyp, isAscending, isASCII); if (i < numSegments - 1) { Api.JetMove(sesid, indexlist.tableid, JET_Move.Next, MoveGrbit.None); } } return segments; }
/// <summary> /// Create an IndexInfo object from the data in the current JET_INDEXLIST entry. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to take the data from.</param> /// <returns>An IndexInfo object containing the information from that record.</returns> private static IndexInfo GetIndexInfoFromIndexlist(JET_SESID sesid, JET_INDEXLIST indexlist) { string name = RetrieveColumnAsString( sesid, indexlist.tableid, indexlist.columnidindexname, NativeMethods.Encoding, RetrieveColumnGrbit.None); var lcid = (int) RetrieveColumnAsInt16(sesid, indexlist.tableid, indexlist.columnidLangid); var cultureInfo = new CultureInfo(lcid); var lcmapFlags = (uint) RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidLCMapFlags); CompareOptions compareOptions = Conversions.CompareOptionsFromLCMapFlags(lcmapFlags); var grbit = (uint) RetrieveColumnAsUInt32(sesid, indexlist.tableid, indexlist.columnidgrbitIndex); IndexSegment[] segments = GetIndexSegmentsFromIndexlist(sesid, indexlist); return new IndexInfo( name, cultureInfo, compareOptions, segments, (CreateIndexGrbit) grbit); }
/// <summary> /// Iterates over the information in the JET_INDEXLIST, returning information about each index. /// The table in the indexlist is closed when finished. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="indexlist">The indexlist to iterate over.</param> /// <returns>An iterator over IndexInfo for each index described in the JET_INDEXLIST.</returns> private static IEnumerable<IndexInfo> EnumerateIndexInfos(JET_SESID sesid, JET_INDEXLIST indexlist) { try { MoveBeforeFirst(sesid, indexlist.tableid); while (TryMoveNext(sesid, indexlist.tableid)) { yield return GetIndexInfoFromIndexlist(sesid, indexlist); } } finally { // Close the temporary table used to return the results JetCloseTable(sesid, indexlist.tableid); } }