Beispiel #1
0
        public void JetGetThreadStatsPerf()
        {
            if (!EsentVersion.SupportsVistaFeatures)
            {
                return;
            }

            // Call the method once to force JIT compilation
            JET_THREADSTATS threadstats;

            VistaApi.JetGetThreadStats(out threadstats);

#if DEBUG
            const int N = 1000;
#else
            const int N = 5000000;
#endif
            var stopwatch = Stopwatch.StartNew();
            for (int i = 0; i < N; ++i)
            {
                VistaApi.JetGetThreadStats(out threadstats);
            }

            stopwatch.Stop();

            EseInteropTestHelper.ConsoleWriteLine(
                "Made {0:N0} calls to JetGetThreadStats in {1} ({2:N6} milliseconds/call)",
                N,
                stopwatch.Elapsed,
                (double)stopwatch.ElapsedMilliseconds / N);
        }
Beispiel #2
0
        public void HowDoIRetrieveAnAutoInc()
        {
            JET_SESID sesid = this.testSession;
            JET_DBID  dbid  = this.testDbid;

            JET_TABLEID   tableid;
            JET_COLUMNDEF columndef = new JET_COLUMNDEF();
            JET_COLUMNID  autoincColumn;

            // First create the table. There is one autoinc column.
            Api.JetCreateTable(sesid, dbid, "table", 0, 100, out tableid);
            columndef.coltyp = JET_coltyp.Long;
            columndef.grbit  = ColumndefGrbit.ColumnAutoincrement;
            Api.JetAddColumn(sesid, tableid, "data", columndef, null, 0, out autoincColumn);

            // Once the update is prepared the autoinc column can be retrieved. This
            // requires the RetrieveCopy option, which gets a value from the record
            // currently under construction.
            for (int i = 0; i < 10; i++)
            {
                using (var update = new Update(sesid, tableid, JET_prep.Insert))
                {
                    int?autoinc = Api.RetrieveColumnAsInt32(
                        sesid,
                        tableid,
                        autoincColumn,
                        RetrieveColumnGrbit.RetrieveCopy);
                    EseInteropTestHelper.ConsoleWriteLine("{0}", autoinc);
                    update.Save();
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Verifies no instances are leaked.
        /// </summary>
        public static void CheckProcessForInstanceLeaks()
        {
#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
            int numInstances;
            JET_INSTANCE_INFO[] instances;
            Api.JetGetInstanceInfo(out numInstances, out instances);

            if (numInstances != 0)
            {
                EseInteropTestHelper.ConsoleWriteLine("There are {0} instances remaining! They are:", numInstances);
                foreach (var instanceInfo in instances)
                {
                    string databaseName = string.Empty;
                    if (instanceInfo.szDatabaseFileName != null && instanceInfo.szDatabaseFileName.Count > 0)
                    {
                        databaseName = instanceInfo.szDatabaseFileName[0];
                    }

                    EseInteropTestHelper.ConsoleWriteLine(
                        "   szInstanceName={0}, szDatabaseName={1}",
                        instanceInfo.szInstanceName,
                        databaseName);
                }
            }

            Assert.AreEqual(0, numInstances);
#endif // !MANAGEDESENT_ON_WSA
        }
        public void PrintVersion()
        {
            if (EsentVersion.SupportsServer2003Features)
            {
                EseInteropTestHelper.ConsoleWriteLine("SupportsServer2003Features");
            }

            if (EsentVersion.SupportsVistaFeatures)
            {
                EseInteropTestHelper.ConsoleWriteLine("SupportsVistaFeatures");
            }

            if (EsentVersion.SupportsWindows7Features)
            {
                EseInteropTestHelper.ConsoleWriteLine("SupportsWindows7Features");
            }

            if (EsentVersion.SupportsUnicodePaths)
            {
                EseInteropTestHelper.ConsoleWriteLine("SupportsUnicodePaths");
            }

            if (EsentVersion.SupportsLargeKeys)
            {
                EseInteropTestHelper.ConsoleWriteLine("SupportsLargeKeys");
            }
        }
        public void VerifyCallbackWrappersCollectsUnusedWrappers()
        {
            DateTime endTime = DateTime.Now + TimeSpan.FromSeconds(19);

            var callbackWrappers = new CallbackWrappers();

            RunFullGarbageCollection();
            long memoryAtStart = EseInteropTestHelper.GCGetTotalMemory(true);

            while (DateTime.Now < endTime)
            {
                for (int i = 0; i < 128; ++i)
                {
                    CreateCallbackWrapper(callbackWrappers);
                }

                RunFullGarbageCollection();
                callbackWrappers.Collect();
                RunFullGarbageCollection();
            }

            RunFullGarbageCollection();
            long memoryAtEnd = EseInteropTestHelper.GCGetTotalMemory(true);

            GC.KeepAlive(callbackWrappers);

            long memory = memoryAtEnd - memoryAtStart;

            EseInteropTestHelper.ConsoleWriteLine("{0:N0} bytes used", memory);
            Assert.IsTrue(memory < 1024 * 1024, "Test used too much memory. JetCallbackWrapper objects weren't collected.");
        }
        public void VerifyJetVersionIsNotZero()
        {
            JET_INSTANCE instance;
            JET_SESID    sesid;
            uint         version;

            Api.JetCreateInstance(out instance, "JetGetVersion");

            var parameters = new InstanceParameters(instance);

            parameters.Recovery           = false;
            parameters.MaxTemporaryTables = 0;
            parameters.NoInformationEvent = true;

            Api.JetInit(ref instance);
            Api.JetBeginSession(instance, out sesid, string.Empty, string.Empty);
#if MANAGEDESENT_ON_WSA // Not exposed in MSDK
            version = 0;
#else
            Api.JetGetVersion(sesid, out version);
#endif
            Api.JetTerm(instance);

            Assert.AreNotEqual(0, version);
            EseInteropTestHelper.ConsoleWriteLine("Version = 0x{0:X}", version);
        }
Beispiel #7
0
            /// <summary>
            /// Run the test.
            /// </summary>
            public void RunTest()
            {
#if !MANAGEDESENT_ON_WSA // The threading model in Windows Store Apps has changed.
                Int32ColumnValue columnValue = new Int32ColumnValue();
                columnValue.Value = 0;
                Assert.AreEqual(0, columnValue.ValueAsObject);

                Thread[] threads = new Thread[Environment.ProcessorCount * 2];
                for (int i = 0; i < threads.Length; ++i)
                {
                    threads[i] = new Thread(this.ThreadProc);
                    threads[i].Start(new Random(i));
                    this.activeThreads++;
                }

                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();

                Stopwatch stopwatch = Stopwatch.StartNew();
                this.startEvent.Set();
                this.stopEvent.WaitOne();
                stopwatch.Stop();

                foreach (Thread t in threads)
                {
                    t.Join();
                }

                EseInteropTestHelper.ConsoleWriteLine("Performed {0:N0} operations on {1} threads in {2}", N, threads.Length, stopwatch.Elapsed);
#endif // !MANAGEDESENT_ON_WSA
            }
Beispiel #8
0
        public void CreateAllErrorExceptions()
        {
            int i = 0;

            foreach (JET_err err in Enum.GetValues(typeof(JET_err)))
            {
                if (JET_err.Success != err)
                {
                    EsentErrorException ex = EsentExceptionHelper.JetErrToException(err);
                    Assert.IsNotNull(ex);
                    Assert.AreEqual(err, ex.Error);
                    Assert.IsNotNull(ex.Message);
                    Assert.AreNotEqual(string.Empty, ex.Message);

#if MANAGEDESENT_ON_CORECLR
#else
                    EsentErrorException deserialized = SerializeDeserialize(ex);
                    Assert.AreEqual(err, deserialized.Error);
                    Assert.AreEqual(ex.Message, deserialized.Message);
#endif
                    i++;
                }
            }

            EseInteropTestHelper.ConsoleWriteLine("Created {0} different error exceptions", i);
        }
        public void TestJetThreadstatsToStringPerf()
        {
            var t = new JET_THREADSTATS
            {
                cPageReferenced = 10,
                cPageRead       = 5,
                cPagePreread    = 4,
                cPageDirtied    = 3,
                cPageRedirtied  = 2,
                cLogRecord      = 1,
                cbLogRecord     = 0,
            };

            // Call the method once to make sure it is compiled.
            string ignored = t.ToString();

            const int      N = 100000;
            EsentStopwatch s = EsentStopwatch.StartNew();

            for (int i = 0; i < N; ++i)
            {
                ignored = t.ToString();
            }

            s.Stop();

            double ms = Math.Max(1, s.Elapsed.Milliseconds);

            EseInteropTestHelper.ConsoleWriteLine("{0} calls in {1} ({2} ms/call)", N, s.Elapsed, ms / N);
        }
        public void CreateResizeAndTrimDatabase()
        {
            if (!EsentVersion.SupportsWindows81Features)
            {
                return;
            }

            string       dir      = SetupHelper.CreateRandomDirectory();
            JET_INSTANCE instance = SetupHelper.CreateNewInstance(dir);

            Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxTemporaryTables, 0, null);

            InstanceParameters instanceParameters = new InstanceParameters(instance);

            instanceParameters.EnableShrinkDatabase = ShrinkDatabaseGrbit.On;
            Api.JetInit(ref instance);
            try
            {
                string database = Path.Combine(dir, "CreateAndResizeDatabase.db");

                JET_SESID sesid;
                JET_DBID  dbid;
                Api.JetBeginSession(instance, out sesid, string.Empty, string.Empty);

                Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.DbExtensionSize, 256, null);
                Api.JetCreateDatabase(sesid, database, string.Empty, out dbid, CreateDatabaseGrbit.None);

                Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.DbExtensionSize, 1, null);

                int databaseSpaceOwned;
                Api.JetGetDatabaseInfo(sesid, dbid, out databaseSpaceOwned, JET_DbInfo.SpaceOwned);

                // We have to take into account the reserved pages in the database as per the API to get the actual
                // space.
                databaseSpaceOwned += ReservedPages;

                int actualPages;
                Windows8Api.JetResizeDatabase(sesid, dbid, databaseSpaceOwned + 100, out actualPages, ResizeDatabaseGrbit.None);
                EseInteropTestHelper.ConsoleWriteLine("actualPages is {0}.", actualPages);

                Assert.IsTrue(actualPages >= databaseSpaceOwned + 100, "Database didn't grow enough!");

                int actualPagesAfterTrim = 0;
                Windows8Api.JetResizeDatabase(sesid, dbid, 0, out actualPagesAfterTrim, ResizeDatabaseGrbit.None);
                EseInteropTestHelper.ConsoleWriteLine("actualPagesAfterTrim is {0}.", actualPagesAfterTrim);

                Assert.IsTrue(actualPagesAfterTrim < actualPages, "Database didn't shrink!");

                int databaseSizeOnDiskInPages;
                Api.JetGetDatabaseInfo(sesid, dbid, out databaseSizeOnDiskInPages, Windows81DbInfo.FilesizeOnDisk);
                EseInteropTestHelper.ConsoleWriteLine("databaseSizeOnDiskInPages is {0}.", databaseSizeOnDiskInPages);
                Assert.AreEqual(actualPagesAfterTrim, databaseSizeOnDiskInPages);
            }
            finally
            {
                Api.JetTerm(instance);
                Cleanup.DeleteDirectoryWithRetry(dir);
            }
        }
        /// <summary>
        /// Perform and time the given action.
        /// </summary>
        /// <param name="name">The name of the action.</param>
        /// <param name="action">The operation to perform.</param>
        private static void TimeAction(string name, Action action)
        {
            var stopwatch = EsentStopwatch.StartNew();

            action();
            stopwatch.Stop();
            EseInteropTestHelper.ConsoleWriteLine("{0}: {1} ({2})", name, stopwatch.Elapsed, stopwatch.ThreadStats);
        }
