Ejemplo n.º 1
0
        /// <summary>
        /// Set the current index of the cursor
        /// </summary>
        /// <param name="indexName">The name of the index on the table for this cursor</param>
        /// <remarks>
        /// This will affect the order records are traversed by the MoveNext,
        /// MovePrevious and Move methods. The cursor will be positioned before
        /// the first record on the index.
        /// <para>
        /// As a side effect, any restriction in effect will be cleared.
        /// </para>
        /// </remarks>
        public void SetCurrentIndex(string indexName)
        {
            lock (this.isamSession)
            {
                this.CheckDisposed();

                // don't do anything if we are already on the new index
                if (string.Compare(indexName, this.CurrentIndex, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    // if this is a TT then selecting another index will fail
                    if (this.isTempTable)
                    {
                        throw new EsentIndexNotFoundException();
                    }

                    this.OnNavigation();

                    // select the new index
                    Api.JetSetCurrentIndex(this.isamSession.Sesid, this.tableid, indexName);

                    // purge our cached index definition
                    this.indexDefinition = null;

                    // clear our field cache because the current record has changed
                    this.fields = null;

                    // clear our index range
                    this.FindAllRecords();

                    // move before first on the new index
                    this.MoveBeforeFirst();
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Set the current index of the cursor
        /// </summary>
        /// <param name="indexName">The name of the index on the table for this cursor</param>
        /// <remarks>
        /// This will affect the order records are traversed by the MoveNext,
        /// MovePrevious and Move methods.  The cursor will be positioned on
        /// the new index at the first entry corresponding to the same record
        /// for the entry in the old index.  If no such entry exists because
        /// that record does not have an entry in the new index then the
        /// operation will fail with EsentNoCurrentRecordException.
        /// <para>
        /// As a side effect, any restriction in effect will be cleared.
        /// </para>
        /// </remarks>
        public void MoveToIndex(string indexName)
        {
            lock (this.isamSession)
            {
                this.CheckDisposed();

                // don't do anything if we are already on the new index
                if (string.Compare(indexName, this.CurrentIndex, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    // if this is a TT then selecting another index will fail
                    if (this.isTempTable)
                    {
                        throw new EsentIndexNotFoundException();
                    }

                    // select the new index and attempt to maintain our
                    // position on this record
                    Api.JetSetCurrentIndex2(this.isamSession.Sesid, this.tableid, indexName, SetCurrentIndexGrbit.NoMove);

                    // purge our cached index definition
                    this.indexDefinition = null;

                    // clear our index range
                    this.FindAllRecords();
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Advances the enumerator to the next element of the collection.
        /// </summary>
        /// <returns>
        /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
        /// </returns>
        public bool MoveNext()
        {
            if (this.database != null)
            {
                lock (this.database.IsamSession)
                {
                    if (!this.moved)
                    {
                        Api.JetGetIndexInfo(
                            this.database.IsamSession.Sesid,
                            this.database.Dbid,
                            this.tableName,
                            null,
                            out this.indexList,
                            JET_IdxInfo.List);
                        this.cleanup = true;
                        this.current = Api.TryMoveFirst(this.database.IsamSession.Sesid, this.indexList.tableid);
                    }
                    else if (this.current)
                    {
                        this.current = Api.TryMoveNext(this.database.IsamSession.Sesid, this.indexList.tableid);
                        if (!this.current)
                        {
                            Api.JetCloseTable(this.database.IsamSession.Sesid, this.indexList.tableid);
                            this.cleanup = false;
                        }
                    }

                    this.moved = true;
                    this.indexDefinition = null;
                    return this.current;
                }
            }
            else
            {
                return this.enumerator.MoveNext();
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection.
        /// </summary>
        public void Reset()
        {
            if (this.database != null)
            {
                lock (this.database.IsamSession)
                {
                    if (this.cleanup)
                    {
                        if (!this.database.IsamSession.Disposed)
                        {
                            // BUGBUG:  we will try to close an already closed tableid
                            // if it was already closed due to a rollback.  this could
                            // cause us to crash in ESENT due to lack of full validation
                            // in small config.  we should use cursor LS to detect when
                            // our cursor gets closed and thus avoid closing it again
                            Api.JetCloseTable(this.database.IsamSession.Sesid, this.indexList.tableid);
                        }
                    }

                    this.cleanup = false;
                    this.moved = false;
                    this.current = false;
                    this.indexDefinition = null;
                }
            }
            else
            {
                this.enumerator.Reset();
            }
        }
Ejemplo n.º 5
0
        /// <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;
                }
            }
        }