/
dev-npgsql
/
npgsql
Обзор
Документация
Войти
/
dev-npgsql
/
npgsql
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
v4.1.15
src/Npgsql/PreparedStatement.cs
157 строк
5 KB
Романов Илья
Fixed error during preparing leaving PreparedStatementManager in a wrong state (#3117)
09 сен 2020, 15:33
09 сен 2020, 15:33
5aa892c
Код
Авторство
О чём код?
using System; using System.Collections.Generic; using System.Diagnostics; using Npgsql.BackendMessages; namespace Npgsql { /// <summary> /// Internally represents a statement has been prepared, is in the process of being prepared, or is a /// candidate for preparation (i.e. awaiting further usages). /// </summary> [DebuggerDisplay("{Name} ({State}): {Sql}")] class PreparedStatement { readonly PreparedStatementManager _manager; internal string Sql { get; } internal string? Name; internal RowDescriptionMessage? Description; internal int Usages; internal PreparedState State { get; set; } internal bool IsPrepared => State == PreparedState.Prepared; /// <summary> /// If true, the user explicitly requested this statement be prepared. It does not get closed as part of /// the automatic preparation LRU mechanism. /// </summary> internal bool IsExplicit { get; } /// <summary> /// If this statement is about to be prepared, but replaces a previous statement which needs to be closed, /// this holds the name of the previous statement. Otherwise null. /// </summary> internal PreparedStatement? StatementBeingReplaced; internal DateTime LastUsed { get; set; } /// <summary> /// Contains the handler types for a prepared statement's parameters, for overloaded cases (same SQL, different param types) /// Only populated after the statement has been prepared (i.e. null for candidates). /// </summary> internal Type[]? HandlerParamTypes { get; private set; } static readonly Type[] EmptyParamTypes = Type.EmptyTypes; internal static PreparedStatement CreateExplicit( PreparedStatementManager manager, string sql, string name, List<NpgsqlParameter> parameters, PreparedStatement? statementBeingReplaced) { var pStatement = new PreparedStatement(manager, sql, true) { Name = name, StatementBeingReplaced = statementBeingReplaced }; pStatement.SetParamTypes(parameters); return pStatement; } internal static PreparedStatement CreateAutoPrepareCandidate(PreparedStatementManager manager, string sql) => new PreparedStatement(manager, sql, false); PreparedStatement(PreparedStatementManager manager, string sql, bool isExplicit) { _manager = manager; Sql = sql; IsExplicit = isExplicit; State = PreparedState.NotPrepared; } internal void SetParamTypes(List<NpgsqlParameter> parameters) { Debug.Assert(HandlerParamTypes == null); if (parameters.Count == 0) { HandlerParamTypes = EmptyParamTypes; return; } HandlerParamTypes = new Type[parameters.Count]; for (var i = 0; i < parameters.Count; i++) HandlerParamTypes[i] = parameters[i].Handler!.GetType(); } internal bool DoParametersMatch(List<NpgsqlParameter> parameters) { if (HandlerParamTypes!.Length != parameters.Count) return false; for (var i = 0; i < HandlerParamTypes.Length; i++) if (HandlerParamTypes[i] != parameters[i].Handler!.GetType()) return false; return true; } internal void CompletePrepare() { Debug.Assert(HandlerParamTypes != null); _manager.BySql[Sql] = this; _manager.NumPrepared++; State = PreparedState.Prepared; } internal void CompleteUnprepare() { _manager.BySql.Remove(Sql); if (IsPrepared || State == PreparedState.BeingUnprepared) _manager.NumPrepared--; State = PreparedState.Unprepared; } public override string ToString() => Sql; } /// <summary> /// The state of a <see cref="PreparedStatement"/>. /// </summary> enum PreparedState { /// <summary> /// The statement hasn't been prepared yet, nor is it in the process of being prepared. /// This is the value for autoprepare candidates which haven't been prepared yet, and is also /// a temporary state during preparation. /// </summary> NotPrepared, /// <summary> /// The statement is in the process of being prepared. /// </summary> BeingPrepared, /// <summary> /// The statement has been fully prepared and can be executed. /// </summary> Prepared, /// <summary> /// The statement is in the process of being unprepared. This is a temporary state that only occurs during /// unprepare. Specifically, it means that a Close message for the statement has already been written /// to the write buffer. /// </summary> BeingUnprepared, /// <summary> /// The statement has been unprepared and is no longer usable. /// </summary> Unprepared } }