Beispiel #12
0
        public void HowDoILockRecords()
        {
            JET_SESID sesid = this.testSession;
            JET_DBID  dbid  = this.testDbid;

            // First create the table
            JET_TABLEID tableid;

            Api.JetCreateTable(sesid, dbid, "table", 0, 100, out tableid);
            Api.JetCloseTable(sesid, tableid);
            Api.JetOpenTable(sesid, dbid, "table", null, 0, OpenTableGrbit.None, out tableid);

            // Insert a selection of records
            for (int i = 0; i < 30; i++)
            {
                using (var update = new Update(sesid, tableid, JET_prep.Insert))
                {
                    update.Save();
                }
            }

            // Create workers
            var workers = new Worker[2];
            var threads = new Thread[workers.Length];

            for (int i = 0; i < workers.Length; ++i)
            {
                JET_SESID workerSesid;
                Api.JetDupSession(sesid, out workerSesid);
                JET_DBID workerDbid;
                Api.JetOpenDatabase(workerSesid, TestDatabase, null, out workerDbid, OpenDatabaseGrbit.None);
                JET_TABLEID workerTableid;
                Api.JetOpenTable(workerSesid, workerDbid, "table", null, 0, OpenTableGrbit.None, out workerTableid);
                workers[i] = new Worker(workerSesid, workerTableid);
                threads[i] = new Thread(workers[i].DoWork);
            }

            // Run the workers then wait for them
            foreach (Thread t in threads)
            {
                t.Start();
            }

            foreach (Thread t in threads)
            {
                t.Join();
            }

            for (int i = 0; i < workers.Length; ++i)
            {
                EseInteropTestHelper.ConsoleWriteLine("Worker {0} processed {1} records", i, workers[i].RecordsProcessed);
            }
        }
        /// <summary>
        /// Prints a sorted list of the Jet apis in the given type.
        /// </summary>
        /// <param name="type">The type to inspect.</param>
        /// <returns>The number of APIs found in the type.</returns>
        private static int PrintJetApiNames(Type type)
        {
            int numApisFound = 0;

            foreach (string method in GetJetApiNames(type).OrderBy(x => x).Distinct())
            {
                EseInteropTestHelper.ConsoleWriteLine("\t{0}", method);
                numApisFound++;
            }

            return(numApisFound);
        }
