/// <summary>Store the column value in the database.</summary> public override void Serialize(EseCursorBase cur, JET_COLUMNID idColumn, object value, bool bNewRecord) { if (!bNewRecord) { // If this is an UPDATE operation, erase the old values. JET_SETINFO si = new JET_SETINFO(); for (int itg = GetValuesCountSilent(cur, idColumn); itg > 0; itg--) { si.ibLongValue = 0; si.itagSequence = itg; Api.JetSetColumn(cur.idSession, cur.idTable, idColumn, null, 0, SetColumnGrbit.None, si); } } var arr = value as int[]; if (null == arr) { return; } // Set new values foreach (var s in arr) { AddValue(cur, idColumn, s); } }
/// <summary> /// Sets the column. /// </summary> /// <param name="columnid">The columnid.</param> /// <param name="coltyp">The coltyp.</param> /// <param name="isAscii">Whether a textual column is Ascii.</param> /// <param name="index">The index.</param> /// <param name="obj">The object.</param> /// <exception cref="System.InvalidOperationException">You may only update fields through Cursor.EditRecord.</exception> /// <remarks> /// Itags start at 1, so we add 1 to the index /// </remarks> private void SetColumn(JET_COLUMNID columnid, JET_coltyp coltyp, bool isAscii, int index, object obj) { lock (this.isamSession) { this.cursor.CheckDisposed(); if ((this.grbit & RetrieveColumnGrbit.RetrieveCopy) == 0) { this.cursor.CheckRecord(); throw new InvalidOperationException("You may only update fields through Cursor.EditRecord."); } // if this is a Sort or PreSortTemporary TT and we are setting // an LV column then always attempt to use intrinsic LVs SetColumnGrbit grbitSet = SetColumnGrbit.None; if ((this.cursor.TableDefinition.Type == TableType.Sort || this.cursor.TableDefinition.Type == TableType.PreSortTemporary) && (coltyp == JET_coltyp.LongText || coltyp == JET_coltyp.LongBinary)) { grbitSet = grbitSet | SetColumnGrbit.IntrinsicLV; } JET_SETINFO setinfo = new JET_SETINFO(); setinfo.ibLongValue = 0; setinfo.itagSequence = index + 1; byte[] bytes = Converter.BytesFromObject(coltyp, isAscii, obj); int bytesLength = bytes == null ? 0 : bytes.Length; Api.JetSetColumn(this.isamSession.Sesid, this.tableid, columnid, bytes, bytesLength, grbitSet, setinfo); this.updateID++; } }
// Append the given value to this column void AddValue(EseCursorBase cur, JET_COLUMNID idColumn, int val) { byte[] data = BitConverter.GetBytes(val); JET_SETINFO si = new JET_SETINFO(); si.itagSequence = 0; Api.JetSetColumn(cur.idSession, cur.idTable, idColumn, data, data.Length, SetColumnGrbit.None, si); }
public void ConvertSetinfoToNativeWhenItagSequenceIsNegative() { var setinfo = new JET_SETINFO { ibLongValue = 0, itagSequence = Int32.MinValue }; NATIVE_SETINFO native = setinfo.GetNativeSetinfo(); }
public void VerifySetinfoCanBeSerialized() { var expected = new JET_SETINFO { ibLongValue = 5, itagSequence = 6 }; SerializeAndCompareContent(expected); }
public void JetSetinfoToString() { var value = new JET_SETINFO { ibLongValue = 1, itagSequence = 2 }; Assert.AreEqual("JET_SETINFO(ibLongValue=1,itagSequence=2)", value.ToString()); }
/// <summary> /// Updates a record setting the given column set to the specified value. /// </summary> /// <param name="columnid">The column to set.</param> /// <param name="data">The data to set.</param> /// <param name="itagSequence">The itag sequence to set.</param> private void SetColumn(JET_COLUMNID columnid, byte[] data, int itagSequence) { var setinfo = new JET_SETINFO { ibLongValue = 0, itagSequence = itagSequence, }; Api.JetSetColumn(this.sesid, this.tableid, columnid, data, (null == data) ? 0 : data.Length, SetColumnGrbit.None, setinfo); }
public void VerifyJetSetinfoEquality() { var x = new JET_SETINFO { ibLongValue = 1, itagSequence = 2 }; var y = new JET_SETINFO { ibLongValue = 1, itagSequence = 2 }; TestContentEquals(x, y); }
public void ConvertSetinfoToNative() { var setinfo = new JET_SETINFO { ibLongValue = 1, itagSequence = 2 }; NATIVE_SETINFO native = setinfo.GetNativeSetinfo(); Assert.AreEqual(1U, native.ibLongValue); Assert.AreEqual(2U, native.itagSequence); }
public void Clear() { var si = new JET_SETINFO() { itagSequence = 1 }; for (var i = 0; i < Count; i++) { Api.JetSetColumn(_table.Session, _table.Table, _columnid, null, 0, SetColumnGrbit.None, si); } }
// Put the column value to the ESE. void LoadVal(string strVal, JET_COLUMNID idColumn, JET_coltyp ct, JET_CP cp) { if (String.IsNullOrEmpty(strVal)) { return; } byte[] val = null; if (ct == JET_coltyp.Currency) // int64 { val = BitConverter.GetBytes(Convert.ToUInt64(strVal, 16)); } else if (ct == JET_coltyp.Long) // int32 { val = BitConverter.GetBytes(Convert.ToUInt32(strVal, 16)); } else if (ct == JET_coltyp.Short) // int16 { val = BitConverter.GetBytes(Convert.ToUInt16(strVal, 16)); } else if (ct == JET_coltyp.UnsignedByte) // uint8 { val = new byte[1] { Convert.ToByte(strVal, 16) } } ; else if (ct == JET_coltyp.DateTime) // DateTime { DateTime dt = DateTime.Parse(strVal, null, System.Globalization.DateTimeStyles.RoundtripKind); double dbl = dt.ToOADate(); val = BitConverter.GetBytes(dbl); } else if (ct == JET_coltyp.Text || ct == JET_coltyp.LongText) // Text { if (cp == JET_CP.Unicode) { val = TSV.UnescapeUnicode(strVal).ToArray(); } else { val = TSV.UnescapeASCII(strVal).ToArray(); } } else { val = Convert.FromBase64String(strVal); // Anything else } JET_SETINFO si = new JET_SETINFO(); si.itagSequence = 0; Api.JetSetColumn(sess.idSession, idTable, idColumn, val, val.Length, SetColumnGrbit.None, si); }
protected void ClearMultiValue(EsentTable table, JET_COLUMNID columnid) { var cnt = GetMultiValueCount(table, columnid); var si = new JET_SETINFO() { itagSequence = 1 }; for (var i = 0; i < cnt; i++) { Api.JetSetColumn(table.Session, table.Table, columnid, null, 0, SetColumnGrbit.None, si); } }
/// <summary> /// Updates a record setting the given column set to the specified value. /// </summary> /// <param name="columnid">The column to set.</param> /// <param name="data">The data to set.</param> /// <param name="itagSequence">The itag sequence to set.</param> private void SetColumn(JET_COLUMNID columnid, byte[] data, int itagSequence) { Api.JetBeginTransaction(this.sesid); Api.JetPrepareUpdate(this.sesid, this.tableid, JET_prep.Replace); var setinfo = new JET_SETINFO { ibLongValue = 0, itagSequence = itagSequence, }; Api.JetSetColumn(this.sesid, this.tableid, columnid, data, (null == data) ? 0 : data.Length, SetColumnGrbit.None, setinfo); Api.JetUpdate(this.sesid, this.tableid); Api.JetCommitTransaction(this.sesid, CommitTransactionGrbit.LazyFlush); }
public void RemoveChannel(string channel) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Replace); try { // Get the existing channels var column = new JET_RETRIEVECOLUMN { columnid = _channelColumn, grbit = RetrieveColumnGrbit.RetrieveTag }; Api.JetRetrieveColumns(_sesid, _table, new[] { column }, 1); int count = column.itagSequence; for (int i = 1; i <= count; i++) { JET_RETINFO retinfo = new JET_RETINFO { itagSequence = i }; byte[] data = Api.RetrieveColumn(_sesid, _table, _channelColumn, RetrieveColumnGrbit.None, retinfo); if (channel.Equals(Encoding.ASCII.GetString(data), StringComparison.OrdinalIgnoreCase)) { JET_SETINFO setInfo = new JET_SETINFO(); setInfo.itagSequence = i; Api.JetSetColumn( _sesid, _table, _channelColumn, null, 0, SetColumnGrbit.None, setInfo ); break; } } Api.JetUpdate(_sesid, _table); } catch (Exception) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Cancel); throw; } }
/// <summary> /// Insert data into the data table. No record with the same key /// should exist. /// </summary> /// <param name="data">The data to add.</param> public void Insert(string subscriber, IEnumerable <string> channels) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Insert); try { // The easy part set the key Api.SetColumn( _sesid, _table, _subscriberColumn, subscriber, Encoding.ASCII ); // Loop through all the channels and create them, // as this is a new record there is no need for checks foreach (var channel in channels) { // Using tag sequence 0 wil mean the items are // automatically pushed into the mv-column JET_SETINFO setInfo = new JET_SETINFO(); setInfo.itagSequence = 0; // Note the use of ASCII to take up half the space // there is no reason either subscriber or channel // will have more than this byte[] data = Encoding.ASCII.GetBytes(channel); Api.JetSetColumn( _sesid, _table, _channelColumn, data, data.Length, SetColumnGrbit.UniqueMultiValues, setInfo ); } Api.JetUpdate(_sesid, _table); } catch (Exception) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Cancel); throw; } }
/// <summary> /// Insert a record with the given column values. After the insert the cursor is /// positioned on the record. /// </summary> /// <param name="key"> /// The key of the record. /// </param> /// <param name="values"> /// The column values to insert. /// </param> private void InsertRecord(int key, params string[] values) { using (var transaction = new Transaction(this.sesid)) using (var update = new Update(this.sesid, this.tableid, JET_prep.Insert)) { Api.SetColumn(this.sesid, this.tableid, this.keyColumn, key); foreach (string value in values) { var setinfo = new JET_SETINFO { ibLongValue = 0, itagSequence = 0, }; byte[] data = Encoding.Unicode.GetBytes(value); Api.JetSetColumn( this.sesid, this.tableid, this.multiValueColumn, data, data.Length, SetColumnGrbit.None, setinfo); } update.SaveAndGotoBookmark(); transaction.Commit(CommitTransactionGrbit.None); } }
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); Console.WriteLine("{0}", retrievecolumn.itagSequence); Assert.AreEqual(3, retrievecolumn.itagSequence); // Retrieve all the columns for (int itag = 1; itag <= retrievecolumn.itagSequence; ++itag) { JET_RETINFO retinfo = new JET_RETINFO { itagSequence = itag }; string s = Encoding.Unicode.GetString(Api.RetrieveColumn(sesid, tableid, tagColumn, RetrieveColumnGrbit.None, retinfo)); Console.WriteLine("{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 }; string s = Encoding.Unicode.GetString(Api.RetrieveColumn(sesid, tableid, tagColumn, RetrieveColumnGrbit.None, retinfo)); Console.WriteLine("{0}: {1}", itag, s); } Api.JetCommitTransaction(sesid, CommitTransactionGrbit.LazyFlush); }
public void Append(IEnumerable <string> channels) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Replace); try { // Get the existing channels var column = new JET_RETRIEVECOLUMN { columnid = _channelColumn, grbit = RetrieveColumnGrbit.RetrieveTag }; Api.JetRetrieveColumns(_sesid, _table, new[] { column }, 1); int count = column.itagSequence; var existing = new string[count]; for (int i = 1; i <= count; i++) { JET_RETINFO retinfo = new JET_RETINFO { itagSequence = i }; byte[] data = Api.RetrieveColumn(_sesid, _table, _channelColumn, RetrieveColumnGrbit.None, retinfo); var channel = Encoding.ASCII.GetString(data); existing[i - 1] = channel; } // Loop through all the channels and create them, // as this is a new record there is no need for checks foreach (var channel in channels) { // Only add the new ones if (Array.IndexOf(existing, channel) > -1) { continue; } // Using tag sequence 0 wil mean the items are // automatically pushed into the mv-column count++; JET_SETINFO setInfo = new JET_SETINFO(); setInfo.itagSequence = count; // Note the use of ASCII to take up half the space // there is no reason either subscriber or channel // will have more than this byte[] data = Encoding.ASCII.GetBytes(channel); Api.JetSetColumn( _sesid, _table, _channelColumn, data, data.Length, SetColumnGrbit.UniqueMultiValues, setInfo ); } Api.JetUpdate(_sesid, _table); } catch (Exception) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Cancel); throw; } }
private void SetEntry(CacheEntry entry, JET_prep updateType) { Api.JetPrepareUpdate(_sesid, _table, updateType); try { // The easy part set the key Api.SetColumn( _sesid, _table, _keyColumn, entry.Key, Encoding.Unicode ); Api.SetColumn( _sesid, _table, _dataColumn, entry.Data ); Api.SetColumn( _sesid, _table, _callbacksColumn, entry.PostEvicationCallbacks ); // Avoid race conditions on update by making sure the record // is clear if (updateType == JET_prep.Replace) { // Get the existing channels var column = new JET_RETRIEVECOLUMN { columnid = _dependencyColumn, grbit = RetrieveColumnGrbit.RetrieveTag }; Api.JetRetrieveColumns(_sesid, _table, new[] { column }, 1); // This is a bit tricky, note that when an item is removed all the // itag sequences update to be one lower int count = column.itagSequence; for (int i = 0; i < count; i++) { JET_SETINFO setInfo = new JET_SETINFO { itagSequence = 1 }; Api.JetSetColumn( _sesid, _table, _dependencyColumn, null, 0, SetColumnGrbit.UniqueMultiValues, setInfo ); } Api.SetColumn(_sesid, _table, _absoluteExpirationColumn, null); Api.SetColumn(_sesid, _table, _lastAccessedColumn, null); Api.SetColumn(_sesid, _table, _slidingExpirationColumn, null); } if (entry.AbsoluteExpiration > 0) { Api.SetColumn( _sesid, _table, _absoluteExpirationColumn, entry.AbsoluteExpiration ); } else if (entry.SlidingExpiration > 0) { Api.SetColumn( _sesid, _table, _lastAccessedColumn, Convert.ToInt64(entry.LastAccessed) ); Api.SetColumn( _sesid, _table, _slidingExpirationColumn, entry.SlidingExpiration ); } // Loop through all the channels and create them, // as this is a new record there is no need for checks foreach (var dependency in entry.Dependencies) { // Using tag sequence 0 wil mean the items are // automatically pushed into the mv-column JET_SETINFO setInfo = new JET_SETINFO(); setInfo.itagSequence = 0; // Note the use of ASCII to take up half the space // there is no reason either subscriber or channel // will have more than this byte[] data = Encoding.ASCII.GetBytes(dependency); Api.JetSetColumn( _sesid, _table, _dependencyColumn, data, data.Length, SetColumnGrbit.UniqueMultiValues, setInfo ); } Api.JetUpdate(_sesid, _table); } catch (Exception exp) { Api.JetPrepareUpdate(_sesid, _table, JET_prep.Cancel); throw exp; } }
// insert a record and update its long-values private void UpdateLongValues() { Console.WriteLine("\tUpdate Long-Values"); JET_TABLEID tableid; Api.JetOpenTable(this.sesid, this.dbid, this.table, null, 0, OpenTableGrbit.None, out tableid); int recordID = NumRecords + 17; var rand = new Random(recordID); var data = new byte[this.columnInfos.Length][]; Api.JetBeginTransaction(this.sesid); // insert the record using (var update = new Update(this.sesid, tableid, JET_prep.Insert)) { for (int i = 0; i < this.columnInfos.Length; ++i) { data[i] = null; if (string.Equals( this.columnInfos[i].Name, "recordID", StringComparison.InvariantCultureIgnoreCase)) { // this is the primary index column, set it to the recordID data[i] = BitConverter.GetBytes(recordID); } else if (this.columnInfos[i].Coltyp == JET_coltyp.LongBinary || this.columnInfos[i].Coltyp == JET_coltyp.LongText) { data[i] = DataGenerator.GetRandomColumnData( this.columnInfos[i].Coltyp, this.columnInfos[i].Cp, rand); } if (null != data[i]) { Api.SetColumn(this.sesid, tableid, this.columnInfos[i].Columnid, data[i]); } } update.SaveAndGotoBookmark(); } this.CheckColumns(this.sesid, tableid, data); // update the record using (var update = new Update(this.sesid, tableid, JET_prep.Replace)) { for (int i = 0; i < this.columnInfos.Length; ++i) { if (this.columnInfos[i].Coltyp == JET_coltyp.LongBinary || this.columnInfos[i].Coltyp == JET_coltyp.LongText) { int size = Api.RetrieveColumnSize(this.sesid, tableid, this.columnInfos[i].Columnid).Value; BasicClass.Assert(size == data[i].Length, "Invalid column size"); var setinfo = new JET_SETINFO(); setinfo.ibLongValue = size / 2; setinfo.itagSequence = 1; // the data that will be added to the column byte[] newdata = DataGenerator.GetRandomColumnData( this.columnInfos[i].Coltyp, this.columnInfos[i].Cp, rand); // what the final data should be byte[] finaldata = null; switch (rand.Next(2)) { case 0: // append Api.SetColumn( this.sesid, tableid, this.columnInfos[i].Columnid, newdata, SetColumnGrbit.AppendLV); finaldata = new byte[size + newdata.Length]; Array.Copy(data[i], finaldata, size); Array.Copy(newdata, 0, finaldata, size, newdata.Length); break; case 1: // overwrite and set size Api.JetSetColumn( this.sesid, tableid, this.columnInfos[i].Columnid, newdata, newdata.Length, SetColumnGrbit.SizeLV | SetColumnGrbit.OverwriteLV, setinfo); finaldata = new byte[setinfo.ibLongValue + newdata.Length]; Array.Copy(data[i], finaldata, setinfo.ibLongValue); Array.Copy(newdata, 0, finaldata, setinfo.ibLongValue, newdata.Length); break; } data[i] = finaldata; } } update.SaveAndGotoBookmark(); } this.CheckColumns(this.sesid, tableid, data); Api.JetCommitTransaction(this.sesid, CommitTransactionGrbit.LazyFlush); Api.JetCloseTable(this.sesid, tableid); }