forked from kenjiuno/Npgsql
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathPreparedStatement.cs
More file actions
157 lines (129 loc) · 5.18 KB
/
PreparedStatement.cs
File metadata and controls
157 lines (129 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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(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
}
}