Beispiel #14
0
        public void VerifyAllPublicClassesHaveToString()
        {
            Assembly assembly = EseInteropTestHelper.GetAssembly(typeof(Api));
            var      classes  = FindPublicClassesWithoutToString(assembly);
            int      classesWithoutToString = 0;

            foreach (Type @class in classes)
            {
                EseInteropTestHelper.ConsoleWriteLine("{0} does not override Object.ToString", @class);
                ++classesWithoutToString;
            }

            Assert.AreEqual(0, classesWithoutToString, "Some classes do not override Object.ToString()");
        }
Beispiel #15
0
        /// <summary>
        /// Verify that all TestMethods in an assembly have a specific attribute.
        /// If not all methods have the attribute then the names of the methods
        /// are printed and the test fails.
        /// </summary>
        /// <typeparam name="T">The required attribute.</typeparam>
        /// <param name="assembly">The assembly to look in.</param>
        private static void VerifyAllTestMethodsHaveAttribute <T>(Assembly assembly) where T : Attribute
        {
            var methods = FindTestMethodsWithoutAttribute <T>(assembly);

            if (methods.Length > 0)
            {
                EseInteropTestHelper.ConsoleWriteLine("{0} methods have no {1} attribute", methods.Length, typeof(T).Name);
                foreach (string m in methods)
                {
                    EseInteropTestHelper.ConsoleWriteLine("\t{0}", m);
                }

                Assert.Fail("A test method does not have a required attribute");
            }
        }
        public void ListAllApis()
        {
            EseInteropTestHelper.ConsoleWriteLine("Api");
            int totalApis = PrintJetApiNames(typeof(Api));

            EseInteropTestHelper.ConsoleWriteLine("Server2003Api");
            totalApis += PrintJetApiNames(typeof(Server2003Api));
            EseInteropTestHelper.ConsoleWriteLine("VistaApi");
            totalApis += PrintJetApiNames(typeof(VistaApi));
            EseInteropTestHelper.ConsoleWriteLine("Windows7Api");
            totalApis += PrintJetApiNames(typeof(Windows7Api));
            EseInteropTestHelper.ConsoleWriteLine("Windows8Api");
            totalApis += PrintJetApiNames(typeof(Windows8Api));
            EseInteropTestHelper.ConsoleWriteLine("Total APIs: {0}", totalApis);
        }
