forked from npgsql/npgsql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPreparedStatement.cs
More file actions
166 lines (140 loc) · 5.77 KB
/
PreparedStatement.cs
File metadata and controls
166 lines (140 loc) · 5.77 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
158
159
160
161
162
163
164
165
166
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using Npgsql.BackendMessages;
using NpgsqlTypes;
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>
class PreparedStatement
{
readonly PreparedStatementManager _manager;
internal string Sql { get; }
internal string Name;
[CanBeNull]
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; private set; }
/// <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>
[CanBeNull]
internal PreparedStatement StatementBeingReplaced;
internal DateTime LastUsed { get; set; }
/// <summary>
/// Contains the parameter types for a prepared statement, for overloaded cases (same SQL, different param types)
/// Only populated after the statement has been prepared (i.e. null for candidates).
/// </summary>
[CanBeNull]
internal NpgsqlDbType[] ParamTypes { get; private set; }
static readonly NpgsqlDbType[] EmptyParamTypes = new NpgsqlDbType[0];
internal static PreparedStatement CreateExplicit(
PreparedStatementManager manager,
string sql,
string name,
List<NpgsqlParameter> parameters,
[CanBeNull] 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(ParamTypes == null);
if (parameters.Count == 0)
ParamTypes = EmptyParamTypes;
ParamTypes = new NpgsqlDbType[parameters.Count];
for (var i = 0; i < parameters.Count; i++)
ParamTypes[i] = parameters[i].NpgsqlDbType;
}
internal bool DoParametersMatch(List<NpgsqlParameter> parameters)
{
Debug.Assert(ParamTypes != null);
if (ParamTypes.Length != parameters.Count)
return false;
for (var i = 0; i < ParamTypes.Length; i++)
if (ParamTypes[i] != parameters[i].NpgsqlDbType)
return false;
return true;
}
internal void CompletePrepare()
{
Debug.Assert(ParamTypes != null);
_manager.BySql[Sql] = this;
_manager.NumPrepared++;
State = PreparedState.Prepared;
}
internal void CompleteUnprepare()
{
_manager.BySql.Remove(Sql);
_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 has been selected for preparation, but the preparation hasn't started yet.
/// This is a temporary state that only occurs during preparation.
/// Specifically, no protocol message (Parse) has been sent yet. Specifically, it means that
/// a Parse message for the statement has already been written to the write buffer.
/// </summary>
ToBePrepared,
/// <summary>
/// The statement is in the process of being prepared. This is a temporary state that only occurs during
/// preparation. Specifically, it means that a Parse message for the statement has already been written
/// to the write buffer.
/// </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
/// unpreparation. 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
}
}