1use alloc::{format, vec::Vec};
14use qusql_parse::{
15 Identifier, InsertReplace, InsertReplaceFlag, InsertReplaceSetPair, InsertReplaceType,
16 OptSpanned, Spanned, issue_todo,
17};
18
19use crate::{
20 BaseType, SelectTypeColumn, Type,
21 schema::lookup_name,
22 type_expression::{ExpressionFlags, type_expression},
23 type_select::{SelectType, type_select, type_select_exprs},
24 typer::{ReferenceType, Typer, did_you_mean, typer_stack},
25};
26
27#[derive(Clone, Debug, PartialEq, Eq)]
29pub enum AutoIncrementId {
30 Yes,
31 No,
32 Optional,
33}
34
35pub(crate) fn type_insert_replace<'a>(
36 typer: &mut Typer<'a, '_>,
37 ior: &InsertReplace<'a>,
38) -> (AutoIncrementId, Option<SelectType<'a>>) {
39 let table = &ior.table.identifier;
40 let table_key = typer.qname_to_key(&ior.table);
41 let search_path = typer.search_path();
42 let columns = &ior.columns;
43
44 let (s, auto_increment) =
45 if let Some(schema) = lookup_name(&typer.schemas.schemas, &table_key, search_path) {
46 if schema.view {
47 typer.err("Inserts into views not yet implemented", table);
48 }
49 let mut col_types = Vec::new();
50
51 for col in columns {
52 if let Some(schema_col) = schema.get_column(col.value) {
53 col_types.push((schema_col.type_.clone(), col.span()));
54 } else {
55 typer.err("No such column in schema", col);
56 }
57 }
58
59 if let Some(set) = &ior.set {
60 for col in &schema.columns {
61 if col.auto_increment
62 || col.default
63 || !col.type_.not_null
64 || col.as_.is_some()
65 || col.generated
66 || set.pairs.iter().any(|v| v.column == col.identifier)
67 {
68 continue;
69 }
70 typer.err(
71 format!(
72 "No value for column {} provided, but it has no default value",
73 col.identifier
74 ),
75 set,
76 );
77 }
78 } else {
79 for col in &schema.columns {
80 if col.auto_increment
81 || col.default
82 || !col.type_.not_null
83 || col.as_.is_some()
84 || col.generated
85 || columns.contains(&col.identifier)
86 {
87 continue;
88 }
89 typer.err(
90 format!(
91 "No value for column {} provided, but it has no default value",
92 col.identifier
93 ),
94 &columns.opt_span().unwrap_or(table.span()),
95 );
96 }
97 }
98
99 (
100 Some(col_types),
101 schema.columns.iter().any(|c| c.auto_increment),
102 )
103 } else {
104 typer.err("Unknown table", table);
105 (None, false)
106 };
107
108 if let Some(values) = &ior.values {
109 for row in &values.1 {
110 for (j, e) in row.iter().enumerate() {
111 if let Some((et, ets)) = s.as_ref().and_then(|v| v.get(j)) {
112 let t = type_expression(typer, e, ExpressionFlags::default(), et.base());
113 if typer.matched_type(&t, et).is_none() {
114 typer
115 .err(format!("Got type {}", t.t), e)
116 .frag(format!("Expected {}", et.t), ets);
117 } else if let Type::Args(_, args) = &t.t {
118 for (idx, arg_type, _) in args.iter() {
119 typer.constrain_arg(*idx, arg_type, et);
120 }
121 }
122 } else {
123 type_expression(typer, e, ExpressionFlags::default(), BaseType::Any);
124 }
125 }
126 if let Some(s) = &s
127 && s.len() != row.len()
128 {
129 typer
130 .err(
131 format!("Got {} columns", row.len()),
132 &row.opt_span().unwrap(),
133 )
134 .frag(
135 format!("Expected {}", columns.len()),
136 &columns.opt_span().unwrap_or(table.span()),
137 );
138 }
139 }
140 }
141
142 if let Some(select_stmt) = &ior.select
143 && let qusql_parse::Statement::Select(select_inner) = select_stmt
144 {
145 let select = type_select(typer, select_inner, true);
146 if let Some(s) = s {
147 for i in 0..usize::max(s.len(), select.columns.len()) {
148 match (s.get(i), select.columns.get(i)) {
149 (Some((et, ets)), Some(t)) => {
150 if typer.matched_type(&t.type_, et).is_none() {
151 typer
152 .err(format!("Got type {}", t.type_.t), &t.span)
153 .frag(format!("Expected {}", et), ets);
154 }
155 }
156 (None, Some(t)) => {
157 typer.err("Column in select not in insert", &t.span);
158 }
159 (Some((_, ets)), None) => {
160 typer.err("Missing column in select", ets);
161 }
162 (None, None) => {
163 panic!("ICE")
164 }
165 }
166 }
167 }
168 }
169 let mut guard = typer_stack(
172 typer,
173 |t| core::mem::take(&mut t.reference_types),
174 |t, v| t.reference_types = v,
175 );
176 let typer = &mut guard.typer;
177
178 if let Some(s) = lookup_name(&typer.schemas.schemas, &table_key, search_path) {
179 let mut columns = Vec::new();
180 for c in &s.columns {
181 columns.push((c.identifier.clone(), c.type_.clone()));
182 }
183 for v in &typer.reference_types {
184 if v.name == Some(table.clone()) {
185 typer
186 .issues
187 .err("Duplicate definitions", table)
188 .frag("Already defined here", &v.span);
189 }
190 }
191 typer.reference_types.push(ReferenceType {
192 name: Some(table.clone()),
193 span: table.span(),
194 columns,
195 });
196 }
197
198 if let Some(set) = &ior.set {
199 for InsertReplaceSetPair { column, value, .. } in &set.pairs {
200 let mut cnt = 0;
201 let mut t = None;
202 for r in &typer.reference_types {
203 for c in &r.columns {
204 if c.0 == *column {
205 cnt += 1;
206 t = Some(c.clone());
207 }
208 }
209 }
210 if cnt > 1 {
211 type_expression(typer, value, ExpressionFlags::default(), BaseType::Any);
212 let mut issue = typer.issues.err("Ambiguous reference", column);
213 for r in &typer.reference_types {
214 for c in &r.columns {
215 if c.0 == *column {
216 issue.frag("Defined here", &r.span);
217 }
218 }
219 }
220 } else if let Some(t) = t {
221 let value_type =
222 type_expression(typer, value, ExpressionFlags::default(), t.1.base());
223 if typer.matched_type(&value_type, &t.1).is_none() {
224 typer.err(format!("Got type {} expected {}", value_type, t.1), value);
225 } else if let Type::Args(_, args) = &value_type.t {
226 for (idx, arg_type, _) in args.iter() {
227 typer.constrain_arg(*idx, arg_type, &t.1);
228 }
229 }
230 } else {
231 type_expression(typer, value, ExpressionFlags::default(), BaseType::Any);
232 let suggestion = did_you_mean(
233 column.value,
234 typer
235 .reference_types
236 .iter()
237 .flat_map(|r| r.columns.iter().map(|(id, _)| id.value)),
238 );
239 let mut issue = typer.err("Unknown identifier", column);
240 if let Some(s) = suggestion {
241 issue.help(alloc::format!("did you mean `{s}`?"));
242 }
243 }
244 }
245 }
246
247 if let Some(up) = &ior.on_duplicate_key_update {
248 for InsertReplaceSetPair { value, column, .. } in &up.pairs {
249 let mut cnt = 0;
250 let mut t = None;
251 for r in &typer.reference_types {
252 for c in &r.columns {
253 if c.0 == *column {
254 cnt += 1;
255 t = Some(c.clone());
256 }
257 }
258 }
259 let flags = ExpressionFlags::default().with_in_on_duplicate_key_update(true);
260 if cnt > 1 {
261 type_expression(typer, value, flags, BaseType::Any);
262 let mut issue = typer.issues.err("Ambiguous reference", column);
263 for r in &typer.reference_types {
264 for c in &r.columns {
265 if c.0 == *column {
266 issue.frag("Defined here", &r.span);
267 }
268 }
269 }
270 } else if let Some(t) = t {
271 let value_type = type_expression(typer, value, flags, t.1.base());
272 if typer.matched_type(&value_type, &t.1).is_none() {
273 typer.err(format!("Got type {} expected {}", value_type, t.1), value);
274 } else if let Type::Args(_, args) = &value_type.t {
275 for (idx, arg_type, _) in args.iter() {
276 typer.constrain_arg(*idx, arg_type, &t.1);
277 }
278 }
279 } else {
280 type_expression(typer, value, flags, BaseType::Any);
281 let suggestion = did_you_mean(
282 column.value,
283 typer
284 .reference_types
285 .iter()
286 .flat_map(|r| r.columns.iter().map(|(id, _)| id.value)),
287 );
288 let mut issue = typer.err("Unknown identifier", column);
289 if let Some(s) = suggestion {
290 issue.help(alloc::format!("did you mean `{s}`?"));
291 }
292 }
293 }
294 }
295
296 if let Some(on_conflict) = &ior.on_conflict {
297 match &on_conflict.target {
298 qusql_parse::OnConflictTarget::Columns { names } => {
299 for name in names {
300 let mut t = None;
301 for r in &typer.reference_types {
302 for c in &r.columns {
303 if c.0 == *name {
304 t = Some(c.clone());
305 }
306 }
307 }
308 if t.is_none() {
309 let suggestion = did_you_mean(
310 name.value,
311 typer
312 .reference_types
313 .iter()
314 .flat_map(|r| r.columns.iter().map(|(id, _)| id.value)),
315 );
316 let mut issue = typer.err("Unknown identifier", name);
317 if let Some(s) = suggestion {
318 issue.help(alloc::format!("did you mean `{s}`?"));
319 }
320 }
321 }
322 }
324 qusql_parse::OnConflictTarget::OnConstraint {
325 on_constraint_span, ..
326 } => {
327 issue_todo!(typer.issues, on_constraint_span);
328 }
329 qusql_parse::OnConflictTarget::None => (),
330 }
331
332 match &on_conflict.action {
333 qusql_parse::OnConflictAction::DoNothing(_) => (),
334 qusql_parse::OnConflictAction::DoUpdateSet {
335 sets,
336 where_,
337 do_update_set_span,
338 } => {
339 let mut excluded_columns = Vec::new();
340 if let Some(schema) = lookup_name(&typer.schemas.schemas, &table_key, search_path)
341 && !schema.view
342 {
343 for col in &ior.columns {
344 if let Some(schema_col) = schema.get_column(col.value) {
345 excluded_columns
346 .push((schema_col.identifier.clone(), schema_col.type_.clone()));
347 }
348 }
349 }
350
351 typer.reference_types.push(ReferenceType {
352 name: Some(Identifier::new("EXCLUDED", do_update_set_span.clone())),
353 span: do_update_set_span.span(),
354 columns: excluded_columns,
355 });
356
357 for (key, value) in sets {
358 let mut cnt = 0;
359 let mut t = None;
360 for r in &typer.reference_types {
361 if let Some(name) = &r.name
362 && name.value == "EXCLUDED"
363 {
364 continue;
365 }
366 for c in &r.columns {
367 if c.0 == *key {
368 cnt += 1;
369 t = Some(c.clone());
370 }
371 }
372 }
373 let flags = ExpressionFlags::default().with_in_on_duplicate_key_update(true);
374 if cnt > 1 {
375 type_expression(typer, value, flags, BaseType::Any);
376 let mut issue = typer.issues.err("Ambiguous reference", key);
377 for r in &typer.reference_types {
378 for c in &r.columns {
379 if c.0 == *key {
380 issue.frag("Defined here", &r.span);
381 }
382 }
383 }
384 } else if let Some(t) = t {
385 let value_type = type_expression(typer, value, flags, t.1.base());
386 if typer.matched_type(&value_type, &t.1).is_none() {
387 typer.err(format!("Got type {} expected {}", value_type, t.1), value);
388 } else if let Type::Args(_, args) = &value_type.t {
389 for (idx, arg_type, _) in args.iter() {
390 typer.constrain_arg(*idx, arg_type, &t.1);
391 }
392 }
393 } else {
394 type_expression(typer, value, flags, BaseType::Any);
395 let suggestion = did_you_mean(
396 key.value,
397 typer
398 .reference_types
399 .iter()
400 .flat_map(|r| r.columns.iter().map(|(id, _)| id.value)),
401 );
402 let mut issue = typer.err("Unknown identifier", key);
403 if let Some(s) = suggestion {
404 issue.help(alloc::format!("did you mean `{s}`?"));
405 }
406 }
407 }
408 if let Some((_, where_)) = where_ {
409 type_expression(typer, where_, ExpressionFlags::default(), BaseType::Bool);
410 }
411 }
412 }
413 }
414
415 let returning_select = match &ior.returning {
416 Some((returning_span, returning_exprs)) => {
417 let columns = type_select_exprs(typer, returning_exprs, true)
418 .into_iter()
419 .map(|(name, type_, span)| SelectTypeColumn { name, type_, span })
420 .collect();
421 Some(SelectType {
422 columns,
423 select_span: returning_span.join_span(returning_exprs),
424 })
425 }
426 None => None,
427 };
428
429 core::mem::drop(guard);
430
431 let auto_increment_id = if auto_increment && matches!(ior.type_, InsertReplaceType::Insert(_)) {
432 if ior
433 .flags
434 .iter()
435 .any(|f| matches!(f, InsertReplaceFlag::Ignore(_)))
436 || ior.on_duplicate_key_update.is_some()
437 {
438 AutoIncrementId::Optional
439 } else {
440 AutoIncrementId::Yes
441 }
442 } else {
443 AutoIncrementId::No
444 };
445
446 (auto_increment_id, returning_select)
447}