Beispiel #17
0
        public void VerifyAllPublicMethodsAreTests()
        {
            Assembly assembly = EseInteropTestHelper.GetAssembly(this.GetType());
            var      methods  = FindPublicNonTestMethods(assembly);

            if (methods.Length > 0)
            {
                EseInteropTestHelper.ConsoleWriteLine("{0} public methods have no [TestMethod] attribute", methods.Length);
                foreach (string m in methods)
                {
                    EseInteropTestHelper.ConsoleWriteLine("\t{0}", m);
                }

                Assert.Fail("A public method is not a test. Missing a [TestMethod] attribute?");
            }
        }
        /// <summary>
        /// Create table with 4 records per page
        /// </summary>
        private void CreatePopulateAndTestTable()
        {
            Api.JetBeginTransaction(this.sesId);
            EseInteropTestHelper.ConsoleWriteLine("Create and popluate table.");
            JET_TABLECREATE tc = this.CreateTable(this.tableName);

            for (int i = 0; i < 10000; i++)
            {
                this.InsertRecord(tc.tableid, System.Guid.NewGuid());
                if ((i % 100) == 0)
                {
                    if ((i % 2000) == 0)
                    {
                        EseInteropTestHelper.ConsoleWriteLine("Added another 2000 Guids.");
                    }

                    Api.JetCommitTransaction(this.sesId, CommitTransactionGrbit.None);
                    Api.JetBeginTransaction(this.sesId);
                }
            }

            EseInteropTestHelper.ConsoleWriteLine("Finished inserting first set of values in index.");

            Guid guidPrev;
            Guid guidCur;

            Api.JetMove(this.sesId, tc.tableid, JET_Move.First, MoveGrbit.None);
            int bytesRead;

            byte[] data = new byte[16];
            Api.JetRetrieveColumn(this.sesId, tc.tableid, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
            guidPrev = new System.Guid(data);
            for (int i = 1; i < 10000; i++)
            {
                Api.JetMove(this.sesId, tc.tableid, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, tc.tableid, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
                guidCur = new System.Guid(data);
                Assert.IsTrue(guidCur.CompareTo(guidPrev) > 0);
                guidPrev = guidCur;
            }

            Api.JetCommitTransaction(this.sesId, CommitTransactionGrbit.None);

            EseInteropTestHelper.ConsoleWriteLine("Finished testing .Net Guid sort order on inserted values");
            Api.JetCloseTable(this.sesId, tc.tableid);
        }
        /// <summary>
        /// Perform an action, checking the system's memory usage before and after.
        /// </summary>
        /// <param name="action">The action to perform.</param>
        private static void CheckMemoryUsage(Action action)
        {
            RunGarbageCollection();
            long memoryAtStart          = EseInteropTestHelper.GCGetTotalMemory(true);
            int  collectionCountAtStart = EseInteropTestHelper.GCCollectionCount(0);

            action();

            int collectionCountAtEnd = EseInteropTestHelper.GCCollectionCount(0);

            RunGarbageCollection();
            long memoryAtEnd = EseInteropTestHelper.GCGetTotalMemory(true);

            EseInteropTestHelper.ConsoleWriteLine(
                "Memory changed by {0:N} bytes ({1} GC cycles)",
                memoryAtEnd - memoryAtStart,
                collectionCountAtEnd - collectionCountAtStart);
        }
        /// <summary>
        /// Create table with 4 records per page
        /// </summary>
        private void CreatePopulateAndTestTable()
        {
            EseInteropTestHelper.ConsoleWriteLine("Create and popluate table.");
            JET_TABLECREATE tc = this.CreateTable(this.tableName);

            // make sure full range is covered
            this.InsertRecord(tc.tableid, 0);
            this.InsertRecord(tc.tableid, 0x7fffffffffffffff);
            this.InsertRecord(tc.tableid, 0xffffffffffffffff);

            // add many random values
            for (int i = 0; i < this.cuint64Random; i++)
            {
                this.InsertRecord(tc.tableid, this.RandomULong());
            }

            EseInteropTestHelper.ConsoleWriteLine("Finished inserting records in table.");

            // validate order
            ulong ulongPrev;
            ulong ulongCur;

            Api.JetMove(this.sesId, tc.tableid, JET_Move.First, MoveGrbit.None);
            int bytesRead;

            byte[] data = new byte[8];
            Api.JetRetrieveColumn(this.sesId, tc.tableid, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
            ulongPrev = BitConverter.ToUInt64(data, 0);
            for (int i = 1; i < this.cuint64Random + 3; i++)
            {
                Api.JetMove(this.sesId, tc.tableid, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, tc.tableid, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
                ulongCur = BitConverter.ToUInt64(data, 0);
                EseInteropTestHelper.ConsoleWriteLine("Unsigned long long {0} is larger than {1}.", ulongCur, ulongPrev);
                Assert.IsTrue(ulongCur.CompareTo(ulongPrev) > 0);

                ulongPrev = ulongCur;
            }

            EseInteropTestHelper.ConsoleWriteLine("UInt64 order is correct and same value is retrieved from secondary index key.");
            EseInteropTestHelper.ConsoleWriteLine("Finished testing ULongLong sort order on inserted values");
            Api.JetCloseTable(this.sesId, tc.tableid);
        }
Beispiel #21
0
        public void TestDictionaryLookupPerf()
        {
            const int NumIterations       = 200000;
            const int LookupsPerIteration = 5;

            var stopwatch = EsentStopwatch.StartNew();

            for (int i = 0; i < NumIterations; ++i)
            {
                JET_COLUMNID boolean = this.columnidDict["Boolean"];
                JET_COLUMNID int16   = this.columnidDict["Int16"];
                JET_COLUMNID @float  = this.columnidDict["Float"];
                JET_COLUMNID ascii   = this.columnidDict["Ascii"];
                JET_COLUMNID uint64  = this.columnidDict["Uint64"];
            }

            stopwatch.Stop();
            const double TotalLookups = NumIterations * LookupsPerIteration;
            double       lookupRate   = TotalLookups / stopwatch.Elapsed.Milliseconds;

            EseInteropTestHelper.ConsoleWriteLine("{0} lookups/millisecond", lookupRate);
        }
        public void RepeatedlyRetrieveMetaData()
        {
            var testDuration = TimeSpan.FromSeconds(19);
            var startTime    = DateTime.UtcNow;
            int iteration    = 0;

            while (DateTime.UtcNow < startTime + testDuration)
            {
                Api.GetColumnDictionary(this.sesid, this.tableid);
                foreach (var x in Api.GetTableColumns(this.sesid, this.tableid))
                {
                    foreach (var y in Api.GetTableIndexes(this.sesid, this.tableid))
                    {
                        foreach (var z in Api.GetTableNames(this.sesid, this.dbid))
                        {
                        }
                    }
                }

                iteration++;
            }

            EseInteropTestHelper.ConsoleWriteLine("{0:N0} iterations", iteration);
        }
        public void VerifyJetVersionOverride()
        {
            JET_INSTANCE instance;
            JET_SESID    sesid;
            uint         version;

            IJetApi savedImpl = Api.Impl;

            try
            {
                Api.Impl = new JetApi(Constants.VistaVersion);

                Api.JetCreateInstance(out instance, "JetGetVersionOverride");

                var parameters = new InstanceParameters(instance);
                parameters.Recovery           = false;
                parameters.MaxTemporaryTables = 0;
                parameters.NoInformationEvent = true;

                Api.JetInit(ref instance);
                Api.JetBeginSession(instance, out sesid, string.Empty, string.Empty);
#if MANAGEDESENT_ON_WSA // Not exposed in MSDK
                version = Constants.VistaVersion;
#else
                Api.JetGetVersion(sesid, out version);
#endif
                Api.JetTerm(instance);

                Assert.AreEqual(Constants.VistaVersion, version);
                EseInteropTestHelper.ConsoleWriteLine("Version = 0x{0:X}", version);
            }
            finally
            {
                Api.Impl = savedImpl;
            }
        }
        /// <summary>
        /// Creates a temp table with GUID column and tests .Net sort order.
        /// </summary>
        private void TestTempTableWithGuidDotNetSortOrder()
        {
            // check temp table logic
            EseInteropTestHelper.ConsoleWriteLine("Create temp table on GUID column.");

            var columns = new[]
            {
                new JET_COLUMNDEF {
                    coltyp = VistaColtyp.GUID, cp = JET_CP.Unicode, grbit = ColumndefGrbit.TTKey
                },
            };
            var columnids = new JET_COLUMNID[columns.Length];

            var idxunicode = new JET_UNICODEINDEX
            {
                dwMapFlags   = Conversions.LCMapFlagsFromCompareOptions(CompareOptions.None),
                szLocaleName = "pt-br",
            };

            var opentemporarytable = new JET_OPENTEMPORARYTABLE
            {
                cbKeyMost    = SystemParameters.KeyMost,
                ccolumn      = columns.Length,
                grbit        = TempTableGrbit.Scrollable | Windows8Grbits.TTDotNetGuid,
                pidxunicode  = idxunicode,
                prgcolumndef = columns,
                prgcolumnid  = columnids,
            };

            Windows8Api.JetOpenTemporaryTable2(this.sesId, opentemporarytable);
            Guid g = System.Guid.NewGuid();

            EseInteropTestHelper.ConsoleWriteLine("Insert values in temp table.");
            for (int i = 0; i < 10000; i++)
            {
                if ((i % 2000) == 0)
                {
                    EseInteropTestHelper.ConsoleWriteLine("Added another 2000 Guids.");
                }

                using (var update = new Update(this.sesId, opentemporarytable.tableid, JET_prep.Insert))
                {
                    Api.SetColumn(this.sesId, opentemporarytable.tableid, columnids[0], g);
                    update.Save();
                }

                g = System.Guid.NewGuid();
            }

            EseInteropTestHelper.ConsoleWriteLine("Finished inserting values in temp table.");

            // validate order after having closed the database and restarted
            Api.JetMove(this.sesId, opentemporarytable.tableid, JET_Move.First, MoveGrbit.None);
            int bytesRead;

            byte[] data = new byte[16];
            Api.JetRetrieveColumn(this.sesId, opentemporarytable.tableid, columnids[0], data, data.Length, out bytesRead, 0, null);
            Guid guidPrev = new System.Guid(data);

            EseInteropTestHelper.ConsoleWriteLine("Retrieved first value from temp table.");
            Guid guidCur;

            for (int i = 1; i < 10000; i++)
            {
                Api.JetMove(this.sesId, opentemporarytable.tableid, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, opentemporarytable.tableid, columnids[0], data, data.Length, out bytesRead, 0, null);

                guidCur = new System.Guid(data);
                Assert.IsTrue(guidCur.CompareTo(guidPrev) > 0);
                guidPrev = guidCur;
            }

            EseInteropTestHelper.ConsoleWriteLine("Validated temp table order.");
        }
        public void TestDotNetGuidSortOrder()
        {
            if (!EsentVersion.SupportsWindows8Features)
            {
                return;
            }

            // Create table with GUID column and index over GUID column.
            this.CreatePopulateAndTestTable();

            Api.JetCloseDatabase(this.sesId, this.databaseId, CloseDatabaseGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
            EseInteropTestHelper.ConsoleWriteLine("Compact database.");
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);
            Api.JetCompact(this.sesId, this.database, Path.Combine(this.directory, "defragged.edb"), null, null, CompactGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

            this.database = Path.Combine(this.directory, "defragged.edb");
            Assert.IsTrue(EseInteropTestHelper.FileExists(this.database));
#endif // !MANAGEDESENT_ON_WSA
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);

            Api.JetOpenDatabase(this.sesId, this.database, null, out this.databaseId, OpenDatabaseGrbit.None);
            Api.JetOpenTable(this.sesId, this.databaseId, this.tableName, null, 0, OpenTableGrbit.None, out this.tableId);

            Api.JetBeginTransaction(this.sesId);
            EseInteropTestHelper.ConsoleWriteLine("Insert more values in index.");
            for (int i = 0; i < 10000; i++)
            {
                if ((i % 2000) == 0)
                {
                    EseInteropTestHelper.ConsoleWriteLine("Added another 2000 Guids.");
                }

                Api.JetCommitTransaction(this.sesId, CommitTransactionGrbit.None);
                Api.JetBeginTransaction(this.sesId);
                this.InsertRecord(this.tableId, System.Guid.NewGuid());
            }

            Api.JetCommitTransaction(this.sesId, CommitTransactionGrbit.None);
            EseInteropTestHelper.ConsoleWriteLine("Finished inserting more values in index.");

            // validate order after having closed the database and restarted
            Guid guidPrev;
            Guid guidCur;
            Api.JetMove(this.sesId, this.tableId, JET_Move.First, MoveGrbit.None);
            int    bytesRead;
            byte[] data = new byte[16];
            Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
            guidPrev = new System.Guid(data);
            for (int i = 1; i < 10000; i++)
            {
                Api.JetMove(this.sesId, this.tableId, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
                guidCur = new System.Guid(data);
                Assert.IsTrue(guidCur.CompareTo(guidPrev) > 0);
                guidPrev = guidCur;
            }

            EseInteropTestHelper.ConsoleWriteLine("Validated order.");

            // retrieve newly inserted GUID from index and compare values
            // to test denormalization logic
            Guid guidT = System.Guid.NewGuid();
            EseInteropTestHelper.ConsoleWriteLine("Allocate random GUID...");
            EseInteropTestHelper.ConsoleWriteLine(guidT.ToString());
            this.InsertRecord(this.tableId, guidT);
            Api.JetSetCurrentIndex(this.sesId, this.tableId, this.secIndexName);
            EseInteropTestHelper.ConsoleWriteLine("Guid inserted is....");
            EseInteropTestHelper.ConsoleWriteLine("{0}", guidT);
            byte[] keyArray = guidT.ToByteArray();
            Api.JetMakeKey(this.sesId, this.tableId, keyArray, keyArray.Length, MakeKeyGrbit.NewKey);
            Api.JetSeek(this.sesId, this.tableId, SeekGrbit.SeekEQ);

            Api.JetSetCurrentIndex(this.sesId, this.tableId, this.secIndexName);
            keyArray = guidT.ToByteArray();
            Api.JetMakeKey(this.sesId, this.tableId, keyArray, keyArray.Length, MakeKeyGrbit.NewKey);
            Api.JetSeek(this.sesId, this.tableId, SeekGrbit.SeekEQ);
            JET_wrn err = Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, RetrieveColumnGrbit.RetrieveFromIndex, null);
            Assert.AreEqual(data.Length, bytesRead);
            EseInteropTestHelper.ConsoleWriteLine("Found random GUID in index...");
            Guid guidTT = new System.Guid(data);
            Assert.AreEqual(guidT, guidTT);
            EseInteropTestHelper.ConsoleWriteLine("Found specific GUID in index");

            // check retrieve from index for denormalization
            // by comparing guid inserted.  They should match.
            Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, RetrieveColumnGrbit.RetrieveFromIndex, null);
            guidCur = new System.Guid(data);
            EseInteropTestHelper.ConsoleWriteLine("Retrieved Guid is:");
            EseInteropTestHelper.ConsoleWriteLine(guidCur.ToString());
            Assert.IsTrue(guidCur.CompareTo(guidT) == 0);
            EseInteropTestHelper.ConsoleWriteLine("Retrieve from index matches inserted GUID");

            Api.JetCloseTable(this.sesId, this.tableId);

            this.TestTempTableWithGuidDotNetSortOrder();
        }
Beispiel #26
0
        /// <summary>
        /// Retrieves various pieces of information with JetGetDatabaseInfo.
        /// </summary>
        private void TestJetGetDatabaseInfo()
        {
            using (var instance = this.CreateInstance())
            {
                instance.Init();
                using (var session = new Session(instance))
                {
                    // Attach the database.
                    Api.JetAttachDatabase(session, this.database, AttachDatabaseGrbit.None);
                    JET_DBID dbid;
                    Api.JetOpenDatabase(session, this.database, string.Empty, out dbid, OpenDatabaseGrbit.None);

                    int databaseSizePages;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseSizePages, JET_DbInfo.Filesize);
                    Assert.AreNotEqual(0, databaseSizePages);

                    int databaseLcid;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseLcid, JET_DbInfo.LCID);
                    EseInteropTestHelper.ConsoleWriteLine("databaseLcid is {0}", databaseLcid);
                    Assert.AreEqual(1033, databaseLcid);

                    int databaseOptions;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseOptions, JET_DbInfo.Options);
                    EseInteropTestHelper.ConsoleWriteLine("databaseOptions is {0}", databaseOptions);
                    Assert.AreEqual(0, databaseOptions);

                    int databaseTransactions;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseTransactions, JET_DbInfo.Transactions);
                    EseInteropTestHelper.ConsoleWriteLine("databaseTransactions is {0}", databaseTransactions);
                    Assert.AreEqual(7, databaseTransactions);

                    int databaseVersion;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseVersion, JET_DbInfo.Version);
                    EseInteropTestHelper.ConsoleWriteLine("databaseVersion is {0}", databaseVersion);
                    Assert.AreNotEqual(0, databaseVersion);

                    int databaseSpaceOwned;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseSpaceOwned, JET_DbInfo.SpaceOwned);
                    EseInteropTestHelper.ConsoleWriteLine("databaseSpaceOwned is {0}", databaseSpaceOwned);
                    Assert.AreNotEqual(0, databaseSpaceOwned);

                    int databaseSpaceAvailable;
                    Api.JetGetDatabaseInfo(session, dbid, out databaseSpaceAvailable, JET_DbInfo.SpaceAvailable);
                    EseInteropTestHelper.ConsoleWriteLine("databaseSpaceAvailable is {0}", databaseSpaceAvailable);
                    Assert.AreNotEqual(0, databaseSpaceAvailable);

                    int databasePageSize;
                    Api.JetGetDatabaseInfo(session, dbid, out databasePageSize, JET_DbInfo.PageSize);
                    Assert.AreEqual(SystemParameters.DatabasePageSize, databasePageSize);

                    JET_DBINFOMISC dbinfomisc;
                    Api.JetGetDatabaseInfo(session, dbid, out dbinfomisc, JET_DbInfo.Misc);
                    Assert.AreEqual(SystemParameters.DatabasePageSize, dbinfomisc.cbPageSize);

                    string path;
                    Api.JetGetDatabaseInfo(session, dbid, out path, JET_DbInfo.Filename);
