/// <summary> /// Returns a key containing one ordinary key segment per given value /// and one wildcard key segment. /// </summary> /// <param name="values">the values for each key column that will be used to compose the key</param> /// <returns>A key containing one ordinary key segment per given value /// and one wildcard key segment.</returns> /// <seealso cref="Compose"/> /// <seealso cref="ComposePrefix"/> public static Key ComposeWildcard(params object[] values) { Key key = new Key(); foreach (object value in values) { key.Add(value); } key.AddWildcard(); return key; }
/// <summary> /// Returns a key containing one ordinary key segment per given value /// except that the last given value becomes a prefix key segment. /// </summary> /// <param name="values">the values for each key column that will be used to compose the key</param> /// <returns>A key containing one ordinary key segment per given value /// except that the last given value becomes a prefix key segment.</returns> /// <seealso cref="Compose"/> /// <seealso cref="ComposeWildcard"/> public static Key ComposePrefix(params object[] values) { Key key = new Key(); for (int i = 0; i < values.Length - 1; i++) { key.Add(values[i]); } key.AddPrefix(values[values.Length - 1]); return key; }
/// <summary> /// Position the cursor at the specified key on the current index /// </summary> /// <param name="key">The full key for the desired record on the current index of the cursor</param> /// <remarks> /// Only fully qualified keys are allowed. Partial keys and wildcards /// are forbidden. /// </remarks> /// <returns>true if a record was found, false otherwise</returns> public bool GotoKey(Key key) { lock (this.isamSession) { this.CheckDisposed(); // if this is a Sort then seek is illegal // // NOTE: this is a hack to work around problems in ESE/ESENT // that we cannot fix because we must work downlevel if (this.isSort) { throw new EsentIllegalOperationException(); } this.OnNavigation(); // we only allow fully qualified keys here if (key.HasPrefix) { throw new ArgumentException("Keys containing prefixes are forbidden", "key"); } if (key.HasWildcard) { throw new ArgumentException("Keys containing wildcards are forbidden", "key"); } // compute the key for our seek Api.MakeKey(this.isamSession.Sesid, this.tableid, this.MakeKey(key, false), MakeKeyGrbit.NormalizedKey); // seek for the record that exactly matches this key and remember // if we found it bool found = Api.TrySeek(this.isamSession.Sesid, this.tableid, SeekGrbit.SeekEQ); // clear our field cache because the current record has changed this.fields = null; // if we found a record outside the index range then it doesn't count found = this.CheckRange() && found; return found; } }
/// <summary> /// Restricts the records that are visible to the cursor to a range of /// the current index delineated by the specified keys. /// </summary> /// <param name="keyStart">The partial or full key used to set the start of the records to find on the current index</param> /// <param name="criteriaStart">Indicates if the starting key is inclusive or exclusive</param> /// <param name="keyEnd">The partial or full key used to set the end of the records to find on the current index</param> /// <param name="criteriaEnd">Indicates if the ending key is inclusive or exclusive</param> /// <remarks> /// The restriction will remain in effect until explicitly reset or /// until implicitly reset by other methods as noted. /// <para> /// Any previously defined restriction will be cleared. /// </para> /// <para> /// The cursor will be positioned before the first record in the new /// restriction. /// </para> /// </remarks> public void FindRecordsBetween(Key keyStart, BoundCriteria criteriaStart, Key keyEnd, BoundCriteria criteriaEnd) { lock (this.isamSession) { this.CheckDisposed(); this.OnNavigation(); // clear our index range this.FindAllRecords(); // setup the effective index range to be bounded by the specified keys this.keyStart = this.MakeKey(keyStart, false); this.grbitSeekStart = criteriaStart == BoundCriteria.Inclusive ? SeekGrbit.SeekGE : SeekGrbit.SeekGT; this.grbitRangeStart = criteriaStart == BoundCriteria.Inclusive ? SetIndexRangeGrbit.RangeInclusive : SetIndexRangeGrbit.None; this.keyEnd = this.MakeKey(keyEnd, true); this.grbitSeekEnd = criteriaEnd == BoundCriteria.Inclusive ? SeekGrbit.SeekLE : SeekGrbit.SeekLT; this.grbitRangeEnd = (criteriaEnd == BoundCriteria.Inclusive ? SetIndexRangeGrbit.RangeInclusive : SetIndexRangeGrbit.None) | SetIndexRangeGrbit.RangeUpperLimit; // move before first on the new index range this.MoveBeforeFirst(); } }
/// <summary> /// Restricts the records that are visible to the cursor to those that /// match the given key by the given criteria. The key may contain /// prefix or wildcard key segments which can be used to further /// qualify the desired matching records. /// </summary> /// <param name="criteria">The inequality used to specify which records to find on the current index</param> /// <param name="key">The partial or full key used to specify which records to find on the current index</param> /// <remarks> /// The restriction will remain in effect until explicitly reset or /// until implicitly reset by other methods as noted. /// <para> /// Any previously defined restriction will be cleared. /// </para> /// <para> /// The cursor will be positioned before the first record in the new /// restriction. /// </para> /// </remarks> public void FindRecords(MatchCriteria criteria, Key key) { switch (criteria) { case MatchCriteria.LessThan: this.FindRecordsBetween(Key.Start, BoundCriteria.Inclusive, key, BoundCriteria.Exclusive); break; case MatchCriteria.LessThanOrEqualTo: this.FindRecordsBetween(Key.Start, BoundCriteria.Inclusive, key, BoundCriteria.Inclusive); break; case MatchCriteria.EqualTo: this.FindRecordsBetween(key, BoundCriteria.Inclusive, key, BoundCriteria.Inclusive); break; case MatchCriteria.GreaterThanOrEqualTo: this.FindRecordsBetween(key, BoundCriteria.Inclusive, Key.End, BoundCriteria.Inclusive); break; case MatchCriteria.GreaterThan: this.FindRecordsBetween(key, BoundCriteria.Exclusive, Key.End, BoundCriteria.Inclusive); break; } }
/// <summary> /// Makes the key. /// </summary> /// <param name="key">The key.</param> /// <param name="end">if set to <c>true</c> specifies that the key represents the End Limit /// (<see cref="MakeKeyGrbit.PartialColumnStartLimit"/>/<see cref="MakeKeyGrbit.PartialColumnEndLimit"/>/ /// <see cref="MakeKeyGrbit.FullColumnStartLimit"/>/<see cref="MakeKeyGrbit.FullColumnEndLimit"/>).</param> /// <returns>The byte value of the key for the index entry /// at the current position of a cursor.</returns> /// <exception cref="System.ArgumentException">the provided key must have a key segment per key column on the current index or it must contain a prefix or wildcard;key</exception> private byte[] MakeKey(Key key, bool end) { lock (this.isamSession) { bool firstSegment = true; int i = 0; foreach (KeySegment segment in key) { if (i < this.CurrentIndexDefinition.KeyColumns.Count) { KeyColumn keyColumn = this.CurrentIndexDefinition.KeyColumns[i]; byte[] value = null; if (!(segment.Value == null || segment.Value is DBNull)) { Columnid isamColumnid = keyColumn.Columnid; value = Converter.BytesFromObject(isamColumnid.Coltyp, false, segment.Value); } MakeKeyGrbit grbit = MakeKeyGrbit.None; if (firstSegment == true) { grbit = grbit | MakeKeyGrbit.NewKey; } if (value != null && value.Length == 0) { grbit = grbit | MakeKeyGrbit.KeyDataZeroLength; } if (segment.Prefix == true) { if (end == false) { grbit = grbit | MakeKeyGrbit.PartialColumnStartLimit; } else { grbit = grbit | MakeKeyGrbit.PartialColumnEndLimit; } } else if (segment.WildcardIsNext() == true) { if (end == false) { grbit = grbit | MakeKeyGrbit.FullColumnStartLimit; } else { grbit = grbit | MakeKeyGrbit.FullColumnEndLimit; } } if (segment.Wildcard == false) { int valueLength = value == null ? 0 : value.Length; Api.JetMakeKey(this.isamSession.Sesid, this.tableid, value, valueLength, grbit); firstSegment = false; } } i++; } if (i < this.CurrentIndexDefinition.KeyColumns.Count && key.HasPrefix == false && key.HasWildcard == false) { throw new ArgumentException( "the provided key must have a key segment per key column on the current index or it must contain a prefix or wildcard", "key"); } if (firstSegment) { return null; } return Api.RetrieveKey(this.isamSession.Sesid, this.tableid, RetrieveKeyGrbit.RetrieveCopy); } }