X Tutup
#region License // The PostgreSQL License // // Copyright (C) 2017 The Npgsql Development Team // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose, without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph and the following two paragraphs appear in all copies. // // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #endregion using System; using System.Collections; using System.Collections.Generic; using System.Data.Common; using System.Diagnostics; using JetBrains.Annotations; using NpgsqlTypes; namespace Npgsql { /// /// Represents a collection of parameters relevant to a NpgsqlCommand /// as well as their respective mappings to columns in a DataSet. /// This class cannot be inherited. /// public sealed class NpgsqlParameterCollection : DbParameterCollection, IList { readonly List _internalList = new List(5); // Dictionary lookups for GetValue to improve performance Dictionary _lookup; Dictionary _lookupIgnoreCase; /// /// Initializes a new instance of the NpgsqlParameterCollection class. /// internal NpgsqlParameterCollection() { InvalidateHashLookups(); } /// /// Invalidate the hash lookup tables. This should be done any time a change /// may throw the lookups out of sync with the list. /// internal void InvalidateHashLookups() { _lookup = null; _lookupIgnoreCase = null; } #region NpgsqlParameterCollection Member /// /// Gets the NpgsqlParameter with the specified name. /// /// The name of the NpgsqlParameter to retrieve. /// The NpgsqlParameter with the specified name, or a null reference if the parameter is not found. [PublicAPI] public new NpgsqlParameter this[string parameterName] { get { var index = IndexOf(parameterName); if (index == -1) throw new ArgumentException("Parameter not found"); return _internalList[index]; } set { var index = IndexOf(parameterName); if (index == -1) { throw new ArgumentException("Parameter not found"); } var oldValue = _internalList[index]; if (value.CleanName != oldValue.CleanName) { InvalidateHashLookups(); } _internalList[index] = value; } } /// /// Gets the NpgsqlParameter at the specified index. /// /// The zero-based index of the NpgsqlParameter to retrieve. /// The NpgsqlParameter at the specified index. [PublicAPI] public new NpgsqlParameter this[int index] { get => _internalList[index]; set { var oldValue = _internalList[index]; if (oldValue == value) { // Reasigning the same value is a non-op. return; } if (value.Collection != null) { throw new InvalidOperationException("The parameter already belongs to a collection"); } if (value.CleanName != oldValue.CleanName) { InvalidateHashLookups(); } _internalList[index] = value; value.Collection = this; oldValue.Collection = null; } } /// /// Adds the specified NpgsqlParameter object to the NpgsqlParameterCollection. /// /// The NpgsqlParameter to add to the collection. /// The index of the new NpgsqlParameter object. public NpgsqlParameter Add(NpgsqlParameter value) { // Do not allow parameters without name. if (value.Collection != null) { throw new InvalidOperationException("The parameter already belongs to a collection"); } _internalList.Add(value); value.Collection = this; InvalidateHashLookups(); // Check if there is a name. If not, add a name based of the index+1 of the parameter. if (value.ParameterName.Trim() == string.Empty || (value.ParameterName.Length == 1 && value.ParameterName[0] == ':')) { value.ParameterName = ":" + "Parameter" + _internalList.Count; value.AutoAssignedName = true; } return value; } void ICollection.Add([NotNull] NpgsqlParameter item) { Add(item); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// The paramater that was added. [PublicAPI] public NpgsqlParameter AddWithValue(string parameterName, object value) { return Add(new NpgsqlParameter(parameterName, value)); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name, data type and value. /// /// The name of the NpgsqlParameter. /// One of the NpgsqlDbType values. /// The Value of the NpgsqlParameter to add to the collection. /// The paramater that was added. [PublicAPI] public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, object value) { return Add(new NpgsqlParameter(parameterName, parameterType) { Value = value }); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// One of the NpgsqlDbType values. /// The length of the column. /// The paramater that was added. [PublicAPI] public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, int size, object value) { return Add(new NpgsqlParameter(parameterName, parameterType, size) { Value = value }); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// One of the NpgsqlDbType values. /// The length of the column. /// The name of the source column. /// The paramater that was added. [PublicAPI] public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn, object value) { return Add(new NpgsqlParameter(parameterName, parameterType, size, sourceColumn) { Value = value }); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified value. /// /// The Value of the NpgsqlParameter to add to the collection. /// The paramater that was added. [PublicAPI] public NpgsqlParameter AddWithValue(object value) { return Add(new NpgsqlParameter() { Value = value }); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified data type and value. /// /// One of the NpgsqlDbType values. /// The Value of the NpgsqlParameter to add to the collection. /// The paramater that was added. [PublicAPI] public NpgsqlParameter AddWithValue(NpgsqlDbType parameterType, object value) { return Add(new NpgsqlParameter { NpgsqlDbType = parameterType, Value = value }); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the parameter name and the data type. /// /// The name of the parameter. /// One of the DbType values. /// The index of the new NpgsqlParameter object. [PublicAPI] public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType) { return Add(new NpgsqlParameter(parameterName, parameterType)); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection with the parameter name, the data type, and the column length. /// /// The name of the parameter. /// One of the DbType values. /// The length of the column. /// The index of the new NpgsqlParameter object. [PublicAPI] public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size) { return Add(new NpgsqlParameter(parameterName, parameterType, size)); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection with the parameter name, the data type, the column length, and the source column name. /// /// The name of the parameter. /// One of the DbType values. /// The length of the column. /// The name of the source column. /// The index of the new NpgsqlParameter object. [PublicAPI] public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn) { return Add(new NpgsqlParameter(parameterName, parameterType, size, sourceColumn)); } #endregion #region IDataParameterCollection Member /// /// Removes the specified NpgsqlParameter from the collection using the parameter name. /// /// The name of the NpgsqlParameter object to retrieve. [PublicAPI] // ReSharper disable once ImplicitNotNullOverridesUnknownExternalMember public override void RemoveAt(string parameterName) { if (parameterName == null) throw new ArgumentNullException(nameof(parameterName)); RemoveAt(IndexOf(parameterName)); } /// /// Gets a value indicating whether a NpgsqlParameter with the specified parameter name exists in the collection. /// /// The name of the NpgsqlParameter object to find. /// true if the collection contains the parameter; otherwise, false. // ReSharper disable once ImplicitNotNullOverridesUnknownExternalMember public override bool Contains(string parameterName) { if (parameterName == null) throw new ArgumentNullException(nameof(parameterName)); return (IndexOf(parameterName) != -1); } /// /// Gets the location of the NpgsqlParameter in the collection with a specific parameter name. /// /// The name of the NpgsqlParameter object to find. /// The zero-based location of the NpgsqlParameter in the collection. public override int IndexOf([CanBeNull] string parameterName) { if (parameterName == null) { return -1; } int retIndex; int scanIndex; if (parameterName.Length > 0 && ((parameterName[0] == ':') || (parameterName[0] == '@'))) { parameterName = parameterName.Remove(0, 1); } // Using a dictionary is much faster for 5 or more items if (_internalList.Count >= 5) { if (_lookup == null) { _lookup = new Dictionary(); for (scanIndex = 0 ; scanIndex < _internalList.Count ; scanIndex++) { var item = _internalList[scanIndex]; // Store only the first of each distinct value if (! _lookup.ContainsKey(item.CleanName)) { _lookup.Add(item.CleanName, scanIndex); } } } // Try to access the case sensitive parameter name first if (_lookup.TryGetValue(parameterName, out retIndex)) { return retIndex; } // Case sensitive lookup failed, generate a case insensitive lookup if (_lookupIgnoreCase == null) { _lookupIgnoreCase = new Dictionary(PGUtil.InvariantCaseIgnoringStringComparer); for (scanIndex = 0 ; scanIndex < _internalList.Count ; scanIndex++) { var item = _internalList[scanIndex]; // Store only the first of each distinct value if (!_lookupIgnoreCase.ContainsKey(item.CleanName)) { _lookupIgnoreCase.Add(item.CleanName, scanIndex); } } } // Then try to access the case insensitive parameter name if (_lookupIgnoreCase.TryGetValue(parameterName, out retIndex)) { return retIndex; } return -1; } retIndex = -1; // Scan until a case insensitive match is found, and save its index for possible return. // Items that don't match loosely cannot possibly match exactly. for (scanIndex = 0 ; scanIndex < _internalList.Count ; scanIndex++) { var item = _internalList[scanIndex]; var comparer = PGUtil.InvariantCaseIgnoringStringComparer; if (comparer.Compare(parameterName, item.CleanName) == 0) { retIndex = scanIndex; break; } } // Then continue the scan until a case sensitive match is found, and return it. // If a case insensitive match was found, it will be re-checked for an exact match. for ( ; scanIndex < _internalList.Count ; scanIndex++) { var item = _internalList[scanIndex]; if (item.CleanName == parameterName) { return scanIndex; } } // If a case insensitive match was found, it will be returned here. return retIndex; } #endregion #region IList Member #if !NETSTANDARD1_3 /// /// Report whether the collection is read only. Always false. /// public override bool IsReadOnly => false; #endif /// /// Removes the specified NpgsqlParameter from the collection using a specific index. /// /// The zero-based index of the parameter. public override void RemoveAt(int index) { if (_internalList.Count - 1 < index) { throw new IndexOutOfRangeException(); } Remove(_internalList[index]); } /// /// Inserts a NpgsqlParameter into the collection at the specified index. /// /// The zero-based index where the parameter is to be inserted within the collection. /// The NpgsqlParameter to add to the collection. public override void Insert(int index, [NotNull] object oValue) { if (oValue == null) throw new ArgumentNullException(nameof(oValue)); CheckType(oValue); var value = oValue as NpgsqlParameter; Debug.Assert(value != null); if (value.Collection != null) { throw new InvalidOperationException("The parameter already belongs to a collection"); } value.Collection = this; _internalList.Insert(index, value); InvalidateHashLookups(); } /// /// Removes the specified NpgsqlParameter from the collection. /// /// The name of the NpgsqlParameter to remove from the collection. [PublicAPI] public void Remove(string parameterName) { var index = IndexOf(parameterName); if (index < 0) { throw new InvalidOperationException("No parameter with the specified name exists in the collection"); } RemoveAt(index); } /// /// Removes the specified NpgsqlParameter from the collection. /// /// The NpgsqlParameter to remove from the collection. public override void Remove([NotNull] object oValue) { if (oValue == null) throw new ArgumentNullException(nameof(oValue)); CheckType(oValue); var p = oValue as NpgsqlParameter; Debug.Assert(p != null); Remove(p); } /// /// Gets a value indicating whether a NpgsqlParameter exists in the collection. /// /// The value of the NpgsqlParameter object to find. /// true if the collection contains the NpgsqlParameter object; otherwise, false. // ReSharper disable once AnnotationRedundancyInHierarchy public override bool Contains([CanBeNull] object value) { if (!(value is NpgsqlParameter)) { return false; } return _internalList.Contains((NpgsqlParameter) value); } /// /// Gets a value indicating whether a NpgsqlParameter with the specified parameter name exists in the collection. /// /// The name of the NpgsqlParameter object to find. /// A reference to the requested parameter is returned in this out param if it is found in the list. This value is null if the parameter is not found. /// true if the collection contains the parameter and param will contain the parameter; otherwise, false. [ContractAnnotation("=>true,parameter:notnull; =>false,parameter:null")] public bool TryGetValue(string parameterName, [CanBeNull] out NpgsqlParameter parameter) { var index = IndexOf(parameterName); if (index != -1) { parameter = _internalList[index]; return true; } else { parameter = null; return false; } } /// /// Removes all items from the collection. /// public override void Clear() { foreach (var toRemove in _internalList) { // clean up the parameter so it can be added to another command if required. toRemove.Collection = null; } _internalList.Clear(); InvalidateHashLookups(); } /// /// Gets the location of a NpgsqlParameter in the collection. /// /// The value of the NpgsqlParameter object to find. /// The zero-based index of the NpgsqlParameter object in the collection. // ReSharper disable once ImplicitNotNullConflictInHierarchy public override int IndexOf([NotNull] object value) { if (value == null) throw new ArgumentNullException(nameof(value)); CheckType(value); return _internalList.IndexOf((NpgsqlParameter) value); } /// /// Adds the specified NpgsqlParameter object to the NpgsqlParameterCollection. /// /// The NpgsqlParameter to add to the collection. /// The zero-based index of the new NpgsqlParameter object. public override int Add([NotNull] object value) { CheckType(value); Add((NpgsqlParameter) value); return Count - 1; } #if !NETSTANDARD1_3 /// /// Report whether the collection is fixed size. Always false. /// public override bool IsFixedSize => false; #endif #endregion #region ICollection Member #if !NETSTANDARD1_3 /// /// Report whether the collection is synchronized. /// public override bool IsSynchronized => (_internalList as ICollection).IsSynchronized; #endif /// /// Gets the number of NpgsqlParameter objects in the collection. /// /// The number of NpgsqlParameter objects in the collection. public override int Count => _internalList.Count; /// /// Copies NpgsqlParameter objects from the NpgsqlParameterCollection to the specified array. /// /// An Array to which to copy the NpgsqlParameter objects in the collection. /// The starting index of the array. // ReSharper disable once ImplicitNotNullConflictInHierarchy public override void CopyTo([NotNull] Array array, int index) { if (array == null) throw new ArgumentNullException(nameof(array)); (_internalList as ICollection).CopyTo(array, index); } /// /// Gets a value indicating whether the ICollection{T} is read-only. /// bool ICollection.IsReadOnly => false; /// /// Sync root. /// public override object SyncRoot => (_internalList as ICollection).SyncRoot; #endregion #region IEnumerable Member IEnumerator IEnumerable.GetEnumerator() { return _internalList.GetEnumerator(); } /// /// Returns an enumerator that can iterate through the collection. /// /// An IEnumerator that can be used to iterate through the collection. public override IEnumerator GetEnumerator() { return _internalList.GetEnumerator(); } #endregion /// /// Add an Array of parameters to the collection. /// /// Parameters to add. public override void AddRange([NotNull]Array values) { foreach (NpgsqlParameter parameter in values) Add(parameter); } /// /// Get parameter. /// /// /// // ReSharper disable once ImplicitNotNullOverridesUnknownExternalMember protected override DbParameter GetParameter(string parameterName) { if (parameterName == null) throw new ArgumentNullException(nameof(parameterName)); return this[parameterName]; } /// /// Get parameter. /// /// /// protected override DbParameter GetParameter(int index) { return this[index]; } /// /// Set parameter. /// /// /// // ReSharper disable once ImplicitNotNullOverridesUnknownExternalMember protected override void SetParameter(string parameterName, [NotNull] DbParameter value) { if (parameterName == null) throw new ArgumentNullException(nameof(parameterName)); this[parameterName] = (NpgsqlParameter) value; } /// /// Set parameter. /// /// /// protected override void SetParameter(int index, [NotNull] DbParameter value) { this[index] = (NpgsqlParameter) value; } void CheckType(object o) { if (!(o is NpgsqlParameter)) throw new InvalidCastException($"Can't cast {o.GetType()} into NpgsqlParameter"); } /* /// /// In methods taking an array as argument this method is used to verify /// that the argument has the type NpgsqlParameter[] /// /// The array to verify private void CheckType(Array array) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckType", array); if (array.GetType() != typeof(NpgsqlParameter[])) { throw new InvalidCastException( String.Format(this.resman.GetString("Exception_WrongType"), array.GetType().ToString())); } } */ /// /// Report the offset within the collection of the given parameter. /// /// Parameter to find. /// Index of the parameter, or -1 if the parameter is not present. [PublicAPI] public int IndexOf([NotNull] NpgsqlParameter item) { return _internalList.IndexOf(item); } /// /// Insert the specified parameter into the collection. /// /// Index of the existing parameter before which to insert the new one. /// Parameter to insert. [PublicAPI] public void Insert(int index, [NotNull] NpgsqlParameter item) { if (item.Collection != null) throw new Exception("The parameter already belongs to a collection"); _internalList.Insert(index, item); item.Collection = this; InvalidateHashLookups(); } /// /// Report whether the specified parameter is present in the collection. /// /// Parameter to find. /// True if the parameter was found, otherwise false. [PublicAPI] public bool Contains([NotNull] NpgsqlParameter item) => _internalList.Contains(item); /// /// Remove the specified parameter from the collection. /// /// Parameter to remove. /// True if the parameter was found and removed, otherwise false. [PublicAPI] public bool Remove([NotNull] NpgsqlParameter item) { if (item == null) throw new ArgumentNullException(nameof(item)); if (item.Collection != this) throw new InvalidOperationException("The item does not belong to this collection"); if (_internalList.Remove(item)) { item.Collection = null; InvalidateHashLookups(); return true; } return false; } /// /// Convert collection to a System.Array. /// /// Destination array. /// Starting index in destination array. [PublicAPI] public void CopyTo([NotNull] NpgsqlParameter[] array, int arrayIndex) => _internalList.CopyTo(array, arrayIndex); /// /// Convert collection to a System.Array. /// /// NpgsqlParameter[] [PublicAPI] public NpgsqlParameter[] ToArray() => _internalList.ToArray(); internal void CloneTo(NpgsqlParameterCollection other) { other._internalList.Clear(); foreach (var param in _internalList) { var newParam = param.Clone(); newParam.Collection = this; other._internalList.Add(newParam); } other._lookup = _lookup; other._lookupIgnoreCase = _lookupIgnoreCase; } internal bool HasOutputParameters { get { foreach (var p in _internalList) if (p.IsOutputDirection) return true; return false; } } } }
X Tutup