#if MANAGEDESENT_ON_WSA
                    Assert.IsFalse(string.IsNullOrEmpty(path));
#else
                    Assert.AreEqual(Path.GetFullPath(this.database), path);
#endif
                }
            }
        }
        public void CreateResizeAndTrimDatabaseFailsOnRetail()
        {
            if (!EsentVersion.SupportsWindows81Features)
            {
                return;
            }

            string       dir      = SetupHelper.CreateRandomDirectory();
            JET_INSTANCE instance = SetupHelper.CreateNewInstance(dir);

            Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.MaxTemporaryTables, 0, null);
            Api.JetSetSystemParameter(instance, JET_SESID.Nil, JET_param.DbExtensionSize, 1, null);

            InstanceParameters instanceParameters = new InstanceParameters(instance);

            instanceParameters.EnableShrinkDatabase = ShrinkDatabaseGrbit.Off;
            Api.JetInit(ref instance);
            try
            {
                string database = Path.Combine(dir, "CreateAndResizeDatabase.db");

                JET_SESID sesid;
                JET_DBID  dbid;
                Api.JetBeginSession(instance, out sesid, string.Empty, string.Empty);
                Api.JetCreateDatabase(sesid, database, string.Empty, out dbid, CreateDatabaseGrbit.None);

                int databaseSpaceOwned;
                Api.JetGetDatabaseInfo(sesid, dbid, out databaseSpaceOwned, JET_DbInfo.SpaceOwned);

                // We have to take into account the reserved pages in the database as per the API to get the actual
                // space.
                databaseSpaceOwned += ReservedPages;

                // Growing is still allowed.
                int actualPages;
                Windows8Api.JetResizeDatabase(sesid, dbid, databaseSpaceOwned + 100, out actualPages, ResizeDatabaseGrbit.None);
                EseInteropTestHelper.ConsoleWriteLine("actualPages is {0}.", actualPages);

                Assert.IsTrue(actualPages >= databaseSpaceOwned + 100, "Database didn't grow enough!");

                try
                {
                    int actualPagesAfterTrim = 0;
                    Windows8Api.JetResizeDatabase(sesid, dbid, 0, out actualPagesAfterTrim, ResizeDatabaseGrbit.None);
                    Assert.Fail("JetResizeDatabase() did not return the expected exception: EsentFeatureNotAvailableException.");
                }
                catch (EsentFeatureNotAvailableException)
                {
                    EseInteropTestHelper.ConsoleWriteLine("Caught the expected exception -- EsentFeatureNotAvailableException.");
                }

                // Check the on-disk size.
                int databaseSizeOnDiskInPages;
                Api.JetGetDatabaseInfo(sesid, dbid, out databaseSizeOnDiskInPages, Windows81DbInfo.FilesizeOnDisk);
                EseInteropTestHelper.ConsoleWriteLine("databaseSizeOnDiskInPages is {0}.", databaseSizeOnDiskInPages);
                Assert.AreEqual(actualPages, databaseSizeOnDiskInPages);

                // ...and the logical size (should be the same).
                Api.JetGetDatabaseInfo(sesid, dbid, out databaseSizeOnDiskInPages, JET_DbInfo.Filesize);
                EseInteropTestHelper.ConsoleWriteLine("databaseSizeOnDiskInPages is {0}.", databaseSizeOnDiskInPages);
                Assert.AreEqual(actualPages, databaseSizeOnDiskInPages);
            }
            finally
            {
                Api.JetTerm(instance);
                Cleanup.DeleteDirectoryWithRetry(dir);
            }
        }
        public void ULongLongSortOrder()
        {
            // Create table with ULongLong column and index over ULongLong column.
            if (EsentVersion.SupportsWindows10Features)
            {
                this.CreatePopulateAndTestTable();
            }
            else
            {
                try
                {
                    this.CreatePopulateAndTestTable();
                }
                catch (EsentInvalidColumnTypeException)
                {
                    return;
                }
            }

            Api.JetCloseDatabase(this.sesId, this.databaseId, CloseDatabaseGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
            EseInteropTestHelper.ConsoleWriteLine("Compact database.");
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);
            Api.JetCompact(this.sesId, this.database, Path.Combine(this.directory, "defragged.edb"), null, null, CompactGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

            this.database = Path.Combine(this.directory, "defragged.edb");
            Assert.IsTrue(EseInteropTestHelper.FileExists(this.database));
#endif // !MANAGEDESENT_ON_WSA
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);

            Api.JetOpenDatabase(this.sesId, this.database, null, out this.databaseId, OpenDatabaseGrbit.None);
            Api.JetOpenTable(this.sesId, this.databaseId, this.tableName, null, 0, OpenTableGrbit.None, out this.tableId);

            // validate order after having closed the database and restarted
            ulong ulongPrev;
            ulong ulongCur;
            Api.JetMove(this.sesId, this.tableId, JET_Move.First, MoveGrbit.None);
            int    bytesRead;
            byte[] data = new byte[8];
            Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
            ulongPrev = BitConverter.ToUInt64(data, 0);
            for (int i = 1; i < 3; i++)
            {
                Api.JetMove(this.sesId, this.tableId, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
                ulongCur = BitConverter.ToUInt64(data, 0);
                Assert.IsTrue(ulongCur.CompareTo(ulongPrev) > 0);
                ulongPrev = ulongCur;
            }

            EseInteropTestHelper.ConsoleWriteLine("Validated order.");

            // retrieve newly inserted ULongLong from index and compare values
            // to test denormalization logic
            ulong  ulongT   = 0;
            byte[] keyArray = BitConverter.GetBytes(ulongT);
            Api.JetSetCurrentIndex(this.sesId, this.tableId, this.secIndexName);
            Api.JetMakeKey(this.sesId, this.tableId, keyArray, keyArray.Length, MakeKeyGrbit.NewKey);
            Api.JetSeek(this.sesId, this.tableId, SeekGrbit.SeekEQ);
            JET_wrn err = Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, RetrieveColumnGrbit.RetrieveFromIndex, null);
            Assert.AreEqual(data.Length, bytesRead);
            ulongCur = BitConverter.ToUInt64(data, 0);
            Assert.IsTrue(ulongCur.CompareTo(ulongT) == 0);

            EseInteropTestHelper.ConsoleWriteLine("Retrieved ulong is:");
            EseInteropTestHelper.ConsoleWriteLine(ulongCur.ToString());
            Assert.IsTrue(ulongCur.CompareTo(ulongT) == 0);
            EseInteropTestHelper.ConsoleWriteLine("Retrieve from index matches inserted ULongLong");

            Api.JetCloseTable(this.sesId, this.tableId);
        }
