1use crate::ast::{
10 AlterRoutineKind, AlterTableAction, AlterViewKind, DiscardTarget, DropKind, TransactionStmt,
11};
12use crate::plan::{CommandPlan, UnifiedPlan};
13use crate::SQLResult;
14
15pub fn set_command_completion(
16 plan: &UnifiedPlan,
17 result: &mut SQLResult,
18 transaction_failed: bool,
19) {
20 let command = match plan {
21 UnifiedPlan::Query(_) => {
22 result.command_tag = Some(format!("SELECT {}", result.rows.len()));
23 return;
24 }
25 UnifiedPlan::Command(command) => command.as_ref(),
26 };
27 if matches!(
28 command,
29 CommandPlan::Execute { .. }
30 | CommandPlan::CreateTableAs { .. }
31 | CommandPlan::CreateMaterializedView { .. }
32 ) {
33 return;
35 }
36 result.command_tag = Some(command_completion(command, result, transaction_failed));
37}
38
39fn command_completion(
40 command: &CommandPlan,
41 result: &SQLResult,
42 transaction_failed: bool,
43) -> String {
44 match command {
45 CommandPlan::Insert(_) => format!("INSERT 0 {}", result.affected_rows),
46 CommandPlan::Update(_) => format!("UPDATE {}", result.affected_rows),
47 CommandPlan::Delete(_) => format!("DELETE {}", result.affected_rows),
48 CommandPlan::Merge(_) => format!("MERGE {}", result.affected_rows),
49 CommandPlan::FetchCursor(fetch) if fetch.move_only => {
50 format!("MOVE {}", result.affected_rows)
51 }
52 CommandPlan::FetchCursor(_) => format!("FETCH {}", result.rows.len()),
53 CommandPlan::CreateTableAs { .. } | CommandPlan::CreateMaterializedView { .. } => {
54 unreachable!("population execution owns completion")
55 }
56 CommandPlan::Execute { .. } => {
57 unreachable!("EXECUTE preserves delegated command completion")
58 }
59 CommandPlan::Transaction(statement) => {
60 transaction_completion(statement, transaction_failed).to_string()
61 }
62 command => command_tag_name(command).to_string(),
63 }
64}
65
66#[expect(clippy::too_many_lines, reason = "exhaustive SQL command tag mapping")]
68pub fn command_tag_name(command: &CommandPlan) -> &'static str {
69 match command {
70 CommandPlan::Insert(_) => "INSERT",
71 CommandPlan::Update(_) => "UPDATE",
72 CommandPlan::Delete(_) => "DELETE",
73 CommandPlan::Merge(_) => "MERGE",
74 CommandPlan::FetchCursor(fetch) => {
75 if fetch.move_only {
76 "MOVE"
77 } else {
78 "FETCH"
79 }
80 }
81 CommandPlan::CreateTableAs {
82 select_into: true, ..
83 } => "SELECT INTO",
84 CommandPlan::CreateTableAs { .. } => "CREATE TABLE AS",
85 CommandPlan::CreateMaterializedView { .. } => "CREATE MATERIALIZED VIEW",
86 CommandPlan::Execute { .. } => "EXECUTE",
87 CommandPlan::Transaction(statement) => transaction_completion(statement, false),
88 CommandPlan::CreateTable(_) | CommandPlan::CreateTableIfNotExists(_) => "CREATE TABLE",
89 CommandPlan::CreateIndex(_) => "CREATE INDEX",
90 CommandPlan::RenameIndex(_) => "ALTER INDEX",
91 CommandPlan::Drop(statement) => match statement.kind {
92 DropKind::Table => "DROP TABLE",
93 DropKind::ForeignTable => "DROP FOREIGN TABLE",
94 DropKind::ForeignServer => "DROP SERVER",
95 DropKind::ForeignWrapper => "DROP FOREIGN DATA WRAPPER",
96 DropKind::Index => "DROP INDEX",
97 DropKind::View => "DROP VIEW",
98 DropKind::MaterializedView => "DROP MATERIALIZED VIEW",
99 DropKind::Schema => "DROP SCHEMA",
100 DropKind::Sequence => "DROP SEQUENCE",
101 DropKind::Domain => "DROP DOMAIN",
102 DropKind::Type => "DROP TYPE",
103 },
104 CommandPlan::AlterTable(statement) => match statement.actions.as_slice() {
105 [AlterTableAction::RenameTrigger { .. }] => "ALTER TRIGGER",
106 [AlterTableAction::RenameRule { .. }] => "ALTER RULE",
107 _ => "ALTER TABLE",
108 },
109 CommandPlan::AlterForeignTable(_) => "ALTER FOREIGN TABLE",
110 CommandPlan::AlterView(statement) => match statement.kind {
111 AlterViewKind::View => "ALTER VIEW",
112 AlterViewKind::MaterializedView => "ALTER MATERIALIZED VIEW",
113 },
114 CommandPlan::CreateView { .. } => "CREATE VIEW",
115 CommandPlan::RefreshMaterializedView { .. } => "REFRESH MATERIALIZED VIEW",
116 CommandPlan::CreateSchema { .. } => "CREATE SCHEMA",
117 CommandPlan::AlterSchemaOwner { .. } | CommandPlan::RenameSchema { .. } => "ALTER SCHEMA",
118 CommandPlan::Notify { .. } => "NOTIFY",
119 CommandPlan::Listen { .. } => "LISTEN",
120 CommandPlan::Unlisten { .. } => "UNLISTEN",
121 CommandPlan::SetVariable { .. } => "SET",
122 CommandPlan::ResetVariable { .. } | CommandPlan::ResetAllVariables => "RESET",
123 CommandPlan::SetConstraints { .. } => "SET CONSTRAINTS",
124 CommandPlan::ShowVariable { .. } => "SHOW",
125 CommandPlan::Discard { target } => match target {
126 DiscardTarget::All => "DISCARD ALL",
127 DiscardTarget::Plans => "DISCARD PLANS",
128 DiscardTarget::Sequences => "DISCARD SEQUENCES",
129 DiscardTarget::Temp => "DISCARD TEMP",
130 },
131 CommandPlan::Load { .. } => "LOAD",
132 CommandPlan::Explain { .. } => "EXPLAIN",
133 CommandPlan::Analyze { .. } => "ANALYZE",
134 CommandPlan::LockTable(_) => "LOCK TABLE",
135 CommandPlan::Vacuum(_) => "VACUUM",
136 CommandPlan::Truncate { .. } => "TRUNCATE TABLE",
137 CommandPlan::DeclareCursor { .. } => "DECLARE CURSOR",
138 CommandPlan::CloseCursor { name } => {
139 if name.is_some() {
140 "CLOSE CURSOR"
141 } else {
142 "CLOSE CURSOR ALL"
143 }
144 }
145 CommandPlan::CreateSequence(_) => "CREATE SEQUENCE",
146 CommandPlan::CreateDomain(_) => "CREATE DOMAIN",
147 CommandPlan::AlterDomain(_) => "ALTER DOMAIN",
148 CommandPlan::CreateEnum(_) | CommandPlan::CreateCompositeType(_) => "CREATE TYPE",
149 CommandPlan::AlterEnum(_) => "ALTER TYPE",
150 CommandPlan::AlterTypeObject(statement) => match statement.kind {
151 crate::ast::TypeObjectKind::Type => "ALTER TYPE",
152 crate::ast::TypeObjectKind::Domain => "ALTER DOMAIN",
153 },
154 CommandPlan::GrantType(statement) => grant_completion(statement.is_grant),
155 CommandPlan::AlterSequence(_) => "ALTER SEQUENCE",
156 CommandPlan::Prepare { .. } => "PREPARE",
157 CommandPlan::Deallocate { name } => {
158 if name.is_some() {
159 "DEALLOCATE"
160 } else {
161 "DEALLOCATE ALL"
162 }
163 }
164 CommandPlan::CreateForeignWrapper(_) => "CREATE FOREIGN DATA WRAPPER",
165 CommandPlan::CreateForeignServer(_) => "CREATE SERVER",
166 CommandPlan::CreateForeignTable(_) | CommandPlan::CreateForeignTableDefinition(_) => {
167 "CREATE FOREIGN TABLE"
168 }
169 CommandPlan::CreateFunction(statement) => {
170 if statement.is_procedure {
171 "CREATE PROCEDURE"
172 } else {
173 "CREATE FUNCTION"
174 }
175 }
176 CommandPlan::DropFunction(statement) => {
177 if statement.is_procedure {
178 "DROP PROCEDURE"
179 } else {
180 "DROP FUNCTION"
181 }
182 }
183 CommandPlan::AlterRoutine(statement) => alter_routine_completion(statement.kind),
184 CommandPlan::AlterRoutineOwner(statement) => alter_routine_completion(statement.kind),
185 CommandPlan::RenameRoutine(statement) => alter_routine_completion(statement.kind),
186 CommandPlan::GrantRoutine(statement) => grant_completion(statement.is_grant),
187 CommandPlan::GrantTable(statement) => grant_completion(statement.is_grant),
188 CommandPlan::GrantSequence(statement) => grant_completion(statement.is_grant),
189 CommandPlan::GrantDatabase(statement) => grant_completion(statement.is_grant),
190 CommandPlan::GrantSchema(statement) => grant_completion(statement.is_grant),
191 CommandPlan::GrantRole(statement) => {
192 if statement.is_grant {
193 "GRANT ROLE"
194 } else {
195 "REVOKE ROLE"
196 }
197 }
198 CommandPlan::CreateRole(_) => "CREATE ROLE",
199 CommandPlan::AlterRole(_) | CommandPlan::RenameRole(_) => "ALTER ROLE",
200 CommandPlan::DropRole(_) => "DROP ROLE",
201 CommandPlan::CreateTrigger(_) => "CREATE TRIGGER",
202 CommandPlan::DropTrigger(_) => "DROP TRIGGER",
203 CommandPlan::CreateRule(_) => "CREATE RULE",
204 CommandPlan::DropRule(_) => "DROP RULE",
205 CommandPlan::DoBlock { .. } => "DO",
206 CommandPlan::Call { .. } => "CALL",
207 }
208}
209
210pub const fn transaction_completion(statement: &TransactionStmt, failed: bool) -> &'static str {
211 match statement {
212 TransactionStmt::Begin | TransactionStmt::BeginWithCharacteristics(_) => "BEGIN",
213 TransactionStmt::Commit | TransactionStmt::CommitAndChain => {
214 if failed {
215 "ROLLBACK"
216 } else {
217 "COMMIT"
218 }
219 }
220 TransactionStmt::Rollback
221 | TransactionStmt::RollbackAndChain
222 | TransactionStmt::RollbackToSavepoint(_) => "ROLLBACK",
223 TransactionStmt::Savepoint(_) => "SAVEPOINT",
224 TransactionStmt::ReleaseSavepoint(_) => "RELEASE",
225 TransactionStmt::SetCharacteristics(_)
226 | TransactionStmt::SetSessionCharacteristics(_)
227 | TransactionStmt::SetSnapshot(_) => "SET",
228 }
229}
230
231const fn alter_routine_completion(kind: AlterRoutineKind) -> &'static str {
232 match kind {
233 AlterRoutineKind::Function => "ALTER FUNCTION",
234 AlterRoutineKind::Procedure => "ALTER PROCEDURE",
235 AlterRoutineKind::Routine => "ALTER ROUTINE",
236 }
237}
238
239const fn grant_completion(is_grant: bool) -> &'static str {
240 if is_grant {
241 "GRANT"
242 } else {
243 "REVOKE"
244 }
245}