Beispiel #29
0
        public void HowDoIDealWithMultivalues()
        {
            JET_SESID sesid = this.testSession;
            JET_DBID  dbid  = this.testDbid;

            JET_TABLEID   tableid;
            JET_COLUMNDEF columndef = new JET_COLUMNDEF();
            JET_COLUMNID  tagColumn;

            Api.JetCreateTable(sesid, dbid, "table", 0, 100, out tableid);

            // Create the column. Any column can be multivalued. Using
            // ColumndefGrbit controls how the column is indexed.
            columndef.coltyp = JET_coltyp.LongText;
            columndef.cp     = JET_CP.Unicode;
            columndef.grbit  = ColumndefGrbit.ColumnMultiValued;
            Api.JetAddColumn(sesid, tableid, "tags", columndef, null, 0, out tagColumn);

            // Create the index. There will be one entry in the index for each
            // instance of the multivalued column.
            const string IndexKey = "+tags\0\0";

            Api.JetCreateIndex(sesid, tableid, "tagsindex", CreateIndexGrbit.None, IndexKey, IndexKey.Length, 100);

            Api.JetBeginTransaction(sesid);

            // Now insert a record. An ESENT column can have multiple instances (multivalues)
            // inside the same record. Each multivalue is identified by an itag, the first itag
            // in a sequence is 1.
            Api.JetPrepareUpdate(sesid, tableid, JET_prep.Insert);

            // With no JET_SETINFO specified, itag 1 will be set.
            byte[] data = Encoding.Unicode.GetBytes("foo");
            Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.None, null);

            // Set a column with a setinfo. The itagSequence in the setinfo will be 0, which
            // means the value will be added to the collection of values, i.e. the column will
            // have two instances, "foo" and "bar".
            JET_SETINFO setinfo = new JET_SETINFO();

            data = Encoding.Unicode.GetBytes("bar");
            Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.None, setinfo);

            // Add a third instance, explicitly setting the itagSequence
            data = Encoding.Unicode.GetBytes("baz");
            setinfo.itagSequence = 4;
            Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.None, setinfo);

            // Add a duplicate value, checking for uniqueness
            data = Encoding.Unicode.GetBytes("foo");
            setinfo.itagSequence = 0;
            try
            {
                Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.UniqueMultiValues, setinfo);
                Assert.Fail("Expected an EsentErrorException");
            }
            catch (EsentErrorException ex)
            {
                Assert.AreEqual(JET_err.MultiValuedDuplicate, ex.Error);
            }

            Api.JetUpdate(sesid, tableid);

            // Find the record. We can seek for any column instance.
            Api.JetSetCurrentIndex(sesid, tableid, "tagsindex");
            Api.MakeKey(sesid, tableid, "bar", Encoding.Unicode, MakeKeyGrbit.NewKey);
            Assert.IsTrue(Api.TrySeek(sesid, tableid, SeekGrbit.SeekEQ));

            // Retrieve the number of column instances. This can be done with JetRetrieveColumns by setting
            // itagSequence to 0.
            JET_RETRIEVECOLUMN retrievecolumn = new JET_RETRIEVECOLUMN();

            retrievecolumn.columnid     = tagColumn;
            retrievecolumn.itagSequence = 0;
            Api.JetRetrieveColumns(sesid, tableid, new[] { retrievecolumn }, 1);
            EseInteropTestHelper.ConsoleWriteLine("Api.JetRetrieveColumns retrieved {0} multi-values.", retrievecolumn.itagSequence);
            Assert.AreEqual(3, retrievecolumn.itagSequence);

            // Use Api.RetrieveColumns() to get the number of multi-values.
            StringColumnValue retrieveStringColumnValue = new StringColumnValue();

            retrieveStringColumnValue.Columnid     = tagColumn;
            retrieveStringColumnValue.ItagSequence = 0;
            Api.RetrieveColumns(sesid, tableid, retrieveStringColumnValue);
            EseInteropTestHelper.ConsoleWriteLine("Api.RetrieveColumns retrieved {0} multi-values.", retrieveStringColumnValue.ItagSequence);
            Assert.AreEqual(3, retrieveStringColumnValue.ItagSequence);

            // Retrieve all the columns
            for (int itag = 1; itag <= retrievecolumn.itagSequence; ++itag)
            {
                JET_RETINFO retinfo = new JET_RETINFO {
                    itagSequence = itag
                };
                byte[] rawBytes = Api.RetrieveColumn(sesid, tableid, tagColumn, RetrieveColumnGrbit.None, retinfo);
                string s        = Encoding.Unicode.GetString(rawBytes, 0, rawBytes.Length);
                EseInteropTestHelper.ConsoleWriteLine("{0}: {1}", itag, s);
            }

            // Update the record
            Api.JetPrepareUpdate(sesid, tableid, JET_prep.Replace);

            // With no JET_SETINFO specified, itag 1 will be set, overwriting the existing value.
            data = Encoding.Unicode.GetBytes("qux");
            Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.None, null);

            // Set an instance to null to delete it.
            setinfo.itagSequence = 2;
            Api.JetSetColumn(sesid, tableid, tagColumn, null, 0, SetColumnGrbit.None, setinfo);

            // Removing itag 2 moved the other itags down (i.e. itag 3 became itag 2).
            // Overwrite itag 2.
            data = Encoding.Unicode.GetBytes("xyzzy");
            setinfo.itagSequence = 2;
            Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.None, setinfo);

            // Now add a new instance by setting itag 0. This instance will go at the end.
            data = Encoding.Unicode.GetBytes("flob");
            setinfo.itagSequence = 0;
            Api.JetSetColumn(sesid, tableid, tagColumn, data, data.Length, SetColumnGrbit.None, setinfo);

            Api.JetUpdate(sesid, tableid);

            // Retrieve the number of column instances again.
            retrievecolumn.itagSequence = 0;
            Api.JetRetrieveColumns(sesid, tableid, new[] { retrievecolumn }, 1);

            // Retrieve all the columns
            for (int itag = 1; itag <= retrievecolumn.itagSequence; ++itag)
            {
                JET_RETINFO retinfo = new JET_RETINFO {
                    itagSequence = itag
                };
                byte[] rawBytes = Api.RetrieveColumn(sesid, tableid, tagColumn, RetrieveColumnGrbit.None, retinfo);
                string s        = Encoding.Unicode.GetString(rawBytes, 0, rawBytes.Length);
                EseInteropTestHelper.ConsoleWriteLine("{0}: {1}", itag, s);
            }

            Api.JetCommitTransaction(sesid, CommitTransactionGrbit.LazyFlush);
        }