1use crate::builtins::BUILTINS_SQL;
2use crate::classify::{NameClass, NameRefClass, classify_def_node, classify_name};
3use crate::column_name::ColumnName;
4use crate::offsets::token_from_offset;
5use crate::{
6 binder,
7 symbols::{Name, Schema},
8};
9use crate::{goto_definition, resolve};
10use rowan::TextSize;
11use squawk_syntax::SyntaxNode;
12use squawk_syntax::{
13 SyntaxKind,
14 ast::{self, AstNode},
15};
16
17pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
18 let token = token_from_offset(file, offset)?;
19 let parent = token.parent()?;
20
21 let root = file.syntax();
22 let binder = binder::bind(file);
24
25 if token.kind() == SyntaxKind::STAR {
26 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone())
27 && field_expr.star_token().is_some()
28 && let Some(result) = hover_qualified_star(root, &field_expr, &binder)
29 {
30 return Some(result);
31 }
32
33 if let Some(arg_list) = ast::ArgList::cast(parent.clone())
34 && let Some(result) = hover_unqualified_star_in_arg_list(root, &arg_list, &binder)
35 {
36 return Some(result);
37 }
38
39 if let Some(target) = ast::Target::cast(parent.clone())
40 && target.star_token().is_some()
41 && let Some(result) = hover_unqualified_star(root, &target, &binder)
42 {
43 return Some(result);
44 }
45 }
46
47 if let Some(name_ref) = ast::NameRef::cast(parent.clone()) {
48 let definition = goto_definition::goto_definition(file, offset);
49 let def = definition.first()?;
50
51 let (binder, root) = match def.file {
52 goto_definition::FileId::Current => (binder, root.clone()),
53 goto_definition::FileId::Builtins => {
54 let builtins_tree = ast::SourceFile::parse(BUILTINS_SQL);
55 let builtins_tree = builtins_tree.tree();
56 let binder = binder::bind(&builtins_tree);
58 let tree = builtins_tree.syntax().clone();
59 (binder, tree)
60 }
61 };
62
63 let def_node = match root.covering_element(def.range) {
64 rowan::NodeOrToken::Token(token) => token.parent()?,
65 rowan::NodeOrToken::Node(node) => node,
66 };
67
68 let context = classify_def_node(&def_node)?;
69
70 return hover_name_ref(&root, &name_ref, &binder, context, &def_node);
71 }
72
73 if let Some(name) = ast::Name::cast(parent) {
74 let context = classify_name(&name)?;
75 match context {
76 NameClass::ColumnDefinition {
77 create_table,
78 column,
79 } => return hover_column_definition(&create_table, &column, &binder),
80 NameClass::CreateTable(create_table) => {
81 return format_create_table(&create_table, &binder);
82 }
83 NameClass::WithTable(with_table) => return format_with_table(&with_table),
84 NameClass::CreateIndex(create_index) => {
85 return format_create_index(&create_index, &binder);
86 }
87 NameClass::CreateSequence(create_sequence) => {
88 return format_create_sequence(&create_sequence, &binder);
89 }
90 NameClass::CreateTrigger(create_trigger) => {
91 return format_create_trigger(&create_trigger, &binder);
92 }
93 NameClass::CreateEventTrigger(create_event_trigger) => {
94 return format_create_event_trigger(&create_event_trigger);
95 }
96 NameClass::CreateTablespace(create_tablespace) => {
97 return format_create_tablespace(&create_tablespace);
98 }
99 NameClass::CreateDatabase(create_database) => {
100 return format_create_database(&create_database);
101 }
102 NameClass::CreateServer(create_server) => {
103 return format_create_server(&create_server);
104 }
105 NameClass::CreateExtension(create_extension) => {
106 return format_create_extension(&create_extension);
107 }
108 NameClass::CreateRole(create_role) => {
109 return format_create_role(&create_role);
110 }
111 NameClass::CreateType(create_type) => {
112 return format_create_type(&create_type, &binder);
113 }
114 NameClass::CreateFunction(create_function) => {
115 return format_create_function(&create_function, &binder);
116 }
117 NameClass::CreateAggregate(create_aggregate) => {
118 return format_create_aggregate(&create_aggregate, &binder);
119 }
120 NameClass::CreateProcedure(create_procedure) => {
121 return format_create_procedure(&create_procedure, &binder);
122 }
123 NameClass::CreateSchema(create_schema) => {
124 return format_create_schema(&create_schema);
125 }
126 NameClass::ViewColumnList { create_view, name } => {
127 return format_view_column(&create_view, Name::from_node(&name), &binder);
128 }
129 NameClass::CreateView(create_view) => {
130 return format_create_view(&create_view, &binder);
131 }
132 NameClass::DeclareCursor(declare) => {
133 return format_declare_cursor(&declare);
134 }
135 NameClass::PrepareStatement(prepare) => {
136 return format_prepare(&prepare);
137 }
138 NameClass::Listen(listen) => {
139 return format_listen(&listen);
140 }
141 }
142 }
143
144 None
145}
146
147fn hover_name_ref(
148 root: &SyntaxNode,
149 name_ref: &ast::NameRef,
150 binder: &binder::Binder,
153 context: NameRefClass,
154 def_node: &SyntaxNode,
155) -> Option<String> {
156 match context {
157 NameRefClass::CreateIndexColumn
158 | NameRefClass::InsertColumn
159 | NameRefClass::DeleteColumn
160 | NameRefClass::UpdateColumn
161 | NameRefClass::MergeColumn
162 | NameRefClass::ConstraintColumn
163 | NameRefClass::JoinUsingColumn
164 | NameRefClass::ForeignKeyColumn
165 | NameRefClass::AlterColumn
166 | NameRefClass::QualifiedColumn => hover_column(root, name_ref, binder),
167 NameRefClass::Type => hover_type(root, name_ref, binder),
168 NameRefClass::CompositeTypeField => hover_composite_type_field(root, name_ref, binder),
169 NameRefClass::SelectColumn
170 | NameRefClass::SelectQualifiedColumn
171 | NameRefClass::PolicyColumn => {
172 if let Some(result) = hover_column(root, name_ref, binder) {
174 return Some(result);
175 }
176 if let Some(result) = hover_function(root, name_ref, binder) {
178 return Some(result);
179 }
180 hover_table(binder, def_node)
182 }
183 NameRefClass::DeleteQualifiedColumnTable
184 | NameRefClass::ForeignKeyTable
185 | NameRefClass::FromTable
186 | NameRefClass::InsertQualifiedColumnTable
187 | NameRefClass::LikeTable
188 | NameRefClass::MergeQualifiedColumnTable
189 | NameRefClass::PolicyQualifiedColumnTable
190 | NameRefClass::SelectQualifiedColumnTable
191 | NameRefClass::Table
192 | NameRefClass::UpdateQualifiedColumnTable
193 | NameRefClass::View => hover_table(binder, def_node),
194 NameRefClass::Sequence => hover_sequence(root, name_ref, binder),
195 NameRefClass::Trigger => hover_trigger(root, name_ref, binder),
196 NameRefClass::Policy => hover_policy(root, name_ref, binder),
197 NameRefClass::EventTrigger => hover_event_trigger(root, name_ref, binder),
198 NameRefClass::Database => hover_database(root, name_ref, binder),
199 NameRefClass::Server => hover_server(root, name_ref, binder),
200 NameRefClass::Extension => hover_extension(root, name_ref, binder),
201 NameRefClass::Role => hover_role(root, name_ref, binder),
202 NameRefClass::Tablespace => hover_tablespace(root, name_ref, binder),
203 NameRefClass::Index => hover_index(root, name_ref, binder),
204 NameRefClass::Function | NameRefClass::FunctionCall | NameRefClass::FunctionName => {
205 hover_function(root, name_ref, binder)
206 }
207 NameRefClass::Aggregate => hover_aggregate(root, name_ref, binder),
208 NameRefClass::Procedure | NameRefClass::CallProcedure | NameRefClass::ProcedureCall => {
209 hover_procedure(root, name_ref, binder)
210 }
211 NameRefClass::Routine => hover_routine(root, name_ref, binder),
212 NameRefClass::SelectFunctionCall => {
213 if let Some(result) = hover_function(root, name_ref, binder) {
216 return Some(result);
217 }
218 hover_column(root, name_ref, binder)
219 }
220 NameRefClass::Schema => hover_schema(root, name_ref, binder),
221 NameRefClass::NamedArgParameter => hover_named_arg_parameter(root, name_ref, binder),
222 NameRefClass::Cursor => hover_cursor(root, name_ref, binder),
223 NameRefClass::PreparedStatement => hover_prepared_statement(root, name_ref, binder),
224 NameRefClass::Channel => hover_channel(root, name_ref, binder),
225 }
226}
227
228struct ColumnHover {}
229impl ColumnHover {
230 fn table_column(table_name: &str, column_name: &str) -> String {
231 format!("column {table_name}.{column_name}")
232 }
233 fn schema_table_column_type(
234 schema: &str,
235 table_name: &str,
236 column_name: &str,
237 ty: &str,
238 ) -> String {
239 format!("column {schema}.{table_name}.{column_name} {ty}")
240 }
241 fn schema_table_column(schema: &str, table_name: &str, column_name: &str) -> String {
242 format!("column {schema}.{table_name}.{column_name}")
243 }
244
245 fn anon_column(col_name: &str) -> String {
246 format!("column {}", col_name)
247 }
248 fn anon_column_type(col_name: &str, ty: &str) -> String {
249 format!("column {} {}", col_name, ty)
250 }
251}
252
253fn hover_column(
254 root: &SyntaxNode,
255 name_ref: &ast::NameRef,
256 binder: &binder::Binder,
257) -> Option<String> {
258 let column_ptrs = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?;
259
260 let results: Vec<String> = column_ptrs
261 .iter()
262 .filter_map(|column_ptr| {
263 let column_name_node = column_ptr.to_node(root);
264 format_hover_for_column_node(binder, root, &column_name_node, name_ref)
265 })
266 .collect();
267
268 if results.is_empty() {
269 return None;
270 }
271
272 Some(results.join("\n"))
273}
274
275fn format_hover_for_column_node(
276 binder: &binder::Binder,
277 root: &SyntaxNode,
278 column_name_node: &squawk_syntax::SyntaxNode,
279 name_ref: &ast::NameRef,
280) -> Option<String> {
281 for a in column_name_node.ancestors() {
282 if let Some(with_table) = ast::WithTable::cast(a.clone()) {
283 let cte_name = with_table.name()?;
284 let column_name = if column_name_node
285 .ancestors()
286 .any(|a| ast::Values::can_cast(a.kind()))
287 {
288 Name::from_node(name_ref)
289 } else {
290 Name::from_string(column_name_node.text().to_string())
291 };
292 let table_name = Name::from_node(&cte_name);
293 return Some(ColumnHover::table_column(
294 &table_name.to_string(),
295 &column_name.to_string(),
296 ));
297 }
298 if let Some(paren_select) = ast::ParenSelect::cast(a.clone()) {
299 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast)
301 && let Some(base) = field_expr.base()
302 && let ast::Expr::NameRef(table_name_ref) = base
303 {
304 let table_name = Name::from_node(&table_name_ref);
305 let column_name = Name::from_string(column_name_node.text().to_string());
306 return Some(ColumnHover::table_column(
307 &table_name.to_string(),
308 &column_name.to_string(),
309 ));
310 }
311 let column_name = if column_name_node
314 .ancestors()
315 .any(|a| ast::Values::can_cast(a.kind()))
316 {
317 Name::from_node(name_ref)
318 } else {
319 Name::from_string(column_name_node.text().to_string())
320 };
321 let ty = resolve::collect_paren_select_columns_with_types(binder, root, &paren_select)
322 .into_iter()
323 .find(|(name, _)| *name == column_name)
324 .and_then(|(_, ty)| ty)?;
325 return Some(ColumnHover::anon_column_type(
326 &column_name.to_string(),
327 &ty.to_string(),
328 ));
329 }
330
331 if let Some(create_view) = ast::CreateView::cast(a.clone())
335 && let Some(column_name) =
336 ast::Name::cast(column_name_node.clone()).map(|name| Name::from_node(&name))
337 {
338 return format_view_column(&create_view, column_name, binder);
339 }
340
341 if let Some(alias) = ast::Alias::cast(a.clone())
342 && let Some(alias_name) = alias.name()
343 && alias.column_list().is_some()
344 {
345 let table_name = Name::from_node(&alias_name);
346 let column_name = Name::from_string(column_name_node.text().to_string());
347 return Some(ColumnHover::table_column(
348 &table_name.to_string(),
349 &column_name.to_string(),
350 ));
351 }
352
353 if let Some(create_table_as) = ast::CreateTableAs::cast(a.clone()) {
354 let column_name = if let Some(name) = ast::Name::cast(column_name_node.clone()) {
355 Name::from_node(&name)
356 } else {
357 continue;
358 };
359 let path = create_table_as.path()?;
360 let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
361 return Some(ColumnHover::schema_table_column(
362 &schema.to_string(),
363 &table_name,
364 &column_name.to_string(),
365 ));
366 }
367 }
368
369 let column = column_name_node.ancestors().find_map(ast::Column::cast)?;
370 let column_name = column.name()?;
371 let ty = column.ty()?;
372
373 let create_table = column
374 .syntax()
375 .ancestors()
376 .find_map(ast::CreateTableLike::cast)?;
377 let path = create_table.path()?;
378 let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
379
380 let schema = schema.to_string();
381 let column_name = Name::from_node(&column_name);
382 let ty = &ty.syntax().text().to_string();
383 Some(ColumnHover::schema_table_column_type(
384 &schema,
385 &table_name,
386 &column_name.to_string(),
387 ty,
388 ))
389}
390
391fn hover_composite_type_field(
392 root: &SyntaxNode,
393 name_ref: &ast::NameRef,
394 binder: &binder::Binder,
395) -> Option<String> {
396 let field_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
397 .into_iter()
398 .next()?;
399 let field_name_node = field_ptr.to_node(root);
400
401 let column = field_name_node.ancestors().find_map(ast::Column::cast)?;
402 let field_name = column.name()?.syntax().text().to_string();
403 let ty = column.ty()?;
404
405 let create_type = column
406 .syntax()
407 .ancestors()
408 .find_map(ast::CreateType::cast)?;
409 let type_path = create_type.path()?;
410 let (schema, type_name) = resolve::resolve_type_info(binder, &type_path)?;
411
412 Some(format!(
413 "field {}.{}.{} {}",
414 schema,
415 type_name,
416 field_name,
417 ty.syntax().text()
418 ))
419}
420
421fn hover_column_definition(
422 create_table: &impl ast::HasCreateTable,
423 column: &ast::Column,
424 binder: &binder::Binder,
425) -> Option<String> {
426 let column_name = column.name()?.syntax().text().to_string();
427 let ty = column.ty()?;
428 let path = create_table.path()?;
429 let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
430 let ty = ty.syntax().text().to_string();
431 Some(ColumnHover::schema_table_column_type(
432 &schema.to_string(),
433 &table_name,
434 &column_name,
435 &ty,
436 ))
437}
438
439fn format_table_source(
442 root: &SyntaxNode,
443 source: resolve::TableSource,
444 binder: &binder::Binder,
445) -> Option<String> {
446 match source {
447 resolve::TableSource::Alias(alias) => format_alias_with_column_list(root, &alias, binder),
448 resolve::TableSource::WithTable(with_table) => format_with_table(&with_table),
449 resolve::TableSource::CreateView(create_view) => format_create_view(&create_view, binder),
450 resolve::TableSource::CreateMaterializedView(create_materialized_view) => {
451 format_create_materialized_view(&create_materialized_view, binder)
452 }
453 resolve::TableSource::CreateTable(create_table) => {
454 format_create_table(&create_table, binder)
455 }
456 resolve::TableSource::ParenSelect(paren_select) => format_paren_select(&paren_select),
457 }
458}
459
460fn hover_table(binder: &binder::Binder, def_node: &SyntaxNode) -> Option<String> {
461 if let Some(result) = hover_subquery_table(def_node) {
462 return Some(result);
463 }
464
465 if let Some(source) = resolve::find_table_source(def_node)
466 && let Some(root) = def_node.ancestors().last()
467 {
468 return format_table_source(&root, source, binder);
469 }
470
471 None
472}
473
474fn format_alias_with_column_list(
475 root: &SyntaxNode,
476 alias: &ast::Alias,
477 binder: &binder::Binder,
478) -> Option<String> {
479 let alias_name = alias.name()?;
480 let name = Name::from_node(&alias_name);
481
482 let mut columns: Vec<Name> = alias
483 .column_list()?
484 .columns()
485 .filter_map(|column| {
486 column
487 .name()
488 .map(|column_name| Name::from_node(&column_name))
489 })
490 .collect();
491
492 if let Some(from_item) = alias.syntax().ancestors().find_map(ast::FromItem::cast)
493 && let Some(table_ptr) = resolve::table_ptr_from_from_item(binder, &from_item)
494 {
495 let base_columns = collect_star_column_names(root, &table_ptr, binder);
496 for column in base_columns.iter().skip(columns.len()) {
497 columns.push(column.clone());
498 }
499 }
500
501 let columns = columns
502 .iter()
503 .map(|column| column.to_string())
504 .collect::<Vec<_>>()
505 .join(", ");
506 Some(format!("table {}({})", name, columns))
507}
508
509fn hover_qualified_star(
510 root: &SyntaxNode,
511 field_expr: &ast::FieldExpr,
512 binder: &binder::Binder,
513) -> Option<String> {
514 let table_ptr = resolve::resolve_qualified_star_table_ptr(binder, field_expr)?;
515 hover_qualified_star_columns(root, &table_ptr, binder)
516}
517
518fn hover_unqualified_star(
519 root: &SyntaxNode,
520 target: &ast::Target,
521 binder: &binder::Binder,
522) -> Option<String> {
523 let mut results = hover_unqualified_star_with_binder(root, target, binder);
524
525 if results.is_empty() && target_has_schema_qualified_from_item(target) {
526 let builtins_tree = ast::SourceFile::parse(BUILTINS_SQL).tree();
527 let builtins_binder = binder::bind(&builtins_tree);
528 results =
529 hover_unqualified_star_with_binder(builtins_tree.syntax(), target, &builtins_binder);
530 }
531
532 if results.is_empty() {
533 return None;
534 }
535
536 Some(results.join("\n"))
537}
538
539fn hover_unqualified_star_with_binder(
540 root: &SyntaxNode,
541 target: &ast::Target,
542 binder: &binder::Binder,
543) -> Vec<String> {
544 let mut results = vec![];
545
546 if let Some(table_ptrs) = resolve::resolve_unqualified_star_table_ptrs(binder, target) {
547 for table_ptr in table_ptrs {
548 if let Some(columns) = hover_qualified_star_columns(root, &table_ptr, binder) {
549 results.push(columns);
550 }
551 }
552 }
553
554 results
555}
556
557fn target_has_schema_qualified_from_item(target: &ast::Target) -> bool {
558 let Some(select) = target.syntax().ancestors().find_map(ast::Select::cast) else {
559 return false;
560 };
561 let Some(from_clause) = select.from_clause() else {
562 return false;
563 };
564
565 for from_item in from_clause.from_items() {
566 if from_item.field_expr().is_some() {
567 return true;
568 }
569 }
570
571 false
572}
573
574fn hover_unqualified_star_in_arg_list(
575 root: &SyntaxNode,
576 arg_list: &ast::ArgList,
577 binder: &binder::Binder,
578) -> Option<String> {
579 let table_ptrs = resolve::resolve_unqualified_star_in_arg_list_ptrs(binder, arg_list)?;
580 let mut results = vec![];
581 for table_ptr in table_ptrs {
582 if let Some(columns) = hover_qualified_star_columns(root, &table_ptr, binder) {
583 results.push(columns);
584 }
585 }
586
587 if results.is_empty() {
588 return None;
589 }
590
591 Some(results.join("\n"))
592}
593
594fn hover_subquery_table(def_node: &SyntaxNode) -> Option<String> {
595 let alias = def_node.ancestors().find_map(ast::Alias::cast)?;
596 if alias.column_list().is_some() {
597 return None;
598 }
599 let name = Name::from_node(&alias.name()?);
600 let from_item = alias.syntax().ancestors().find_map(ast::FromItem::cast)?;
601 let paren_select = from_item.paren_select()?;
602 format_subquery_table(&name, &paren_select)
603}
604
605fn format_subquery_table(name: &Name, paren_select: &ast::ParenSelect) -> Option<String> {
606 let name = name.to_string();
607 let query = paren_select.syntax().text().to_string();
608 Some(format!("subquery {} as {}", name, query))
609}
610
611fn hover_qualified_star_columns(
612 root: &SyntaxNode,
613 table_ptr: &squawk_syntax::SyntaxNodePtr,
614 binder: &binder::Binder,
615) -> Option<String> {
616 let table_name_node = table_ptr.to_node(root);
617
618 if let Some(paren_select) = ast::ParenSelect::cast(table_name_node.clone()) {
619 return hover_qualified_star_columns_from_subquery(root, &paren_select, binder);
620 }
621
622 match resolve::find_table_source(&table_name_node)? {
623 resolve::TableSource::Alias(alias) => {
624 hover_qualified_star_columns_from_alias(root, &alias, binder)
625 }
626 resolve::TableSource::WithTable(with_table) => {
627 hover_qualified_star_columns_from_cte(root, &with_table, binder)
628 }
629 resolve::TableSource::CreateTable(create_table) => {
630 hover_qualified_star_columns_from_table(root, &create_table, binder)
631 }
632 resolve::TableSource::CreateView(create_view) => {
633 hover_qualified_star_columns_from_view(&create_view, binder)
634 }
635 resolve::TableSource::CreateMaterializedView(create_materialized_view) => {
636 hover_qualified_star_columns_from_materialized_view(&create_materialized_view, binder)
637 }
638 resolve::TableSource::ParenSelect(paren_select) => {
639 hover_qualified_star_columns_from_subquery(root, &paren_select, binder)
640 }
641 }
642}
643
644fn hover_qualified_star_columns_from_alias(
645 root: &SyntaxNode,
646 alias: &ast::Alias,
647 binder: &binder::Binder,
648) -> Option<String> {
649 let alias_name = Name::from_node(&alias.name()?);
650 let alias_columns: Vec<Name> = alias
651 .column_list()?
652 .columns()
653 .filter_map(|column| column.name().map(|name| Name::from_node(&name)))
654 .collect();
655
656 if alias_columns.is_empty() {
657 return None;
658 }
659
660 let mut results: Vec<String> = alias_columns
661 .iter()
662 .map(|column_name| {
663 ColumnHover::table_column(&alias_name.to_string(), &column_name.to_string())
664 })
665 .collect();
666
667 let from_item = alias.syntax().ancestors().find_map(ast::FromItem::cast)?;
668 let table_ptr = resolve::table_ptr_from_from_item(binder, &from_item)?;
669 let base_column_names = collect_star_column_names(root, &table_ptr, binder);
670
671 for column_name in base_column_names.iter().skip(alias_columns.len()) {
672 results.push(ColumnHover::table_column(
673 &alias_name.to_string(),
674 &column_name.to_string(),
675 ));
676 }
677
678 Some(results.join("\n"))
679}
680
681fn collect_star_column_names(
682 root: &SyntaxNode,
683 table_ptr: &squawk_syntax::SyntaxNodePtr,
684 binder: &binder::Binder,
685) -> Vec<Name> {
686 let table_name_node = table_ptr.to_node(root);
687
688 if let Some(paren_select) = ast::ParenSelect::cast(table_name_node.clone()) {
689 let columns: Vec<Name> =
690 resolve::collect_paren_select_columns_with_types(binder, root, &paren_select)
691 .into_iter()
692 .map(|(name, _ty)| name)
693 .collect();
694 if !columns.is_empty() {
695 return columns;
696 }
697 return collect_star_column_names_from_paren_select(root, &paren_select, binder);
698 }
699
700 match resolve::find_table_source(&table_name_node) {
701 Some(resolve::TableSource::Alias(alias)) => alias
702 .column_list()
703 .into_iter()
704 .flat_map(|column_list| column_list.columns())
705 .filter_map(|column| column.name().map(|name| Name::from_node(&name)))
706 .collect(),
707 Some(resolve::TableSource::WithTable(with_table)) => {
708 let columns = resolve::collect_with_table_column_names(binder, root, &with_table);
709 if !columns.is_empty() {
710 return columns;
711 }
712
713 let builtins_tree = ast::SourceFile::parse(BUILTINS_SQL).tree();
714 let builtins_binder = binder::bind(&builtins_tree);
715 resolve::collect_with_table_column_names(
716 &builtins_binder,
717 builtins_tree.syntax(),
718 &with_table,
719 )
720 }
721 Some(resolve::TableSource::CreateTable(create_table)) => {
722 resolve::collect_table_columns(binder, root, &create_table)
723 .into_iter()
724 .filter_map(|column| column.name().map(|name| Name::from_node(&name)))
725 .collect()
726 }
727 Some(resolve::TableSource::CreateView(create_view)) => {
728 resolve::collect_view_column_names(&create_view)
729 }
730 Some(resolve::TableSource::CreateMaterializedView(create_materialized_view)) => {
731 resolve::collect_materialized_view_column_names(&create_materialized_view)
732 }
733 Some(resolve::TableSource::ParenSelect(paren_select)) => {
734 resolve::collect_paren_select_columns_with_types(binder, root, &paren_select)
735 .into_iter()
736 .map(|(name, _ty)| name)
737 .collect()
738 }
739 None => vec![],
740 }
741}
742
743fn collect_star_column_names_from_paren_select(
744 root: &SyntaxNode,
745 paren_select: &ast::ParenSelect,
746 binder: &binder::Binder,
747) -> Vec<Name> {
748 let Some(select_variant) = paren_select.select() else {
749 return vec![];
750 };
751 let ast::SelectVariant::Select(select) = select_variant else {
752 return vec![];
753 };
754 let Some(from_clause) = select.from_clause() else {
755 return vec![];
756 };
757 let mut columns = vec![];
758 for from_item in from_clause.from_items() {
759 if let Some(table_ptr) = resolve::table_ptr_from_from_item(binder, &from_item) {
760 columns.extend(collect_star_column_names(root, &table_ptr, binder));
761 }
762 }
763 columns
764}
765
766fn hover_qualified_star_columns_from_table(
767 root: &SyntaxNode,
768 create_table: &impl ast::HasCreateTable,
769 binder: &binder::Binder,
770) -> Option<String> {
771 let path = create_table.path()?;
772 let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
773 let schema = schema.to_string();
774 let results: Vec<String> = resolve::collect_table_columns(binder, root, create_table)
775 .into_iter()
776 .filter_map(|column| {
777 let column_name = Name::from_node(&column.name()?);
778 let ty = column.ty()?;
779 let ty = &ty.syntax().text().to_string();
780 Some(ColumnHover::schema_table_column_type(
781 &schema,
782 &table_name,
783 &column_name.to_string(),
784 ty,
785 ))
786 })
787 .collect();
788
789 if results.is_empty() {
790 return None;
791 }
792
793 Some(results.join("\n"))
794}
795
796fn hover_qualified_star_columns_from_cte(
797 root: &SyntaxNode,
798 with_table: &ast::WithTable,
799 binder: &binder::Binder,
800) -> Option<String> {
801 let cte_name = Name::from_node(&with_table.name()?);
802 let column_names = resolve::collect_with_table_column_names(binder, root, with_table);
803 let results: Vec<String> = column_names
804 .iter()
805 .map(|column_name| {
806 ColumnHover::table_column(&cte_name.to_string(), &column_name.to_string())
807 })
808 .collect();
809
810 if results.is_empty() {
811 return None;
812 }
813
814 Some(results.join("\n"))
815}
816
817fn hover_qualified_star_columns_from_view(
818 create_view: &ast::CreateView,
819 binder: &binder::Binder,
820) -> Option<String> {
821 let path = create_view.path()?;
822 let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
823
824 let schema_str = schema.to_string();
825 let column_names = resolve::collect_view_column_names(create_view);
826 let results: Vec<String> = column_names
827 .iter()
828 .map(|column_name| {
829 ColumnHover::schema_table_column(&schema_str, &view_name, &column_name.to_string())
830 })
831 .collect();
832
833 if results.is_empty() {
834 return None;
835 }
836
837 Some(results.join("\n"))
838}
839
840fn hover_qualified_star_columns_from_materialized_view(
841 create_materialized_view: &ast::CreateMaterializedView,
842 binder: &binder::Binder,
843) -> Option<String> {
844 let path = create_materialized_view.path()?;
845 let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
846
847 let schema_str = schema.to_string();
848 let column_names = resolve::collect_materialized_view_column_names(create_materialized_view);
849 let results: Vec<String> = column_names
850 .iter()
851 .map(|column_name| {
852 ColumnHover::schema_table_column(&schema_str, &view_name, &column_name.to_string())
853 })
854 .collect();
855
856 if results.is_empty() {
857 return None;
858 }
859
860 Some(results.join("\n"))
861}
862
863fn hover_qualified_star_columns_from_subquery(
864 root: &SyntaxNode,
865 paren_select: &ast::ParenSelect,
866 binder: &binder::Binder,
867) -> Option<String> {
868 let select_variant = paren_select.select()?;
869
870 if let ast::SelectVariant::Select(select) = select_variant {
871 let select_clause = select.select_clause()?;
872 let target_list = select_clause.target_list()?;
873
874 let mut results = vec![];
875 let subquery_alias = subquery_alias_name(paren_select);
876
877 for target in target_list.targets() {
878 if target.star_token().is_some() {
879 let table_ptrs = resolve::resolve_unqualified_star_table_ptrs(binder, &target)?;
880 for table_ptr in table_ptrs {
881 if let Some(columns) = hover_qualified_star_columns(root, &table_ptr, binder) {
882 results.push(columns)
883 }
884 }
885 continue;
886 }
887
888 if let Some(result) =
889 hover_subquery_target_column(root, &target, subquery_alias.as_ref(), binder)
890 {
891 results.push(result);
892 }
893 }
894
895 if results.is_empty() {
896 return None;
897 }
898
899 return Some(results.join("\n"));
900 }
901
902 let subquery_alias = subquery_alias_name(paren_select);
903 let results: Vec<String> =
904 resolve::collect_paren_select_columns_with_types(binder, root, paren_select)
905 .into_iter()
906 .map(|(column_name, ty)| {
907 if let Some(alias) = &subquery_alias {
908 return ColumnHover::table_column(&alias.to_string(), &column_name.to_string());
909 }
910 if let Some(ty) = ty {
911 return ColumnHover::anon_column_type(
912 &column_name.to_string(),
913 &ty.to_string(),
914 );
915 }
916 ColumnHover::anon_column(&column_name.to_string())
917 })
918 .collect();
919
920 if results.is_empty() {
921 return None;
922 }
923
924 Some(results.join("\n"))
925}
926
927fn subquery_alias_name(paren_select: &ast::ParenSelect) -> Option<Name> {
928 let from_item = paren_select
929 .syntax()
930 .ancestors()
931 .find_map(ast::FromItem::cast)?;
932 let alias_name = from_item.alias()?.name()?;
933 Some(Name::from_node(&alias_name))
934}
935
936fn hover_subquery_target_column(
937 root: &SyntaxNode,
938 target: &ast::Target,
939 subquery_alias: Option<&Name>,
940 binder: &binder::Binder,
941) -> Option<String> {
942 if let Some(alias) = subquery_alias
943 && let Some((col_name, _node)) = ColumnName::from_target(target.clone())
944 && let Some(col_name) = col_name.to_string()
945 {
946 return Some(ColumnHover::table_column(&alias.to_string(), &col_name));
947 }
948
949 let result = match target.expr()? {
950 ast::Expr::NameRef(name_ref) => hover_column(root, &name_ref, binder),
951 ast::Expr::FieldExpr(field_expr) => {
952 let field = field_expr.field()?;
953 hover_column(root, &field, binder)
954 }
955 _ => None,
956 };
957
958 if result.is_some() {
959 return result;
960 }
961
962 if let Some((col_name, _node)) = ColumnName::from_target(target.clone())
963 && let Some(col_name) = col_name.to_string()
964 {
965 return Some(ColumnHover::anon_column(&col_name));
966 }
967
968 None
969}
970
971fn hover_index(
972 root: &SyntaxNode,
973 name_ref: &ast::NameRef,
974 binder: &binder::Binder,
975) -> Option<String> {
976 let index_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
977 .into_iter()
978 .next()?;
979
980 let index_name_node = index_ptr.to_node(root);
981
982 let create_index = index_name_node
983 .ancestors()
984 .find_map(ast::CreateIndex::cast)?;
985
986 format_create_index(&create_index, binder)
987}
988
989fn hover_sequence(
990 root: &SyntaxNode,
991 name_ref: &ast::NameRef,
992 binder: &binder::Binder,
993) -> Option<String> {
994 let sequence_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
995 .into_iter()
996 .next()?;
997
998 let sequence_name_node = sequence_ptr.to_node(root);
999
1000 let create_sequence = sequence_name_node
1001 .ancestors()
1002 .find_map(ast::CreateSequence::cast)?;
1003
1004 format_create_sequence(&create_sequence, binder)
1005}
1006
1007fn hover_trigger(
1008 root: &SyntaxNode,
1009 name_ref: &ast::NameRef,
1010 binder: &binder::Binder,
1011) -> Option<String> {
1012 let trigger_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1013 .into_iter()
1014 .next()?;
1015
1016 let trigger_name_node = trigger_ptr.to_node(root);
1017
1018 let create_trigger = trigger_name_node
1019 .ancestors()
1020 .find_map(ast::CreateTrigger::cast)?;
1021
1022 format_create_trigger(&create_trigger, binder)
1023}
1024
1025fn hover_policy(
1026 root: &SyntaxNode,
1027 name_ref: &ast::NameRef,
1028 binder: &binder::Binder,
1029) -> Option<String> {
1030 let policy_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1031 .into_iter()
1032 .next()?;
1033
1034 let policy_name_node = policy_ptr.to_node(root);
1035
1036 let create_policy = policy_name_node
1037 .ancestors()
1038 .find_map(ast::CreatePolicy::cast)?;
1039
1040 format_create_policy(&create_policy, binder)
1041}
1042
1043fn hover_event_trigger(
1044 root: &SyntaxNode,
1045 name_ref: &ast::NameRef,
1046 binder: &binder::Binder,
1047) -> Option<String> {
1048 let event_trigger_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1049 .into_iter()
1050 .next()?;
1051
1052 let event_trigger_name_node = event_trigger_ptr.to_node(root);
1053
1054 let create_event_trigger = event_trigger_name_node
1055 .ancestors()
1056 .find_map(ast::CreateEventTrigger::cast)?;
1057
1058 format_create_event_trigger(&create_event_trigger)
1059}
1060
1061fn hover_tablespace(
1062 root: &SyntaxNode,
1063 name_ref: &ast::NameRef,
1064 binder: &binder::Binder,
1065) -> Option<String> {
1066 let tablespace_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1067 .into_iter()
1068 .next()?;
1069 let tablespace_name_node = tablespace_ptr.to_node(root);
1070 Some(format!("tablespace {}", tablespace_name_node.text()))
1071}
1072
1073fn hover_database(
1074 root: &SyntaxNode,
1075 name_ref: &ast::NameRef,
1076 binder: &binder::Binder,
1077) -> Option<String> {
1078 let database_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1079 .into_iter()
1080 .next()?;
1081 let database_name_node = database_ptr.to_node(root);
1082 Some(format!("database {}", database_name_node.text()))
1083}
1084
1085fn hover_server(
1086 root: &SyntaxNode,
1087 name_ref: &ast::NameRef,
1088 binder: &binder::Binder,
1089) -> Option<String> {
1090 let server_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1091 .into_iter()
1092 .next()?;
1093 let server_name_node = server_ptr.to_node(root);
1094 Some(format!("server {}", server_name_node.text()))
1095}
1096
1097fn hover_extension(
1098 root: &SyntaxNode,
1099 name_ref: &ast::NameRef,
1100 binder: &binder::Binder,
1101) -> Option<String> {
1102 let extension_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1103 .into_iter()
1104 .next()?;
1105 let extension_name_node = extension_ptr.to_node(root);
1106 Some(format!("extension {}", extension_name_node.text()))
1107}
1108
1109fn hover_role(
1110 root: &SyntaxNode,
1111 name_ref: &ast::NameRef,
1112 binder: &binder::Binder,
1113) -> Option<String> {
1114 let role_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1115 .into_iter()
1116 .next()?;
1117 let role_name_node = role_ptr.to_node(root);
1118 Some(format!("role {}", role_name_node.text()))
1119}
1120
1121fn hover_cursor(
1122 root: &SyntaxNode,
1123 name_ref: &ast::NameRef,
1124 binder: &binder::Binder,
1125) -> Option<String> {
1126 let cursor_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1127 .into_iter()
1128 .next()?;
1129 let cursor_name_node = cursor_ptr.to_node(root);
1130 let declare = cursor_name_node.ancestors().find_map(ast::Declare::cast)?;
1131 format_declare_cursor(&declare)
1132}
1133
1134fn hover_prepared_statement(
1135 root: &SyntaxNode,
1136 name_ref: &ast::NameRef,
1137 binder: &binder::Binder,
1138) -> Option<String> {
1139 let statement_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1140 .into_iter()
1141 .next()?;
1142 let statement_name_node = statement_ptr.to_node(root);
1143 let prepare = statement_name_node
1144 .ancestors()
1145 .find_map(ast::Prepare::cast)?;
1146 format_prepare(&prepare)
1147}
1148
1149fn hover_channel(
1150 root: &SyntaxNode,
1151 name_ref: &ast::NameRef,
1152 binder: &binder::Binder,
1153) -> Option<String> {
1154 let channel_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1155 .into_iter()
1156 .next()?;
1157 let channel_name_node = channel_ptr.to_node(root);
1158 let listen = channel_name_node.ancestors().find_map(ast::Listen::cast)?;
1159 format_listen(&listen)
1160}
1161
1162fn hover_type(
1163 root: &SyntaxNode,
1164 name_ref: &ast::NameRef,
1165 binder: &binder::Binder,
1166) -> Option<String> {
1167 let type_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1168 .into_iter()
1169 .next()?;
1170
1171 let type_name_node = type_ptr.to_node(root);
1172
1173 let create_type = type_name_node.ancestors().find_map(ast::CreateType::cast)?;
1174
1175 format_create_type(&create_type, binder)
1176}
1177
1178fn format_declare_cursor(declare: &ast::Declare) -> Option<String> {
1179 let name = declare.name()?;
1180 let query = declare.query()?;
1181 Some(format!(
1182 "cursor {} for {}",
1183 name.syntax().text(),
1184 query.syntax().text()
1185 ))
1186}
1187
1188fn format_prepare(prepare: &ast::Prepare) -> Option<String> {
1189 let name = prepare.name()?;
1190 let stmt = prepare.preparable_stmt()?;
1191 Some(format!(
1192 "prepare {} as {}",
1193 name.syntax().text(),
1194 stmt.syntax().text()
1195 ))
1196}
1197
1198fn format_listen(listen: &ast::Listen) -> Option<String> {
1199 let name = listen.name()?;
1200 Some(format!("listen {}", name.syntax().text()))
1201}
1202
1203fn format_create_table(
1204 create_table: &impl ast::HasCreateTable,
1205 binder: &binder::Binder,
1206) -> Option<String> {
1207 let path = create_table.path()?;
1208 let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
1209 let schema = schema.to_string();
1210 let args = create_table.table_arg_list()?.syntax().text().to_string();
1211
1212 let foreign = if create_table.syntax().kind() == SyntaxKind::CREATE_FOREIGN_TABLE {
1213 "foreign "
1214 } else {
1215 ""
1216 };
1217
1218 Some(format!("{foreign}table {schema}.{table_name}{args}"))
1219}
1220
1221fn format_create_view(create_view: &ast::CreateView, binder: &binder::Binder) -> Option<String> {
1222 let path = create_view.path()?;
1223 let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
1226 let schema = schema.to_string();
1227
1228 let column_list = create_view
1229 .column_list()
1230 .map(|cl| cl.syntax().text().to_string())
1231 .unwrap_or_default();
1232
1233 let query = create_view.query()?.syntax().text().to_string();
1234
1235 Some(format!(
1236 "view {}.{}{} as {}",
1237 schema, view_name, column_list, query
1238 ))
1239}
1240
1241fn format_create_materialized_view(
1242 create_materialized_view: &ast::CreateMaterializedView,
1243 binder: &binder::Binder,
1244) -> Option<String> {
1245 let path = create_materialized_view.path()?;
1246 let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
1247 let schema = schema.to_string();
1248
1249 let column_list = create_materialized_view
1250 .column_list()
1251 .map(|cl| cl.syntax().text().to_string())
1252 .unwrap_or_default();
1253
1254 let query = create_materialized_view
1255 .query()?
1256 .syntax()
1257 .text()
1258 .to_string();
1259
1260 Some(format!(
1261 "materialized view {}.{}{} as {}",
1262 schema, view_name, column_list, query
1263 ))
1264}
1265
1266fn format_view_column(
1267 create_view: &ast::CreateView,
1268 column_name: Name,
1269 binder: &binder::Binder,
1270) -> Option<String> {
1271 let path = create_view.path()?;
1272 let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
1273 Some(ColumnHover::schema_table_column(
1274 &schema.to_string(),
1275 &view_name,
1276 &column_name.to_string(),
1277 ))
1278}
1279
1280fn format_with_table(with_table: &ast::WithTable) -> Option<String> {
1281 let name = with_table.name()?.syntax().text().to_string();
1282 let query = with_table.query()?.syntax().text().to_string();
1283 Some(format!("with {} as ({})", name, query))
1284}
1285
1286fn format_paren_select(paren_select: &ast::ParenSelect) -> Option<String> {
1287 let query = paren_select.select()?.syntax().text().to_string();
1288 Some(format!("({})", query))
1289}
1290
1291fn format_create_index(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
1292 let index_name = create_index.name()?.syntax().text().to_string();
1293
1294 let index_schema = index_schema(create_index, binder)?;
1295
1296 let relation_name = create_index.relation_name()?;
1297 let path = relation_name.path()?;
1298 let (table_schema, table_name) = resolve::resolve_table_info(binder, &path)?;
1299
1300 let partition_item_list = create_index.partition_item_list()?;
1301 let columns = partition_item_list.syntax().text().to_string();
1302
1303 Some(format!(
1304 "index {}.{} on {}.{}{}",
1305 index_schema, index_name, table_schema, table_name, columns
1306 ))
1307}
1308
1309fn format_create_sequence(
1310 create_sequence: &ast::CreateSequence,
1311 binder: &binder::Binder,
1312) -> Option<String> {
1313 let path = create_sequence.path()?;
1314 let (schema, sequence_name) = resolve::resolve_sequence_info(binder, &path)?;
1315
1316 Some(format!("sequence {}.{}", schema, sequence_name))
1317}
1318
1319fn format_create_trigger(
1320 create_trigger: &ast::CreateTrigger,
1321 binder: &binder::Binder,
1322) -> Option<String> {
1323 let trigger_name = create_trigger.name()?.syntax().text().to_string();
1324 let on_table_path = create_trigger.on_table()?.path()?;
1325
1326 let (schema, table_name) = resolve::resolve_table_info(binder, &on_table_path)?;
1327 Some(format!(
1328 "trigger {}.{} on {}.{}",
1329 schema, trigger_name, schema, table_name
1330 ))
1331}
1332
1333fn format_create_policy(
1334 create_policy: &ast::CreatePolicy,
1335 binder: &binder::Binder,
1336) -> Option<String> {
1337 let policy_name = create_policy.name()?.syntax().text().to_string();
1338 let on_table_path = create_policy.on_table()?.path()?;
1339
1340 let (schema, table_name) = resolve::resolve_table_info(binder, &on_table_path)?;
1341 Some(format!(
1342 "policy {}.{} on {}.{}",
1343 schema, policy_name, schema, table_name
1344 ))
1345}
1346
1347fn format_create_event_trigger(create_event_trigger: &ast::CreateEventTrigger) -> Option<String> {
1348 let name = create_event_trigger.name()?.syntax().text().to_string();
1349 Some(format!("event trigger {}", name))
1350}
1351
1352fn format_create_tablespace(create_tablespace: &ast::CreateTablespace) -> Option<String> {
1353 let name = create_tablespace.name()?.syntax().text().to_string();
1354 Some(format!("tablespace {}", name))
1355}
1356
1357fn format_create_database(create_database: &ast::CreateDatabase) -> Option<String> {
1358 let name = create_database.name()?.syntax().text().to_string();
1359 Some(format!("database {}", name))
1360}
1361
1362fn format_create_server(create_server: &ast::CreateServer) -> Option<String> {
1363 let name = create_server.name()?.syntax().text().to_string();
1364 Some(format!("server {}", name))
1365}
1366
1367fn format_create_extension(create_extension: &ast::CreateExtension) -> Option<String> {
1368 let name = create_extension.name()?.syntax().text().to_string();
1369 Some(format!("extension {}", name))
1370}
1371
1372fn format_create_role(create_role: &ast::CreateRole) -> Option<String> {
1373 let name = create_role.name()?.syntax().text().to_string();
1374 Some(format!("role {}", name))
1375}
1376
1377fn index_schema(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
1378 let position = create_index.syntax().text_range().start();
1379 let search_path = binder.search_path_at(position);
1380 search_path.first().map(|s| s.to_string())
1381}
1382
1383fn format_create_type(create_type: &ast::CreateType, binder: &binder::Binder) -> Option<String> {
1384 let path = create_type.path()?;
1385 let (schema, type_name) = resolve::resolve_type_info(binder, &path)?;
1386
1387 if let Some(variant_list) = create_type.variant_list() {
1388 let variants = variant_list.syntax().text().to_string();
1389 return Some(format!(
1390 "type {}.{} as enum {}",
1391 schema, type_name, variants
1392 ));
1393 }
1394
1395 if let Some(column_list) = create_type.column_list() {
1396 let columns = column_list.syntax().text().to_string();
1397 return Some(format!("type {}.{} as {}", schema, type_name, columns));
1398 }
1399
1400 if let Some(attribute_list) = create_type.attribute_list() {
1401 let attributes = attribute_list.syntax().text().to_string();
1402 return Some(format!("type {}.{} {}", schema, type_name, attributes));
1403 }
1404
1405 Some(format!("type {}.{}", schema, type_name))
1406}
1407
1408fn hover_schema(
1409 root: &SyntaxNode,
1410 name_ref: &ast::NameRef,
1411 binder: &binder::Binder,
1412) -> Option<String> {
1413 let schema_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1414 .into_iter()
1415 .next()?;
1416
1417 let schema_name_node = schema_ptr.to_node(root);
1418
1419 let create_schema = schema_name_node
1420 .ancestors()
1421 .find_map(ast::CreateSchema::cast)?;
1422
1423 format_create_schema(&create_schema)
1424}
1425
1426fn create_schema_name(create_schema: &ast::CreateSchema) -> Option<String> {
1427 if let Some(schema_name) = create_schema.name() {
1428 return Some(schema_name.syntax().text().to_string());
1429 }
1430
1431 create_schema
1432 .role()
1433 .and_then(|r| r.name())
1434 .map(|n| n.syntax().text().to_string())
1435}
1436
1437fn format_create_schema(create_schema: &ast::CreateSchema) -> Option<String> {
1438 let schema_name = create_schema_name(create_schema)?;
1439 Some(format!("schema {}", schema_name))
1440}
1441
1442fn hover_function(
1443 root: &SyntaxNode,
1444 name_ref: &ast::NameRef,
1445 binder: &binder::Binder,
1446) -> Option<String> {
1447 let function_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1448 .into_iter()
1449 .next()?;
1450
1451 let function_name_node = function_ptr.to_node(root);
1452
1453 let create_function = function_name_node
1454 .ancestors()
1455 .find_map(ast::CreateFunction::cast)?;
1456
1457 format_create_function(&create_function, binder)
1458}
1459
1460fn hover_named_arg_parameter(
1461 root: &SyntaxNode,
1462 name_ref: &ast::NameRef,
1463 binder: &binder::Binder,
1464) -> Option<String> {
1465 let param_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1466 .into_iter()
1467 .next()?;
1468 let param_name_node = param_ptr.to_node(root);
1469 let param = param_name_node.ancestors().find_map(ast::Param::cast)?;
1470 let param_name = param.name().map(|name| Name::from_node(&name))?;
1471 let param_type = param.ty().map(|ty| ty.syntax().text().to_string());
1472
1473 for ancestor in param_name_node.ancestors() {
1474 if let Some(create_function) = ast::CreateFunction::cast(ancestor.clone()) {
1475 let path = create_function.path()?;
1476 let (schema, function_name) = resolve::resolve_function_info(binder, &path)?;
1477 return Some(format_param_hover(
1478 schema,
1479 function_name,
1480 param_name,
1481 param_type,
1482 ));
1483 }
1484 if let Some(create_procedure) = ast::CreateProcedure::cast(ancestor.clone()) {
1485 let path = create_procedure.path()?;
1486 let (schema, procedure_name) = resolve::resolve_procedure_info(binder, &path)?;
1487 return Some(format_param_hover(
1488 schema,
1489 procedure_name,
1490 param_name,
1491 param_type,
1492 ));
1493 }
1494 if let Some(create_aggregate) = ast::CreateAggregate::cast(ancestor) {
1495 let path = create_aggregate.path()?;
1496 let (schema, aggregate_name) = resolve::resolve_aggregate_info(binder, &path)?;
1497 return Some(format_param_hover(
1498 schema,
1499 aggregate_name,
1500 param_name,
1501 param_type,
1502 ));
1503 }
1504 }
1505
1506 None
1507}
1508
1509fn format_param_hover(
1510 schema: Schema,
1511 routine_name: String,
1512 param_name: Name,
1513 param_type: Option<String>,
1514) -> String {
1515 if let Some(param_type) = param_type {
1516 return format!(
1517 "parameter {}.{}.{} {}",
1518 schema, routine_name, param_name, param_type
1519 );
1520 }
1521
1522 format!("parameter {}.{}.{}", schema, routine_name, param_name)
1523}
1524
1525fn format_create_function(
1526 create_function: &ast::CreateFunction,
1527 binder: &binder::Binder,
1528) -> Option<String> {
1529 let path = create_function.path()?;
1530 let (schema, function_name) = resolve::resolve_function_info(binder, &path)?;
1531
1532 let param_list = create_function.param_list()?;
1533 let params = param_list.syntax().text().to_string();
1534
1535 let ret_type = create_function.ret_type()?;
1536 let return_type = ret_type.syntax().text().to_string();
1537
1538 Some(format!(
1539 "function {}.{}{} {}",
1540 schema, function_name, params, return_type
1541 ))
1542}
1543
1544fn hover_aggregate(
1545 root: &SyntaxNode,
1546 name_ref: &ast::NameRef,
1547 binder: &binder::Binder,
1548) -> Option<String> {
1549 let aggregate_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1550 .into_iter()
1551 .next()?;
1552
1553 let aggregate_name_node = aggregate_ptr.to_node(root);
1554
1555 let create_aggregate = aggregate_name_node
1556 .ancestors()
1557 .find_map(ast::CreateAggregate::cast)?;
1558
1559 format_create_aggregate(&create_aggregate, binder)
1560}
1561
1562fn format_create_aggregate(
1563 create_aggregate: &ast::CreateAggregate,
1564 binder: &binder::Binder,
1565) -> Option<String> {
1566 let path = create_aggregate.path()?;
1567 let (schema, aggregate_name) = resolve::resolve_aggregate_info(binder, &path)?;
1568
1569 let param_list = create_aggregate.param_list()?;
1570 let params = param_list.syntax().text().to_string();
1571
1572 Some(format!("aggregate {}.{}{}", schema, aggregate_name, params))
1573}
1574
1575fn hover_procedure(
1576 root: &SyntaxNode,
1577 name_ref: &ast::NameRef,
1578 binder: &binder::Binder,
1579) -> Option<String> {
1580 let procedure_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1581 .into_iter()
1582 .next()?;
1583
1584 let procedure_name_node = procedure_ptr.to_node(root);
1585
1586 let create_procedure = procedure_name_node
1587 .ancestors()
1588 .find_map(ast::CreateProcedure::cast)?;
1589
1590 format_create_procedure(&create_procedure, binder)
1591}
1592
1593fn format_create_procedure(
1594 create_procedure: &ast::CreateProcedure,
1595 binder: &binder::Binder,
1596) -> Option<String> {
1597 let path = create_procedure.path()?;
1598 let (schema, procedure_name) = resolve::resolve_procedure_info(binder, &path)?;
1599
1600 let param_list = create_procedure.param_list()?;
1601 let params = param_list.syntax().text().to_string();
1602
1603 Some(format!("procedure {}.{}{}", schema, procedure_name, params))
1604}
1605
1606fn hover_routine(
1607 root: &SyntaxNode,
1608 name_ref: &ast::NameRef,
1609 binder: &binder::Binder,
1610) -> Option<String> {
1611 let routine_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
1612 .into_iter()
1613 .next()?;
1614 let routine_name = routine_ptr.to_node(root);
1615
1616 for a in routine_name.ancestors() {
1617 if let Some(create_function) = ast::CreateFunction::cast(a.clone()) {
1618 return format_create_function(&create_function, binder);
1619 }
1620 if let Some(create_aggregate) = ast::CreateAggregate::cast(a.clone()) {
1621 return format_create_aggregate(&create_aggregate, binder);
1622 }
1623 if let Some(create_procedure) = ast::CreateProcedure::cast(a) {
1624 return format_create_procedure(&create_procedure, binder);
1625 }
1626 }
1627
1628 None
1629}
1630
1631#[cfg(test)]
1632mod test {
1633 use crate::hover::hover;
1634 use crate::test_utils::fixture;
1635 use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet, renderer::DecorStyle};
1636 use insta::assert_snapshot;
1637 use squawk_syntax::ast;
1638
1639 #[track_caller]
1640 fn check_hover(sql: &str) -> String {
1641 check_hover_(sql).expect("should find hover information")
1642 }
1643
1644 #[track_caller]
1645 fn check_hover_(sql: &str) -> Option<String> {
1646 let (mut offset, sql) = fixture(sql);
1647 offset = offset.checked_sub(1.into()).unwrap_or_default();
1648 let parse = ast::SourceFile::parse(&sql);
1649 assert_eq!(parse.errors(), vec![]);
1650 let file: ast::SourceFile = parse.tree();
1651
1652 if let Some(type_info) = hover(&file, offset) {
1653 let offset_usize: usize = offset.into();
1654 let title = format!("hover: {}", type_info);
1655 let group = Level::INFO.primary_title(&title).element(
1656 Snippet::source(&sql).fold(true).annotation(
1657 AnnotationKind::Context
1658 .span(offset_usize..offset_usize + 1)
1659 .label("hover"),
1660 ),
1661 );
1662 let renderer = Renderer::plain().decor_style(DecorStyle::Unicode);
1663 return Some(
1664 renderer
1665 .render(&[group])
1666 .to_string()
1667 .replace("info: hover:", "hover:"),
1669 );
1670 }
1671 None
1672 }
1673
1674 #[test]
1675 fn hover_column_in_create_index() {
1676 assert_snapshot!(check_hover("
1677create table users(id int, email text);
1678create index idx_email on users(email$0);
1679"), @r"
1680 hover: column public.users.email text
1681 ╭▸
1682 3 │ create index idx_email on users(email);
1683 ╰╴ ─ hover
1684 ");
1685 }
1686
1687 #[test]
1688 fn hover_column_int_type() {
1689 assert_snapshot!(check_hover("
1690create table users(id int, email text);
1691create index idx_id on users(id$0);
1692"), @r"
1693 hover: column public.users.id int
1694 ╭▸
1695 3 │ create index idx_id on users(id);
1696 ╰╴ ─ hover
1697 ");
1698 }
1699
1700 #[test]
1701 fn hover_column_with_schema() {
1702 assert_snapshot!(check_hover("
1703create table public.users(id int, email text);
1704create index idx_email on public.users(email$0);
1705"), @r"
1706 hover: column public.users.email text
1707 ╭▸
1708 3 │ create index idx_email on public.users(email);
1709 ╰╴ ─ hover
1710 ");
1711 }
1712
1713 #[test]
1714 fn hover_column_temp_table() {
1715 assert_snapshot!(check_hover("
1716create temp table users(id int, email text);
1717create index idx_email on users(email$0);
1718"), @r"
1719 hover: column pg_temp.users.email text
1720 ╭▸
1721 3 │ create index idx_email on users(email);
1722 ╰╴ ─ hover
1723 ");
1724 }
1725
1726 #[test]
1727 fn hover_column_multiple_columns() {
1728 assert_snapshot!(check_hover("
1729create table users(id int, email text, name varchar(100));
1730create index idx_users on users(id, email$0, name);
1731"), @r"
1732 hover: column public.users.email text
1733 ╭▸
1734 3 │ create index idx_users on users(id, email, name);
1735 ╰╴ ─ hover
1736 ");
1737 }
1738
1739 #[test]
1740 fn hover_column_varchar() {
1741 assert_snapshot!(check_hover("
1742create table users(id int, name varchar(100));
1743create index idx_name on users(name$0);
1744"), @r"
1745 hover: column public.users.name varchar(100)
1746 ╭▸
1747 3 │ create index idx_name on users(name);
1748 ╰╴ ─ hover
1749 ");
1750 }
1751
1752 #[test]
1753 fn hover_column_bigint() {
1754 assert_snapshot!(check_hover("
1755create table metrics(value bigint);
1756create index idx_value on metrics(value$0);
1757"), @r"
1758 hover: column public.metrics.value bigint
1759 ╭▸
1760 3 │ create index idx_value on metrics(value);
1761 ╰╴ ─ hover
1762 ");
1763 }
1764
1765 #[test]
1766 fn hover_column_timestamp() {
1767 assert_snapshot!(check_hover("
1768create table events(created_at timestamp with time zone);
1769create index idx_created on events(created_at$0);
1770"), @r"
1771 hover: column public.events.created_at timestamp with time zone
1772 ╭▸
1773 3 │ create index idx_created on events(created_at);
1774 ╰╴ ─ hover
1775 ");
1776 }
1777
1778 #[test]
1779 fn hover_column_with_search_path() {
1780 assert_snapshot!(check_hover(r#"
1781set search_path to myschema;
1782create table myschema.users(id int, email text);
1783create index idx_email on users(email$0);
1784"#), @r"
1785 hover: column myschema.users.email text
1786 ╭▸
1787 4 │ create index idx_email on users(email);
1788 ╰╴ ─ hover
1789 ");
1790 }
1791
1792 #[test]
1793 fn hover_column_explicit_schema_overrides_search_path() {
1794 assert_snapshot!(check_hover(r#"
1795set search_path to myschema;
1796create table public.users(id int, email text);
1797create table myschema.users(value bigint);
1798create index idx_email on public.users(email$0);
1799"#), @r"
1800 hover: column public.users.email text
1801 ╭▸
1802 5 │ create index idx_email on public.users(email);
1803 ╰╴ ─ hover
1804 ");
1805 }
1806
1807 #[test]
1808 fn hover_on_table_name() {
1809 assert_snapshot!(check_hover("
1810create table t(id int);
1811create index idx on t$0(id);
1812"), @r"
1813 hover: table public.t(id int)
1814 ╭▸
1815 3 │ create index idx on t(id);
1816 ╰╴ ─ hover
1817 ");
1818 }
1819
1820 #[test]
1821 fn hover_on_index_name_in_create() {
1822 assert_snapshot!(check_hover("
1823create table users(id int);
1824create index idx$0 on users(id);
1825"), @r"
1826 hover: index public.idx on public.users(id)
1827 ╭▸
1828 3 │ create index idx on users(id);
1829 ╰╴ ─ hover
1830 ");
1831 }
1832
1833 #[test]
1834 fn hover_table_in_create_index() {
1835 assert_snapshot!(check_hover("
1836create table users(id int, email text);
1837create index idx_email on users$0(email);
1838"), @r"
1839 hover: table public.users(id int, email text)
1840 ╭▸
1841 3 │ create index idx_email on users(email);
1842 ╰╴ ─ hover
1843 ");
1844 }
1845
1846 #[test]
1847 fn hover_table_with_schema() {
1848 assert_snapshot!(check_hover("
1849create table public.users(id int, email text);
1850create index idx on public.users$0(id);
1851"), @r"
1852 hover: table public.users(id int, email text)
1853 ╭▸
1854 3 │ create index idx on public.users(id);
1855 ╰╴ ─ hover
1856 ");
1857 }
1858
1859 #[test]
1860 fn hover_table_temp() {
1861 assert_snapshot!(check_hover("
1862create temp table users(id int, email text);
1863create index idx on users$0(id);
1864"), @r"
1865 hover: table pg_temp.users(id int, email text)
1866 ╭▸
1867 3 │ create index idx on users(id);
1868 ╰╴ ─ hover
1869 ");
1870 }
1871
1872 #[test]
1873 fn hover_table_multiline() {
1874 assert_snapshot!(check_hover("
1875create table users(
1876 id int,
1877 email text,
1878 name varchar(100)
1879);
1880create index idx on users$0(id);
1881"), @r"
1882 hover: table public.users(
1883 id int,
1884 email text,
1885 name varchar(100)
1886 )
1887 ╭▸
1888 7 │ create index idx on users(id);
1889 ╰╴ ─ hover
1890 ");
1891 }
1892
1893 #[test]
1894 fn hover_table_with_search_path() {
1895 assert_snapshot!(check_hover(r#"
1896set search_path to myschema;
1897create table users(id int, email text);
1898create index idx on users$0(id);
1899"#), @r"
1900 hover: table myschema.users(id int, email text)
1901 ╭▸
1902 4 │ create index idx on users(id);
1903 ╰╴ ─ hover
1904 ");
1905 }
1906
1907 #[test]
1908 fn hover_table_search_path_at_definition() {
1909 assert_snapshot!(check_hover(r#"
1910set search_path to myschema;
1911create table users(id int, email text);
1912set search_path to myschema, otherschema;
1913create index idx on users$0(id);
1914"#), @r"
1915 hover: table myschema.users(id int, email text)
1916 ╭▸
1917 5 │ create index idx on users(id);
1918 ╰╴ ─ hover
1919 ");
1920 }
1921
1922 #[test]
1923 fn hover_on_create_table_definition() {
1924 assert_snapshot!(check_hover("
1925create table t$0(x bigint);
1926"), @r"
1927 hover: table public.t(x bigint)
1928 ╭▸
1929 2 │ create table t(x bigint);
1930 ╰╴ ─ hover
1931 ");
1932 }
1933
1934 #[test]
1935 fn hover_on_create_table_definition_with_schema() {
1936 assert_snapshot!(check_hover("
1937create table myschema.users$0(id int);
1938"), @r"
1939 hover: table myschema.users(id int)
1940 ╭▸
1941 2 │ create table myschema.users(id int);
1942 ╰╴ ─ hover
1943 ");
1944 }
1945
1946 #[test]
1947 fn hover_on_create_temp_table_definition() {
1948 assert_snapshot!(check_hover("
1949create temp table t$0(x bigint);
1950"), @r"
1951 hover: table pg_temp.t(x bigint)
1952 ╭▸
1953 2 │ create temp table t(x bigint);
1954 ╰╴ ─ hover
1955 ");
1956 }
1957
1958 #[test]
1959 fn hover_on_column_in_create_table() {
1960 assert_snapshot!(check_hover("
1961create table t(id$0 int);
1962"), @r"
1963 hover: column public.t.id int
1964 ╭▸
1965 2 │ create table t(id int);
1966 ╰╴ ─ hover
1967 ");
1968 }
1969
1970 #[test]
1971 fn hover_on_column_in_create_table_with_schema() {
1972 assert_snapshot!(check_hover("
1973create table myschema.users(id$0 int, name text);
1974"), @r"
1975 hover: column myschema.users.id int
1976 ╭▸
1977 2 │ create table myschema.users(id int, name text);
1978 ╰╴ ─ hover
1979 ");
1980 }
1981
1982 #[test]
1983 fn hover_on_column_in_temp_table() {
1984 assert_snapshot!(check_hover("
1985create temp table t(x$0 bigint);
1986"), @r"
1987 hover: column pg_temp.t.x bigint
1988 ╭▸
1989 2 │ create temp table t(x bigint);
1990 ╰╴ ─ hover
1991 ");
1992 }
1993
1994 #[test]
1995 fn hover_on_multiple_columns() {
1996 assert_snapshot!(check_hover("
1997create table t(id int, email$0 text, name varchar(100));
1998"), @r"
1999 hover: column public.t.email text
2000 ╭▸
2001 2 │ create table t(id int, email text, name varchar(100));
2002 ╰╴ ─ hover
2003 ");
2004 }
2005
2006 #[test]
2007 fn hover_on_drop_table() {
2008 assert_snapshot!(check_hover("
2009create table users(id int, email text);
2010drop table users$0;
2011"), @r"
2012 hover: table public.users(id int, email text)
2013 ╭▸
2014 3 │ drop table users;
2015 ╰╴ ─ hover
2016 ");
2017 }
2018
2019 #[test]
2020 fn hover_on_drop_table_with_schema() {
2021 assert_snapshot!(check_hover("
2022create table myschema.users(id int);
2023drop table myschema.users$0;
2024"), @r"
2025 hover: table myschema.users(id int)
2026 ╭▸
2027 3 │ drop table myschema.users;
2028 ╰╴ ─ hover
2029 ");
2030 }
2031
2032 #[test]
2033 fn hover_on_drop_temp_table() {
2034 assert_snapshot!(check_hover("
2035create temp table t(x bigint);
2036drop table t$0;
2037"), @r"
2038 hover: table pg_temp.t(x bigint)
2039 ╭▸
2040 3 │ drop table t;
2041 ╰╴ ─ hover
2042 ");
2043 }
2044
2045 #[test]
2046 fn hover_on_create_index_definition() {
2047 assert_snapshot!(check_hover("
2048create table t(x bigint);
2049create index idx$0 on t(x);
2050"), @r"
2051 hover: index public.idx on public.t(x)
2052 ╭▸
2053 3 │ create index idx on t(x);
2054 ╰╴ ─ hover
2055 ");
2056 }
2057
2058 #[test]
2059 fn hover_on_drop_index() {
2060 assert_snapshot!(check_hover("
2061create table t(x bigint);
2062create index idx_x on t(x);
2063drop index idx_x$0;
2064"), @r"
2065 hover: index public.idx_x on public.t(x)
2066 ╭▸
2067 4 │ drop index idx_x;
2068 ╰╴ ─ hover
2069 ");
2070 }
2071
2072 #[test]
2073 fn hover_on_create_type_definition() {
2074 assert_snapshot!(check_hover("
2075create type status$0 as enum ('active', 'inactive');
2076"), @r"
2077 hover: type public.status as enum ('active', 'inactive')
2078 ╭▸
2079 2 │ create type status as enum ('active', 'inactive');
2080 ╰╴ ─ hover
2081 ");
2082 }
2083
2084 #[test]
2085 fn hover_on_create_type_definition_with_schema() {
2086 assert_snapshot!(check_hover("
2087create type myschema.status$0 as enum ('active', 'inactive');
2088"), @r"
2089 hover: type myschema.status as enum ('active', 'inactive')
2090 ╭▸
2091 2 │ create type myschema.status as enum ('active', 'inactive');
2092 ╰╴ ─ hover
2093 ");
2094 }
2095
2096 #[test]
2097 fn hover_on_drop_type() {
2098 assert_snapshot!(check_hover("
2099create type status as enum ('active', 'inactive');
2100drop type status$0;
2101"), @r"
2102 hover: type public.status as enum ('active', 'inactive')
2103 ╭▸
2104 3 │ drop type status;
2105 ╰╴ ─ hover
2106 ");
2107 }
2108
2109 #[test]
2110 fn hover_on_drop_type_with_schema() {
2111 assert_snapshot!(check_hover("
2112create type myschema.status as enum ('active', 'inactive');
2113drop type myschema.status$0;
2114"), @r"
2115 hover: type myschema.status as enum ('active', 'inactive')
2116 ╭▸
2117 3 │ drop type myschema.status;
2118 ╰╴ ─ hover
2119 ");
2120 }
2121
2122 #[test]
2123 fn hover_on_create_type_composite() {
2124 assert_snapshot!(check_hover("
2125create type person$0 as (name text, age int);
2126"), @r"
2127 hover: type public.person as (name text, age int)
2128 ╭▸
2129 2 │ create type person as (name text, age int);
2130 ╰╴ ─ hover
2131 ");
2132 }
2133
2134 #[test]
2135 fn hover_on_drop_type_composite() {
2136 assert_snapshot!(check_hover("
2137create type person as (name text, age int);
2138drop type person$0;
2139"), @r"
2140 hover: type public.person as (name text, age int)
2141 ╭▸
2142 3 │ drop type person;
2143 ╰╴ ─ hover
2144 ");
2145 }
2146
2147 #[test]
2148 fn hover_on_create_type_range() {
2149 assert_snapshot!(check_hover("
2150create type int4_range$0 as range (subtype = int4);
2151"), @r"
2152 hover: type public.int4_range (subtype = int4)
2153 ╭▸
2154 2 │ create type int4_range as range (subtype = int4);
2155 ╰╴ ─ hover
2156 ");
2157 }
2158
2159 #[test]
2160 fn hover_on_drop_type_range() {
2161 assert_snapshot!(check_hover("
2162create type int4_range as range (subtype = int4);
2163drop type int4_range$0;
2164"), @r"
2165 hover: type public.int4_range (subtype = int4)
2166 ╭▸
2167 3 │ drop type int4_range;
2168 ╰╴ ─ hover
2169 ");
2170 }
2171
2172 #[test]
2173 fn hover_on_cast_operator() {
2174 assert_snapshot!(check_hover("
2175create type foo as enum ('a', 'b');
2176select x::foo$0;
2177"), @r"
2178 hover: type public.foo as enum ('a', 'b')
2179 ╭▸
2180 3 │ select x::foo;
2181 ╰╴ ─ hover
2182 ");
2183 }
2184
2185 #[test]
2186 fn hover_on_cast_function() {
2187 assert_snapshot!(check_hover("
2188create type bar as enum ('x', 'y');
2189select cast(x as bar$0);
2190"), @r"
2191 hover: type public.bar as enum ('x', 'y')
2192 ╭▸
2193 3 │ select cast(x as bar);
2194 ╰╴ ─ hover
2195 ");
2196 }
2197
2198 #[test]
2199 fn hover_on_cast_with_schema() {
2200 assert_snapshot!(check_hover("
2201create type myschema.baz as enum ('m', 'n');
2202select x::myschema.baz$0;
2203"), @r"
2204 hover: type myschema.baz as enum ('m', 'n')
2205 ╭▸
2206 3 │ select x::myschema.baz;
2207 ╰╴ ─ hover
2208 ");
2209 }
2210
2211 #[test]
2212 fn hover_on_drop_function() {
2213 assert_snapshot!(check_hover("
2214create function foo() returns int as $$ select 1 $$ language sql;
2215drop function foo$0();
2216"), @r"
2217 hover: function public.foo() returns int
2218 ╭▸
2219 3 │ drop function foo();
2220 ╰╴ ─ hover
2221 ");
2222 }
2223
2224 #[test]
2225 fn hover_on_drop_function_with_schema() {
2226 assert_snapshot!(check_hover("
2227create function myschema.foo() returns int as $$ select 1 $$ language sql;
2228drop function myschema.foo$0();
2229"), @r"
2230 hover: function myschema.foo() returns int
2231 ╭▸
2232 3 │ drop function myschema.foo();
2233 ╰╴ ─ hover
2234 ");
2235 }
2236
2237 #[test]
2238 fn hover_on_create_function_definition() {
2239 assert_snapshot!(check_hover("
2240create function foo$0() returns int as $$ select 1 $$ language sql;
2241"), @r"
2242 hover: function public.foo() returns int
2243 ╭▸
2244 2 │ create function foo() returns int as $$ select 1 $$ language sql;
2245 ╰╴ ─ hover
2246 ");
2247 }
2248
2249 #[test]
2250 fn hover_on_create_function_with_explicit_schema() {
2251 assert_snapshot!(check_hover("
2252create function myschema.foo$0() returns int as $$ select 1 $$ language sql;
2253"), @r"
2254 hover: function myschema.foo() returns int
2255 ╭▸
2256 2 │ create function myschema.foo() returns int as $$ select 1 $$ language sql;
2257 ╰╴ ─ hover
2258 ");
2259 }
2260
2261 #[test]
2262 fn hover_on_drop_function_with_search_path() {
2263 assert_snapshot!(check_hover(r#"
2264set search_path to myschema;
2265create function foo() returns int as $$ select 1 $$ language sql;
2266drop function foo$0();
2267"#), @r"
2268 hover: function myschema.foo() returns int
2269 ╭▸
2270 4 │ drop function foo();
2271 ╰╴ ─ hover
2272 ");
2273 }
2274
2275 #[test]
2276 fn hover_on_drop_function_overloaded() {
2277 assert_snapshot!(check_hover("
2278create function add(complex) returns complex as $$ select null $$ language sql;
2279create function add(bigint) returns bigint as $$ select 1 $$ language sql;
2280drop function add$0(complex);
2281"), @r"
2282 hover: function public.add(complex) returns complex
2283 ╭▸
2284 4 │ drop function add(complex);
2285 ╰╴ ─ hover
2286 ");
2287 }
2288
2289 #[test]
2290 fn hover_on_drop_function_second_overload() {
2291 assert_snapshot!(check_hover("
2292create function add(complex) returns complex as $$ select null $$ language sql;
2293create function add(bigint) returns bigint as $$ select 1 $$ language sql;
2294drop function add$0(bigint);
2295"), @r"
2296 hover: function public.add(bigint) returns bigint
2297 ╭▸
2298 4 │ drop function add(bigint);
2299 ╰╴ ─ hover
2300 ");
2301 }
2302
2303 #[test]
2304 fn hover_on_drop_aggregate() {
2305 assert_snapshot!(check_hover("
2306create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2307drop aggregate myavg$0(int);
2308"), @r"
2309 hover: aggregate public.myavg(int)
2310 ╭▸
2311 3 │ drop aggregate myavg(int);
2312 ╰╴ ─ hover
2313 ");
2314 }
2315
2316 #[test]
2317 fn hover_on_drop_aggregate_with_schema() {
2318 assert_snapshot!(check_hover("
2319create aggregate myschema.myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2320drop aggregate myschema.myavg$0(int);
2321"), @r"
2322 hover: aggregate myschema.myavg(int)
2323 ╭▸
2324 3 │ drop aggregate myschema.myavg(int);
2325 ╰╴ ─ hover
2326 ");
2327 }
2328
2329 #[test]
2330 fn hover_on_create_aggregate_definition() {
2331 assert_snapshot!(check_hover("
2332create aggregate myavg$0(int) (sfunc = int4_avg_accum, stype = _int8);
2333"), @r"
2334 hover: aggregate public.myavg(int)
2335 ╭▸
2336 2 │ create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2337 ╰╴ ─ hover
2338 ");
2339 }
2340
2341 #[test]
2342 fn hover_on_drop_aggregate_with_search_path() {
2343 assert_snapshot!(check_hover(r#"
2344set search_path to myschema;
2345create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2346drop aggregate myavg$0(int);
2347"#), @r"
2348 hover: aggregate myschema.myavg(int)
2349 ╭▸
2350 4 │ drop aggregate myavg(int);
2351 ╰╴ ─ hover
2352 ");
2353 }
2354
2355 #[test]
2356 fn hover_on_drop_aggregate_overloaded() {
2357 assert_snapshot!(check_hover("
2358create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
2359create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
2360drop aggregate sum$0(complex);
2361"), @r"
2362 hover: aggregate public.sum(complex)
2363 ╭▸
2364 4 │ drop aggregate sum(complex);
2365 ╰╴ ─ hover
2366 ");
2367 }
2368
2369 #[test]
2370 fn hover_on_drop_aggregate_second_overload() {
2371 assert_snapshot!(check_hover("
2372create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
2373create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
2374drop aggregate sum$0(bigint);
2375"), @r"
2376 hover: aggregate public.sum(bigint)
2377 ╭▸
2378 4 │ drop aggregate sum(bigint);
2379 ╰╴ ─ hover
2380 ");
2381 }
2382
2383 #[test]
2384 fn hover_on_select_function_call() {
2385 assert_snapshot!(check_hover("
2386create function foo() returns int as $$ select 1 $$ language sql;
2387select foo$0();
2388"), @r"
2389 hover: function public.foo() returns int
2390 ╭▸
2391 3 │ select foo();
2392 ╰╴ ─ hover
2393 ");
2394 }
2395
2396 #[test]
2397 fn hover_on_select_function_call_with_schema() {
2398 assert_snapshot!(check_hover("
2399create function public.foo() returns int as $$ select 1 $$ language sql;
2400select public.foo$0();
2401"), @r"
2402 hover: function public.foo() returns int
2403 ╭▸
2404 3 │ select public.foo();
2405 ╰╴ ─ hover
2406 ");
2407 }
2408
2409 #[test]
2410 fn hover_on_select_function_call_with_search_path() {
2411 assert_snapshot!(check_hover(r#"
2412set search_path to myschema;
2413create function foo() returns int as $$ select 1 $$ language sql;
2414select foo$0();
2415"#), @r"
2416 hover: function myschema.foo() returns int
2417 ╭▸
2418 4 │ select foo();
2419 ╰╴ ─ hover
2420 ");
2421 }
2422
2423 #[test]
2424 fn hover_on_select_function_call_with_params() {
2425 assert_snapshot!(check_hover("
2426create function add(a int, b int) returns int as $$ select a + b $$ language sql;
2427select add$0(1, 2);
2428"), @r"
2429 hover: function public.add(a int, b int) returns int
2430 ╭▸
2431 3 │ select add(1, 2);
2432 ╰╴ ─ hover
2433 ");
2434 }
2435
2436 #[test]
2437 fn hover_on_builtin_function_call() {
2438 assert_snapshot!(check_hover("
2439select now$0();
2440"), @r"
2441 hover: function pg_catalog.now() returns timestamp with time zone
2442 ╭▸
2443 2 │ select now();
2444 ╰╴ ─ hover
2445 ");
2446 }
2447
2448 #[test]
2449 fn hover_on_named_arg_param() {
2450 assert_snapshot!(check_hover("
2451create function foo(bar_param int) returns int as $$ select 1 $$ language sql;
2452select foo(bar_param$0 := 5);
2453"), @r"
2454 hover: parameter public.foo.bar_param int
2455 ╭▸
2456 3 │ select foo(bar_param := 5);
2457 ╰╴ ─ hover
2458 ");
2459 }
2460
2461 #[test]
2462 fn hover_on_named_arg_param_schema_qualified() {
2463 assert_snapshot!(check_hover("
2464create schema s;
2465create function s.foo(my_param int) returns int as $$ select 1 $$ language sql;
2466select s.foo(my_param$0 := 10);
2467"), @r"
2468 hover: parameter s.foo.my_param int
2469 ╭▸
2470 4 │ select s.foo(my_param := 10);
2471 ╰╴ ─ hover
2472 ");
2473 }
2474
2475 #[test]
2476 fn hover_on_named_arg_param_procedure() {
2477 assert_snapshot!(check_hover("
2478create procedure proc(param_x int) as 'select 1' language sql;
2479call proc(param_x$0 := 42);
2480"), @r"
2481 hover: parameter public.proc.param_x int
2482 ╭▸
2483 3 │ call proc(param_x := 42);
2484 ╰╴ ─ hover
2485 ");
2486 }
2487
2488 #[test]
2489 fn hover_on_function_call_style_column_access() {
2490 assert_snapshot!(check_hover("
2491create table t(a int, b int);
2492select a$0(t) from t;
2493"), @r"
2494 hover: column public.t.a int
2495 ╭▸
2496 3 │ select a(t) from t;
2497 ╰╴ ─ hover
2498 ");
2499 }
2500
2501 #[test]
2502 fn hover_on_function_call_style_column_access_with_function_precedence() {
2503 assert_snapshot!(check_hover("
2504create table t(a int, b int);
2505create function b(t) returns int as 'select 1' LANGUAGE sql;
2506select b$0(t) from t;
2507"), @r"
2508 hover: function public.b(t) returns int
2509 ╭▸
2510 4 │ select b(t) from t;
2511 ╰╴ ─ hover
2512 ");
2513 }
2514
2515 #[test]
2516 fn hover_on_function_call_style_table_arg() {
2517 assert_snapshot!(check_hover("
2518create table t(a int, b int);
2519select a(t$0) from t;
2520"), @r"
2521 hover: table public.t(a int, b int)
2522 ╭▸
2523 3 │ select a(t) from t;
2524 ╰╴ ─ hover
2525 ");
2526 }
2527
2528 #[test]
2529 fn hover_on_function_call_style_table_arg_with_function() {
2530 assert_snapshot!(check_hover("
2531create table t(a int, b int);
2532create function b(t) returns int as 'select 1' LANGUAGE sql;
2533select b(t$0) from t;
2534"), @r"
2535 hover: table public.t(a int, b int)
2536 ╭▸
2537 4 │ select b(t) from t;
2538 ╰╴ ─ hover
2539 ");
2540 }
2541
2542 #[test]
2543 fn hover_on_function_call_style_table_arg_in_where() {
2544 assert_snapshot!(check_hover("
2545create table t(a int);
2546select * from t where a(t$0) > 2;
2547"), @r"
2548 hover: table public.t(a int)
2549 ╭▸
2550 3 │ select * from t where a(t) > 2;
2551 ╰╴ ─ hover
2552 ");
2553 }
2554
2555 #[test]
2556 fn hover_on_qualified_table_ref_in_where() {
2557 assert_snapshot!(check_hover("
2558create table t(a int);
2559create function b(t) returns int as 'select 1' language sql;
2560select * from t where t$0.b > 2;
2561"), @r"
2562 hover: table public.t(a int)
2563 ╭▸
2564 4 │ select * from t where t.b > 2;
2565 ╰╴ ─ hover
2566 ");
2567 }
2568
2569 #[test]
2570 fn hover_on_field_style_function_call() {
2571 assert_snapshot!(check_hover("
2572create table t(a int);
2573create function b(t) returns int as 'select 1' language sql;
2574select t.b$0 from t;
2575"), @r"
2576 hover: function public.b(t) returns int
2577 ╭▸
2578 4 │ select t.b from t;
2579 ╰╴ ─ hover
2580 ");
2581 }
2582
2583 #[test]
2584 fn hover_on_field_style_function_call_column_precedence() {
2585 assert_snapshot!(check_hover("
2586create table t(a int, b int);
2587create function b(t) returns int as 'select 1' language sql;
2588select t.b$0 from t;
2589"), @r"
2590 hover: column public.t.b int
2591 ╭▸
2592 4 │ select t.b from t;
2593 ╰╴ ─ hover
2594 ");
2595 }
2596
2597 #[test]
2598 fn hover_on_field_style_function_call_table_ref() {
2599 assert_snapshot!(check_hover("
2600create table t(a int);
2601create function b(t) returns int as 'select 1' language sql;
2602select t$0.b from t;
2603"), @r"
2604 hover: table public.t(a int)
2605 ╭▸
2606 4 │ select t.b from t;
2607 ╰╴ ─ hover
2608 ");
2609 }
2610
2611 #[test]
2612 fn hover_on_select_from_table() {
2613 assert_snapshot!(check_hover("
2614create table users(id int, email text);
2615select * from users$0;
2616"), @r"
2617 hover: table public.users(id int, email text)
2618 ╭▸
2619 3 │ select * from users;
2620 ╰╴ ─ hover
2621 ");
2622 }
2623
2624 #[test]
2625 fn hover_on_subquery_qualified_table_ref() {
2626 assert_snapshot!(check_hover("
2627select t$0.a from (select 1 a) t;
2628"), @r"
2629 hover: subquery t as (select 1 a)
2630 ╭▸
2631 2 │ select t.a from (select 1 a) t;
2632 ╰╴ ─ hover
2633 ");
2634 }
2635
2636 #[test]
2637 fn hover_on_subquery_qualified_column_ref() {
2638 assert_snapshot!(check_hover("
2639select t.a$0 from (select 1 a) t;
2640"), @r"
2641 hover: column t.a
2642 ╭▸
2643 2 │ select t.a from (select 1 a) t;
2644 ╰╴ ─ hover
2645 ");
2646 }
2647
2648 #[test]
2649 fn hover_on_select_from_table_with_schema() {
2650 assert_snapshot!(check_hover("
2651create table public.users(id int, email text);
2652select * from public.users$0;
2653"), @r"
2654 hover: table public.users(id int, email text)
2655 ╭▸
2656 3 │ select * from public.users;
2657 ╰╴ ─ hover
2658 ");
2659 }
2660
2661 #[test]
2662 fn hover_on_select_from_table_with_search_path() {
2663 assert_snapshot!(check_hover("
2664set search_path to foo;
2665create table foo.users(id int, email text);
2666select * from users$0;
2667"), @r"
2668 hover: table foo.users(id int, email text)
2669 ╭▸
2670 4 │ select * from users;
2671 ╰╴ ─ hover
2672 ");
2673 }
2674
2675 #[test]
2676 fn hover_on_select_from_temp_table() {
2677 assert_snapshot!(check_hover("
2678create temp table users(id int, email text);
2679select * from users$0;
2680"), @r"
2681 hover: table pg_temp.users(id int, email text)
2682 ╭▸
2683 3 │ select * from users;
2684 ╰╴ ─ hover
2685 ");
2686 }
2687
2688 #[test]
2689 fn hover_on_select_from_multiline_table() {
2690 assert_snapshot!(check_hover("
2691create table users(
2692 id int,
2693 email text,
2694 name varchar(100)
2695);
2696select * from users$0;
2697"), @r"
2698 hover: table public.users(
2699 id int,
2700 email text,
2701 name varchar(100)
2702 )
2703 ╭▸
2704 7 │ select * from users;
2705 ╰╴ ─ hover
2706 ");
2707 }
2708
2709 #[test]
2710 fn hover_on_select_column() {
2711 assert_snapshot!(check_hover("
2712create table users(id int, email text);
2713select id$0 from users;
2714"), @r"
2715 hover: column public.users.id int
2716 ╭▸
2717 3 │ select id from users;
2718 ╰╴ ─ hover
2719 ");
2720 }
2721
2722 #[test]
2723 fn hover_on_select_column_second() {
2724 assert_snapshot!(check_hover("
2725create table users(id int, email text);
2726select id, email$0 from users;
2727"), @r"
2728 hover: column public.users.email text
2729 ╭▸
2730 3 │ select id, email from users;
2731 ╰╴ ─ hover
2732 ");
2733 }
2734
2735 #[test]
2736 fn hover_on_select_column_with_schema() {
2737 assert_snapshot!(check_hover("
2738create table public.users(id int, email text);
2739select email$0 from public.users;
2740"), @r"
2741 hover: column public.users.email text
2742 ╭▸
2743 3 │ select email from public.users;
2744 ╰╴ ─ hover
2745 ");
2746 }
2747
2748 #[test]
2749 fn hover_on_select_column_with_search_path() {
2750 assert_snapshot!(check_hover("
2751set search_path to foo;
2752create table foo.users(id int, email text);
2753select id$0 from users;
2754"), @r"
2755 hover: column foo.users.id int
2756 ╭▸
2757 4 │ select id from users;
2758 ╰╴ ─ hover
2759 ");
2760 }
2761
2762 #[test]
2763 fn hover_on_select_qualified_star() {
2764 assert_snapshot!(check_hover("
2765create table u(id int, b int);
2766select u.*$0 from u;
2767"), @r"
2768 hover: column public.u.id int
2769 column public.u.b int
2770 ╭▸
2771 3 │ select u.* from u;
2772 ╰╴ ─ hover
2773 ");
2774 }
2775
2776 #[test]
2777 fn hover_on_select_unqualified_star() {
2778 assert_snapshot!(check_hover("
2779create table u(id int, b int);
2780select *$0 from u;
2781"), @r"
2782 hover: column public.u.id int
2783 column public.u.b int
2784 ╭▸
2785 3 │ select * from u;
2786 ╰╴ ─ hover
2787 ");
2788 }
2789
2790 #[test]
2791 fn hover_on_select_count_star() {
2792 assert_snapshot!(check_hover("
2793create table u(id int, b int);
2794select count(*$0) from u;
2795"), @r"
2796 hover: column public.u.id int
2797 column public.u.b int
2798 ╭▸
2799 3 │ select count(*) from u;
2800 ╰╴ ─ hover
2801 ");
2802 }
2803
2804 #[test]
2805 fn hover_on_insert_table() {
2806 assert_snapshot!(check_hover("
2807create table users(id int, email text);
2808insert into users$0(id, email) values (1, 'test');
2809"), @r"
2810 hover: table public.users(id int, email text)
2811 ╭▸
2812 3 │ insert into users(id, email) values (1, 'test');
2813 ╰╴ ─ hover
2814 ");
2815 }
2816
2817 #[test]
2818 fn hover_on_insert_table_with_schema() {
2819 assert_snapshot!(check_hover("
2820create table public.users(id int, email text);
2821insert into public.users$0(id, email) values (1, 'test');
2822"), @r"
2823 hover: table public.users(id int, email text)
2824 ╭▸
2825 3 │ insert into public.users(id, email) values (1, 'test');
2826 ╰╴ ─ hover
2827 ");
2828 }
2829
2830 #[test]
2831 fn hover_on_insert_column() {
2832 assert_snapshot!(check_hover("
2833create table users(id int, email text);
2834insert into users(id$0, email) values (1, 'test');
2835"), @r"
2836 hover: column public.users.id int
2837 ╭▸
2838 3 │ insert into users(id, email) values (1, 'test');
2839 ╰╴ ─ hover
2840 ");
2841 }
2842
2843 #[test]
2844 fn hover_on_insert_column_second() {
2845 assert_snapshot!(check_hover("
2846create table users(id int, email text);
2847insert into users(id, email$0) values (1, 'test');
2848"), @r"
2849 hover: column public.users.email text
2850 ╭▸
2851 3 │ insert into users(id, email) values (1, 'test');
2852 ╰╴ ─ hover
2853 ");
2854 }
2855
2856 #[test]
2857 fn hover_on_insert_column_with_schema() {
2858 assert_snapshot!(check_hover("
2859create table public.users(id int, email text);
2860insert into public.users(email$0) values ('test');
2861"), @r"
2862 hover: column public.users.email text
2863 ╭▸
2864 3 │ insert into public.users(email) values ('test');
2865 ╰╴ ─ hover
2866 ");
2867 }
2868
2869 #[test]
2870 fn hover_on_delete_table() {
2871 assert_snapshot!(check_hover("
2872create table users(id int, email text);
2873delete from users$0 where id = 1;
2874"), @r"
2875 hover: table public.users(id int, email text)
2876 ╭▸
2877 3 │ delete from users where id = 1;
2878 ╰╴ ─ hover
2879 ");
2880 }
2881
2882 #[test]
2883 fn hover_on_delete_table_with_schema() {
2884 assert_snapshot!(check_hover("
2885create table public.users(id int, email text);
2886delete from public.users$0 where id = 1;
2887"), @r"
2888 hover: table public.users(id int, email text)
2889 ╭▸
2890 3 │ delete from public.users where id = 1;
2891 ╰╴ ─ hover
2892 ");
2893 }
2894
2895 #[test]
2896 fn hover_on_delete_where_column() {
2897 assert_snapshot!(check_hover("
2898create table users(id int, email text);
2899delete from users where id$0 = 1;
2900"), @r"
2901 hover: column public.users.id int
2902 ╭▸
2903 3 │ delete from users where id = 1;
2904 ╰╴ ─ hover
2905 ");
2906 }
2907
2908 #[test]
2909 fn hover_on_delete_where_column_second() {
2910 assert_snapshot!(check_hover("
2911create table users(id int, email text, active boolean);
2912delete from users where id = 1 and email$0 = 'test';
2913"), @r"
2914 hover: column public.users.email text
2915 ╭▸
2916 3 │ delete from users where id = 1 and email = 'test';
2917 ╰╴ ─ hover
2918 ");
2919 }
2920
2921 #[test]
2922 fn hover_on_delete_where_column_with_schema() {
2923 assert_snapshot!(check_hover("
2924create table public.users(id int, email text);
2925delete from public.users where email$0 = 'test';
2926"), @r"
2927 hover: column public.users.email text
2928 ╭▸
2929 3 │ delete from public.users where email = 'test';
2930 ╰╴ ─ hover
2931 ");
2932 }
2933
2934 #[test]
2935 fn hover_on_select_table_as_column() {
2936 assert_snapshot!(check_hover("
2937create table t(x bigint, y bigint);
2938select t$0 from t;
2939"), @r"
2940 hover: table public.t(x bigint, y bigint)
2941 ╭▸
2942 3 │ select t from t;
2943 ╰╴ ─ hover
2944 ");
2945 }
2946
2947 #[test]
2948 fn hover_on_select_table_as_column_with_schema() {
2949 assert_snapshot!(check_hover("
2950create table public.t(x bigint, y bigint);
2951select t$0 from public.t;
2952"), @r"
2953 hover: table public.t(x bigint, y bigint)
2954 ╭▸
2955 3 │ select t from public.t;
2956 ╰╴ ─ hover
2957 ");
2958 }
2959
2960 #[test]
2961 fn hover_on_select_table_as_column_with_search_path() {
2962 assert_snapshot!(check_hover("
2963set search_path to foo;
2964create table foo.users(id int, email text);
2965select users$0 from users;
2966"), @r"
2967 hover: table foo.users(id int, email text)
2968 ╭▸
2969 4 │ select users from users;
2970 ╰╴ ─ hover
2971 ");
2972 }
2973
2974 #[test]
2975 fn hover_on_select_column_with_same_name_as_table() {
2976 assert_snapshot!(check_hover("
2977create table t(t int);
2978select t$0 from t;
2979"), @r"
2980 hover: column public.t.t int
2981 ╭▸
2982 3 │ select t from t;
2983 ╰╴ ─ hover
2984 ");
2985 }
2986
2987 #[test]
2988 fn hover_on_create_schema() {
2989 assert_snapshot!(check_hover("
2990create schema foo$0;
2991"), @r"
2992 hover: schema foo
2993 ╭▸
2994 2 │ create schema foo;
2995 ╰╴ ─ hover
2996 ");
2997 }
2998
2999 #[test]
3000 fn hover_on_create_schema_authorization() {
3001 assert_snapshot!(check_hover("
3002create schema authorization foo$0;
3003"), @r"
3004 hover: schema foo
3005 ╭▸
3006 2 │ create schema authorization foo;
3007 ╰╴ ─ hover
3008 ");
3009 }
3010
3011 #[test]
3012 fn hover_on_drop_schema_authorization() {
3013 assert_snapshot!(check_hover("
3014create schema authorization foo;
3015drop schema foo$0;
3016"), @r"
3017 hover: schema foo
3018 ╭▸
3019 3 │ drop schema foo;
3020 ╰╴ ─ hover
3021 ");
3022 }
3023
3024 #[test]
3025 fn hover_on_drop_schema() {
3026 assert_snapshot!(check_hover("
3027create schema foo;
3028drop schema foo$0;
3029"), @r"
3030 hover: schema foo
3031 ╭▸
3032 3 │ drop schema foo;
3033 ╰╴ ─ hover
3034 ");
3035 }
3036
3037 #[test]
3038 fn hover_on_schema_after_definition() {
3039 assert_snapshot!(check_hover("
3040drop schema foo$0;
3041create schema foo;
3042"), @r"
3043 hover: schema foo
3044 ╭▸
3045 2 │ drop schema foo;
3046 ╰╴ ─ hover
3047 ");
3048 }
3049
3050 #[test]
3051 fn hover_on_cte_table() {
3052 assert_snapshot!(check_hover("
3053with t as (select 1 a)
3054select a from t$0;
3055"), @r"
3056 hover: with t as (select 1 a)
3057 ╭▸
3058 3 │ select a from t;
3059 ╰╴ ─ hover
3060 ");
3061 }
3062
3063 #[test]
3064 fn hover_on_select_cte_table_as_column() {
3065 assert_snapshot!(check_hover("
3066with t as (select 1 a, 2 b, 3 c)
3067select t$0 from t;
3068"), @r"
3069 hover: with t as (select 1 a, 2 b, 3 c)
3070 ╭▸
3071 3 │ select t from t;
3072 ╰╴ ─ hover
3073 ");
3074 }
3075
3076 #[test]
3077 fn hover_on_cte_column() {
3078 assert_snapshot!(check_hover("
3079with t as (select 1 a)
3080select a$0 from t;
3081"), @r"
3082 hover: column t.a
3083 ╭▸
3084 3 │ select a from t;
3085 ╰╴ ─ hover
3086 ");
3087 }
3088
3089 #[test]
3090 fn hover_on_cte_with_multiple_columns() {
3091 assert_snapshot!(check_hover("
3092with t as (select 1 a, 2 b)
3093select b$0 from t;
3094"), @r"
3095 hover: column t.b
3096 ╭▸
3097 3 │ select b from t;
3098 ╰╴ ─ hover
3099 ");
3100 }
3101
3102 #[test]
3103 fn hover_on_cte_with_column_list() {
3104 assert_snapshot!(check_hover("
3105with t(a) as (select 1)
3106select a$0 from t;
3107"), @r"
3108 hover: column t.a
3109 ╭▸
3110 3 │ select a from t;
3111 ╰╴ ─ hover
3112 ");
3113 }
3114
3115 #[test]
3116 fn hover_on_nested_cte() {
3117 assert_snapshot!(check_hover("
3118with x as (select 1 a),
3119 y as (select a from x)
3120select a$0 from y;
3121"), @r"
3122 hover: column y.a
3123 ╭▸
3124 4 │ select a from y;
3125 ╰╴ ─ hover
3126 ");
3127 }
3128
3129 #[test]
3130 fn hover_on_cte_shadowing_table_with_star() {
3131 assert_snapshot!(check_hover("
3132create table t(a bigint);
3133with t as (select * from t)
3134select a$0 from t;
3135"), @r"
3136 hover: column public.t.a bigint
3137 ╭▸
3138 4 │ select a from t;
3139 ╰╴ ─ hover
3140 ");
3141 }
3142
3143 #[test]
3144 fn hover_on_cte_definition() {
3145 assert_snapshot!(check_hover("
3146with t$0 as (select 1 a)
3147select a from t;
3148"), @r"
3149 hover: with t as (select 1 a)
3150 ╭▸
3151 2 │ with t as (select 1 a)
3152 ╰╴ ─ hover
3153 ");
3154 }
3155
3156 #[test]
3157 fn hover_on_cte_values_column1() {
3158 assert_snapshot!(check_hover("
3159with t as (
3160 values (1, 2), (3, 4)
3161)
3162select column1$0, column2 from t;
3163"), @r"
3164 hover: column t.column1
3165 ╭▸
3166 5 │ select column1, column2 from t;
3167 ╰╴ ─ hover
3168 ");
3169 }
3170
3171 #[test]
3172 fn hover_on_cte_values_column2() {
3173 assert_snapshot!(check_hover("
3174with t as (
3175 values (1, 2), (3, 4)
3176)
3177select column1, column2$0 from t;
3178"), @r"
3179 hover: column t.column2
3180 ╭▸
3181 5 │ select column1, column2 from t;
3182 ╰╴ ─ hover
3183 ");
3184 }
3185
3186 #[test]
3187 fn hover_on_cte_values_single_column() {
3188 assert_snapshot!(check_hover("
3189with t as (
3190 values (1), (2), (3)
3191)
3192select column1$0 from t;
3193"), @r"
3194 hover: column t.column1
3195 ╭▸
3196 5 │ select column1 from t;
3197 ╰╴ ─ hover
3198 ");
3199 }
3200
3201 #[test]
3202 fn hover_on_cte_values_uppercase_column_names() {
3203 assert_snapshot!(check_hover("
3204with t as (
3205 values (1, 2), (3, 4)
3206)
3207select COLUMN1$0, COLUMN2 from t;
3208"), @r"
3209 hover: column t.column1
3210 ╭▸
3211 5 │ select COLUMN1, COLUMN2 from t;
3212 ╰╴ ─ hover
3213 ");
3214 }
3215
3216 #[test]
3217 fn hover_on_subquery_column() {
3218 assert_snapshot!(check_hover("
3219select a$0 from (select 1 a);
3220"), @r"
3221 hover: column a integer
3222 ╭▸
3223 2 │ select a from (select 1 a);
3224 ╰╴ ─ hover
3225 ");
3226 }
3227
3228 #[test]
3229 fn hover_on_subquery_values_column() {
3230 assert_snapshot!(check_hover("
3231select column1$0 from (values (1, 'foo'));
3232"), @r"
3233 hover: column column1 integer
3234 ╭▸
3235 2 │ select column1 from (values (1, 'foo'));
3236 ╰╴ ─ hover
3237 ");
3238 }
3239
3240 #[test]
3241 fn hover_on_cte_qualified_star() {
3242 assert_snapshot!(check_hover("
3243with u as (select 1 id, 2 b)
3244select u.*$0 from u;
3245"), @r"
3246 hover: column u.id
3247 column u.b
3248 ╭▸
3249 3 │ select u.* from u;
3250 ╰╴ ─ hover
3251 ");
3252 }
3253
3254 #[test]
3255 fn hover_on_cte_values_qualified_star() {
3256 assert_snapshot!(check_hover("
3257with t as (values (1, 2), (3, 4))
3258select t.*$0 from t;
3259"), @r"
3260 hover: column t.column1
3261 column t.column2
3262 ╭▸
3263 3 │ select t.* from t;
3264 ╰╴ ─ hover
3265 ");
3266 }
3267
3268 #[test]
3269 fn hover_on_cte_table_alias_with_column_list() {
3270 assert_snapshot!(check_hover("
3271with t as (select 1 a, 2 b, 3 c)
3272select u$0.x, u.y from t as u(x, y);
3273"), @"
3274 hover: table u(x, y, c)
3275 ╭▸
3276 3 │ select u.x, u.y from t as u(x, y);
3277 ╰╴ ─ hover
3278 ");
3279 }
3280
3281 #[test]
3282 fn hover_on_cte_table_alias_with_column_list_column_ref() {
3283 assert_snapshot!(check_hover("
3284with t as (select 1 a, 2 b, 3 c)
3285select u.x$0 from t as u(x, y);
3286"), @"
3287 hover: column u.x
3288 ╭▸
3289 3 │ select u.x from t as u(x, y);
3290 ╰╴ ─ hover
3291 ");
3292 }
3293
3294 #[test]
3295 fn hover_on_cte_table_alias_with_column_list_table_ref() {
3296 assert_snapshot!(check_hover("
3297with t as (select 1 a, 2 b, 3 c)
3298select u$0 from t as u(x, y);
3299"), @"
3300 hover: table u(x, y, c)
3301 ╭▸
3302 3 │ select u from t as u(x, y);
3303 ╰╴ ─ hover
3304 ");
3305 }
3306
3307 #[test]
3308 fn hover_on_subquery_alias_with_column_list_table_ref() {
3309 assert_snapshot!(check_hover("
3310with t as (select 1 a, 2 b, 3 c)
3311select z$0 from (select * from t) as z(x, y);
3312"), @"
3313 hover: table z(x, y, c)
3314 ╭▸
3315 3 │ select z from (select * from t) as z(x, y);
3316 ╰╴ ─ hover
3317 ");
3318 }
3319
3320 #[test]
3321 fn hover_on_subquery_nested_paren_alias_with_column_list_table_ref() {
3322 assert_snapshot!(check_hover("
3323with t as (select 1 a, 2 b, 3 c)
3324select z$0 from ((select * from t)) as z(x, y);
3325"), @"
3326 hover: table z(x, y, c)
3327 ╭▸
3328 3 │ select z from ((select * from t)) as z(x, y);
3329 ╰╴ ─ hover
3330 ");
3331 }
3332
3333 #[test]
3334 fn hover_on_cte_table_alias_with_partial_column_list_star() {
3335 assert_snapshot!(check_hover("
3336with t as (select 1 a, 2 b, 3 c)
3337select *$0 from t u(x, y);
3338"), @"
3339 hover: column u.x
3340 column u.y
3341 column u.c
3342 ╭▸
3343 3 │ select * from t u(x, y);
3344 ╰╴ ─ hover
3345 ");
3346 }
3347
3348 #[test]
3349 fn hover_on_cte_table_alias_with_partial_column_list_star_from_information_schema() {
3350 assert_snapshot!(check_hover("
3351with t as (select * from information_schema.sql_features)
3352select *$0 from t u(x);
3353"), @"
3354 hover: column u.x
3355 column u.feature_name
3356 column u.sub_feature_id
3357 column u.sub_feature_name
3358 column u.is_supported
3359 column u.is_verified_by
3360 column u.comments
3361 ╭▸
3362 3 │ select * from t u(x);
3363 ╰╴ ─ hover
3364 ");
3365 }
3366
3367 #[test]
3368 fn hover_on_cte_table_alias_with_partial_column_list_qualified_star() {
3369 assert_snapshot!(check_hover("
3370with t as (select 1 a, 2 b, 3 c)
3371select u.*$0 from t u(x, y);
3372"), @"
3373 hover: column u.x
3374 column u.y
3375 column u.c
3376 ╭▸
3377 3 │ select u.* from t u(x, y);
3378 ╰╴ ─ hover
3379 ");
3380 }
3381
3382 #[test]
3383 fn hover_on_star_from_cte_empty_select() {
3384 assert!(
3385 check_hover_(
3386 "
3387with t as (select)
3388select *$0 from t;
3389",
3390 )
3391 .is_none()
3392 );
3393 }
3394
3395 #[test]
3396 fn hover_on_star_with_subquery_from_cte() {
3397 assert_snapshot!(check_hover("
3398with u as (select 1 id, 2 b)
3399select *$0 from (select *, *, * from u);
3400"), @r"
3401 hover: column u.id
3402 column u.b
3403 column u.id
3404 column u.b
3405 column u.id
3406 column u.b
3407 ╭▸
3408 3 │ select * from (select *, *, * from u);
3409 ╰╴ ─ hover
3410 ");
3411 }
3412
3413 #[test]
3414 fn hover_on_star_with_subquery_from_table() {
3415 assert_snapshot!(check_hover("
3416create table t(a int, b int);
3417select *$0 from (select a from t);
3418"), @r"
3419 hover: column public.t.a int
3420 ╭▸
3421 3 │ select * from (select a from t);
3422 ╰╴ ─ hover
3423 ");
3424 }
3425
3426 #[test]
3427 fn hover_on_star_with_subquery_from_table_statement() {
3428 assert_snapshot!(check_hover("
3429with t as (select 1 a, 2 b)
3430select *$0 from (table t);
3431"), @r"
3432 hover: column a
3433 column b
3434 ╭▸
3435 3 │ select * from (table t);
3436 ╰╴ ─ hover
3437 ");
3438 }
3439
3440 #[test]
3441 fn hover_on_star_from_information_schema_table() {
3442 assert_snapshot!(check_hover("
3443select *$0 from information_schema.sql_features;
3444"), @"
3445 hover: column information_schema.sql_features.feature_id information_schema.character_data
3446 column information_schema.sql_features.feature_name information_schema.character_data
3447 column information_schema.sql_features.sub_feature_id information_schema.character_data
3448 column information_schema.sql_features.sub_feature_name information_schema.character_data
3449 column information_schema.sql_features.is_supported information_schema.yes_or_no
3450 column information_schema.sql_features.is_verified_by information_schema.character_data
3451 column information_schema.sql_features.comments information_schema.character_data
3452 ╭▸
3453 2 │ select * from information_schema.sql_features;
3454 ╰╴ ─ hover
3455 ");
3456 }
3457
3458 #[test]
3459 fn hover_on_star_with_subquery_literal() {
3460 assert_snapshot!(check_hover("
3461select *$0 from (select 1);
3462"), @r"
3463 hover: column ?column?
3464 ╭▸
3465 2 │ select * from (select 1);
3466 ╰╴ ─ hover
3467 ");
3468 }
3469
3470 #[test]
3471 fn hover_on_star_with_subquery_literal_with_alias() {
3472 assert_snapshot!(check_hover("
3473select *$0 from (select 1) as sub;
3474"), @r"
3475 hover: column sub.?column?
3476 ╭▸
3477 2 │ select * from (select 1) as sub;
3478 ╰╴ ─ hover
3479 ");
3480 }
3481
3482 #[test]
3483 fn hover_on_view_qualified_star() {
3484 assert_snapshot!(check_hover("
3485create view v as select 1 id, 2 b;
3486select v.*$0 from v;
3487"), @r"
3488 hover: column public.v.id
3489 column public.v.b
3490 ╭▸
3491 3 │ select v.* from v;
3492 ╰╴ ─ hover
3493 ");
3494 }
3495
3496 #[test]
3497 fn hover_on_drop_procedure() {
3498 assert_snapshot!(check_hover("
3499create procedure foo() language sql as $$ select 1 $$;
3500drop procedure foo$0();
3501"), @r"
3502 hover: procedure public.foo()
3503 ╭▸
3504 3 │ drop procedure foo();
3505 ╰╴ ─ hover
3506 ");
3507 }
3508
3509 #[test]
3510 fn hover_on_drop_procedure_with_schema() {
3511 assert_snapshot!(check_hover("
3512create procedure myschema.foo() language sql as $$ select 1 $$;
3513drop procedure myschema.foo$0();
3514"), @r"
3515 hover: procedure myschema.foo()
3516 ╭▸
3517 3 │ drop procedure myschema.foo();
3518 ╰╴ ─ hover
3519 ");
3520 }
3521
3522 #[test]
3523 fn hover_on_create_procedure_definition() {
3524 assert_snapshot!(check_hover("
3525create procedure foo$0() language sql as $$ select 1 $$;
3526"), @r"
3527 hover: procedure public.foo()
3528 ╭▸
3529 2 │ create procedure foo() language sql as $$ select 1 $$;
3530 ╰╴ ─ hover
3531 ");
3532 }
3533
3534 #[test]
3535 fn hover_on_create_procedure_with_explicit_schema() {
3536 assert_snapshot!(check_hover("
3537create procedure myschema.foo$0() language sql as $$ select 1 $$;
3538"), @r"
3539 hover: procedure myschema.foo()
3540 ╭▸
3541 2 │ create procedure myschema.foo() language sql as $$ select 1 $$;
3542 ╰╴ ─ hover
3543 ");
3544 }
3545
3546 #[test]
3547 fn hover_on_drop_procedure_with_search_path() {
3548 assert_snapshot!(check_hover(r#"
3549set search_path to myschema;
3550create procedure foo() language sql as $$ select 1 $$;
3551drop procedure foo$0();
3552"#), @r"
3553 hover: procedure myschema.foo()
3554 ╭▸
3555 4 │ drop procedure foo();
3556 ╰╴ ─ hover
3557 ");
3558 }
3559
3560 #[test]
3561 fn hover_on_drop_procedure_overloaded() {
3562 assert_snapshot!(check_hover("
3563create procedure add(complex) language sql as $$ select null $$;
3564create procedure add(bigint) language sql as $$ select 1 $$;
3565drop procedure add$0(complex);
3566"), @r"
3567 hover: procedure public.add(complex)
3568 ╭▸
3569 4 │ drop procedure add(complex);
3570 ╰╴ ─ hover
3571 ");
3572 }
3573
3574 #[test]
3575 fn hover_on_drop_procedure_second_overload() {
3576 assert_snapshot!(check_hover("
3577create procedure add(complex) language sql as $$ select null $$;
3578create procedure add(bigint) language sql as $$ select 1 $$;
3579drop procedure add$0(bigint);
3580"), @r"
3581 hover: procedure public.add(bigint)
3582 ╭▸
3583 4 │ drop procedure add(bigint);
3584 ╰╴ ─ hover
3585 ");
3586 }
3587
3588 #[test]
3589 fn hover_on_call_procedure() {
3590 assert_snapshot!(check_hover("
3591create procedure foo() language sql as $$ select 1 $$;
3592call foo$0();
3593"), @r"
3594 hover: procedure public.foo()
3595 ╭▸
3596 3 │ call foo();
3597 ╰╴ ─ hover
3598 ");
3599 }
3600
3601 #[test]
3602 fn hover_on_call_procedure_with_schema() {
3603 assert_snapshot!(check_hover("
3604create procedure public.foo() language sql as $$ select 1 $$;
3605call public.foo$0();
3606"), @r"
3607 hover: procedure public.foo()
3608 ╭▸
3609 3 │ call public.foo();
3610 ╰╴ ─ hover
3611 ");
3612 }
3613
3614 #[test]
3615 fn hover_on_call_procedure_with_search_path() {
3616 assert_snapshot!(check_hover(r#"
3617set search_path to myschema;
3618create procedure foo() language sql as $$ select 1 $$;
3619call foo$0();
3620"#), @r"
3621 hover: procedure myschema.foo()
3622 ╭▸
3623 4 │ call foo();
3624 ╰╴ ─ hover
3625 ");
3626 }
3627
3628 #[test]
3629 fn hover_on_call_procedure_with_params() {
3630 assert_snapshot!(check_hover("
3631create procedure add(a int, b int) language sql as $$ select a + b $$;
3632call add$0(1, 2);
3633"), @r"
3634 hover: procedure public.add(a int, b int)
3635 ╭▸
3636 3 │ call add(1, 2);
3637 ╰╴ ─ hover
3638 ");
3639 }
3640
3641 #[test]
3642 fn hover_on_drop_routine_function() {
3643 assert_snapshot!(check_hover("
3644create function foo() returns int as $$ select 1 $$ language sql;
3645drop routine foo$0();
3646"), @r"
3647 hover: function public.foo() returns int
3648 ╭▸
3649 3 │ drop routine foo();
3650 ╰╴ ─ hover
3651 ");
3652 }
3653
3654 #[test]
3655 fn hover_on_drop_routine_aggregate() {
3656 assert_snapshot!(check_hover("
3657create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
3658drop routine myavg$0(int);
3659"), @r"
3660 hover: aggregate public.myavg(int)
3661 ╭▸
3662 3 │ drop routine myavg(int);
3663 ╰╴ ─ hover
3664 ");
3665 }
3666
3667 #[test]
3668 fn hover_on_drop_routine_procedure() {
3669 assert_snapshot!(check_hover("
3670create procedure foo() language sql as $$ select 1 $$;
3671drop routine foo$0();
3672"), @r"
3673 hover: procedure public.foo()
3674 ╭▸
3675 3 │ drop routine foo();
3676 ╰╴ ─ hover
3677 ");
3678 }
3679
3680 #[test]
3681 fn hover_on_drop_routine_with_schema() {
3682 assert_snapshot!(check_hover("
3683set search_path to public;
3684create function foo() returns int as $$ select 1 $$ language sql;
3685drop routine public.foo$0();
3686"), @r"
3687 hover: function public.foo() returns int
3688 ╭▸
3689 4 │ drop routine public.foo();
3690 ╰╴ ─ hover
3691 ");
3692 }
3693
3694 #[test]
3695 fn hover_on_drop_routine_with_search_path() {
3696 assert_snapshot!(check_hover(r#"
3697set search_path to myschema;
3698create function foo() returns int as $$ select 1 $$ language sql;
3699drop routine foo$0();
3700"#), @r"
3701 hover: function myschema.foo() returns int
3702 ╭▸
3703 4 │ drop routine foo();
3704 ╰╴ ─ hover
3705 ");
3706 }
3707
3708 #[test]
3709 fn hover_on_drop_routine_overloaded() {
3710 assert_snapshot!(check_hover("
3711create function add(complex) returns complex as $$ select null $$ language sql;
3712create function add(bigint) returns bigint as $$ select 1 $$ language sql;
3713drop routine add$0(complex);
3714"), @r"
3715 hover: function public.add(complex) returns complex
3716 ╭▸
3717 4 │ drop routine add(complex);
3718 ╰╴ ─ hover
3719 ");
3720 }
3721
3722 #[test]
3723 fn hover_on_drop_routine_prefers_function_over_procedure() {
3724 assert_snapshot!(check_hover("
3725create function foo() returns int as $$ select 1 $$ language sql;
3726create procedure foo() language sql as $$ select 1 $$;
3727drop routine foo$0();
3728"), @r"
3729 hover: function public.foo() returns int
3730 ╭▸
3731 4 │ drop routine foo();
3732 ╰╴ ─ hover
3733 ");
3734 }
3735
3736 #[test]
3737 fn hover_on_drop_routine_prefers_aggregate_over_procedure() {
3738 assert_snapshot!(check_hover("
3739create aggregate foo(int) (sfunc = int4_avg_accum, stype = _int8);
3740create procedure foo(int) language sql as $$ select 1 $$;
3741drop routine foo$0(int);
3742"), @r"
3743 hover: aggregate public.foo(int)
3744 ╭▸
3745 4 │ drop routine foo(int);
3746 ╰╴ ─ hover
3747 ");
3748 }
3749
3750 #[test]
3751 fn hover_on_update_table() {
3752 assert_snapshot!(check_hover("
3753create table users(id int, email text);
3754update users$0 set email = 'new@example.com';
3755"), @r"
3756 hover: table public.users(id int, email text)
3757 ╭▸
3758 3 │ update users set email = 'new@example.com';
3759 ╰╴ ─ hover
3760 ");
3761 }
3762
3763 #[test]
3764 fn hover_on_update_table_with_schema() {
3765 assert_snapshot!(check_hover("
3766create table public.users(id int, email text);
3767update public.users$0 set email = 'new@example.com';
3768"), @r"
3769 hover: table public.users(id int, email text)
3770 ╭▸
3771 3 │ update public.users set email = 'new@example.com';
3772 ╰╴ ─ hover
3773 ");
3774 }
3775
3776 #[test]
3777 fn hover_on_update_set_column() {
3778 assert_snapshot!(check_hover("
3779create table users(id int, email text);
3780update users set email$0 = 'new@example.com' where id = 1;
3781"), @r"
3782 hover: column public.users.email text
3783 ╭▸
3784 3 │ update users set email = 'new@example.com' where id = 1;
3785 ╰╴ ─ hover
3786 ");
3787 }
3788
3789 #[test]
3790 fn hover_on_update_set_column_with_schema() {
3791 assert_snapshot!(check_hover("
3792create table public.users(id int, email text);
3793update public.users set email$0 = 'new@example.com' where id = 1;
3794"), @r"
3795 hover: column public.users.email text
3796 ╭▸
3797 3 │ update public.users set email = 'new@example.com' where id = 1;
3798 ╰╴ ─ hover
3799 ");
3800 }
3801
3802 #[test]
3803 fn hover_on_update_where_column() {
3804 assert_snapshot!(check_hover("
3805create table users(id int, email text);
3806update users set email = 'new@example.com' where id$0 = 1;
3807"), @r"
3808 hover: column public.users.id int
3809 ╭▸
3810 3 │ update users set email = 'new@example.com' where id = 1;
3811 ╰╴ ─ hover
3812 ");
3813 }
3814
3815 #[test]
3816 fn hover_on_update_where_column_with_schema() {
3817 assert_snapshot!(check_hover("
3818create table public.users(id int, email text);
3819update public.users set email = 'new@example.com' where id$0 = 1;
3820"), @r"
3821 hover: column public.users.id int
3822 ╭▸
3823 3 │ update public.users set email = 'new@example.com' where id = 1;
3824 ╰╴ ─ hover
3825 ");
3826 }
3827
3828 #[test]
3829 fn hover_on_update_from_table() {
3830 assert_snapshot!(check_hover("
3831create table users(id int, email text);
3832create table messages(id int, user_id int, email text);
3833update users set email = messages.email from messages$0 where users.id = messages.user_id;
3834"), @r"
3835 hover: table public.messages(id int, user_id int, email text)
3836 ╭▸
3837 4 │ update users set email = messages.email from messages where users.id = messages.user_id;
3838 ╰╴ ─ hover
3839 ");
3840 }
3841
3842 #[test]
3843 fn hover_on_update_from_table_with_schema() {
3844 assert_snapshot!(check_hover("
3845create table users(id int, email text);
3846create table public.messages(id int, user_id int, email text);
3847update users set email = messages.email from public.messages$0 where users.id = messages.user_id;
3848"), @r"
3849 hover: table public.messages(id int, user_id int, email text)
3850 ╭▸
3851 4 │ update users set email = messages.email from public.messages where users.id = messages.user_id;
3852 ╰╴ ─ hover
3853 ");
3854 }
3855
3856 #[test]
3857 fn hover_on_update_with_cte_table() {
3858 assert_snapshot!(check_hover("
3859create table users(id int, email text);
3860with new_data as (
3861 select 1 as id, 'new@example.com' as email
3862)
3863update users set email = new_data.email from new_data$0 where users.id = new_data.id;
3864"), @r"
3865 hover: with new_data as (select 1 as id, 'new@example.com' as email)
3866 ╭▸
3867 6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
3868 ╰╴ ─ hover
3869 ");
3870 }
3871
3872 #[test]
3873 fn hover_on_update_with_cte_column_in_set() {
3874 assert_snapshot!(check_hover("
3875create table users(id int, email text);
3876with new_data as (
3877 select 1 as id, 'new@example.com' as email
3878)
3879update users set email = new_data.email$0 from new_data where users.id = new_data.id;
3880"), @r"
3881 hover: column new_data.email
3882 ╭▸
3883 6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
3884 ╰╴ ─ hover
3885 ");
3886 }
3887
3888 #[test]
3889 fn hover_on_update_with_cte_column_in_where() {
3890 assert_snapshot!(check_hover("
3891create table users(id int, email text);
3892with new_data as (
3893 select 1 as id, 'new@example.com' as email
3894)
3895update users set email = new_data.email from new_data where new_data.id$0 = users.id;
3896"), @r"
3897 hover: column new_data.id
3898 ╭▸
3899 6 │ update users set email = new_data.email from new_data where new_data.id = users.id;
3900 ╰╴ ─ hover
3901 ");
3902 }
3903
3904 #[test]
3905 fn hover_on_create_view_definition() {
3906 assert_snapshot!(check_hover("
3907create view v$0 as select 1;
3908"), @r"
3909 hover: view public.v as select 1
3910 ╭▸
3911 2 │ create view v as select 1;
3912 ╰╴ ─ hover
3913 ");
3914 }
3915
3916 #[test]
3917 fn hover_on_create_view_definition_with_schema() {
3918 assert_snapshot!(check_hover("
3919create view myschema.v$0 as select 1;
3920"), @r"
3921 hover: view myschema.v as select 1
3922 ╭▸
3923 2 │ create view myschema.v as select 1;
3924 ╰╴ ─ hover
3925 ");
3926 }
3927
3928 #[test]
3929 fn hover_on_create_temp_view_definition() {
3930 assert_snapshot!(check_hover("
3931create temp view v$0 as select 1;
3932"), @r"
3933 hover: view pg_temp.v as select 1
3934 ╭▸
3935 2 │ create temp view v as select 1;
3936 ╰╴ ─ hover
3937 ");
3938 }
3939
3940 #[test]
3941 fn hover_on_create_view_with_column_list() {
3942 assert_snapshot!(check_hover("
3943create view v(col1$0) as select 1;
3944"), @r"
3945 hover: column public.v.col1
3946 ╭▸
3947 2 │ create view v(col1) as select 1;
3948 ╰╴ ─ hover
3949 ");
3950 }
3951
3952 #[test]
3953 fn hover_on_select_from_view() {
3954 assert_snapshot!(check_hover("
3955create view v as select 1;
3956select * from v$0;
3957"), @r"
3958 hover: view public.v as select 1
3959 ╭▸
3960 3 │ select * from v;
3961 ╰╴ ─ hover
3962 ");
3963 }
3964
3965 #[test]
3966 fn hover_on_select_column_from_view_column_list() {
3967 assert_snapshot!(check_hover("
3968create view v(a) as select 1;
3969select a$0 from v;
3970"), @r"
3971 hover: column public.v.a
3972 ╭▸
3973 3 │ select a from v;
3974 ╰╴ ─ hover
3975 ");
3976 }
3977
3978 #[test]
3979 fn hover_on_select_column_from_view_column_list_overrides_target() {
3980 assert_snapshot!(check_hover("
3981create view v(a) as select 1, 2 b;
3982select a, b$0 from v;
3983"), @r"
3984 hover: column public.v.b
3985 ╭▸
3986 3 │ select a, b from v;
3987 ╰╴ ─ hover
3988 ");
3989 }
3990
3991 #[test]
3992 fn hover_on_select_column_from_view_target_list() {
3993 assert_snapshot!(check_hover("
3994create view v as select 1 a, 2 b;
3995select a$0, b from v;
3996"), @r"
3997 hover: column public.v.a
3998 ╭▸
3999 3 │ select a, b from v;
4000 ╰╴ ─ hover
4001 ");
4002 }
4003
4004 #[test]
4005 fn hover_on_select_column_from_create_table_as() {
4006 assert_snapshot!(check_hover("
4007create table t as select 1 a;
4008select a$0 from t;
4009"), @r"
4010 hover: column public.t.a
4011 ╭▸
4012 3 │ select a from t;
4013 ╰╴ ─ hover
4014 ");
4015 }
4016
4017 #[test]
4018 fn hover_on_select_from_view_with_schema() {
4019 assert_snapshot!(check_hover("
4020create view myschema.v as select 1;
4021select * from myschema.v$0;
4022"), @r"
4023 hover: view myschema.v as select 1
4024 ╭▸
4025 3 │ select * from myschema.v;
4026 ╰╴ ─ hover
4027 ");
4028 }
4029
4030 #[test]
4031 fn hover_on_drop_view() {
4032 assert_snapshot!(check_hover("
4033create view v as select 1;
4034drop view v$0;
4035"), @r"
4036 hover: view public.v as select 1
4037 ╭▸
4038 3 │ drop view v;
4039 ╰╴ ─ hover
4040 ");
4041 }
4042
4043 #[test]
4044 fn hover_composite_type_field() {
4045 assert_snapshot!(check_hover("
4046create type person_info as (name varchar(50), age int);
4047with team as (
4048 select 1 as id, ('Alice', 30)::person_info as member
4049)
4050select (member).name$0, (member).age from team;
4051"), @r"
4052 hover: field public.person_info.name varchar(50)
4053 ╭▸
4054 6 │ select (member).name, (member).age from team;
4055 ╰╴ ─ hover
4056 ");
4057 }
4058
4059 #[test]
4060 fn hover_composite_type_field_age() {
4061 assert_snapshot!(check_hover("
4062create type person_info as (name varchar(50), age int);
4063with team as (
4064 select 1 as id, ('Alice', 30)::person_info as member
4065)
4066select (member).name, (member).age$0 from team;
4067"), @r"
4068 hover: field public.person_info.age int
4069 ╭▸
4070 6 │ select (member).name, (member).age from team;
4071 ╰╴ ─ hover
4072 ");
4073 }
4074
4075 #[test]
4076 fn hover_composite_type_field_nested_parens() {
4077 assert_snapshot!(check_hover("
4078create type person_info as (name varchar(50), age int);
4079with team as (
4080 select 1 as id, ('Alice', 30)::person_info as member
4081)
4082select ((((member))).name$0) from team;
4083"), @r"
4084 hover: field public.person_info.name varchar(50)
4085 ╭▸
4086 6 │ select ((((member))).name) from team;
4087 ╰╴ ─ hover
4088 ");
4089 }
4090
4091 #[test]
4092 fn hover_on_join_using_column() {
4093 assert_snapshot!(check_hover("
4094create table t(id int);
4095create table u(id int);
4096select * from t join u using (id$0);
4097"), @r"
4098 hover: column public.t.id int
4099 column public.u.id int
4100 ╭▸
4101 4 │ select * from t join u using (id);
4102 ╰╴ ─ hover
4103 ");
4104 }
4105
4106 #[test]
4107 fn hover_on_truncate_table() {
4108 assert_snapshot!(check_hover("
4109create table users(id int, email text);
4110truncate table users$0;
4111"), @r"
4112 hover: table public.users(id int, email text)
4113 ╭▸
4114 3 │ truncate table users;
4115 ╰╴ ─ hover
4116 ");
4117 }
4118
4119 #[test]
4120 fn hover_on_truncate_table_without_table_keyword() {
4121 assert_snapshot!(check_hover("
4122create table users(id int, email text);
4123truncate users$0;
4124"), @r"
4125 hover: table public.users(id int, email text)
4126 ╭▸
4127 3 │ truncate users;
4128 ╰╴ ─ hover
4129 ");
4130 }
4131
4132 #[test]
4133 fn hover_on_lock_table() {
4134 assert_snapshot!(check_hover("
4135create table users(id int, email text);
4136lock table users$0;
4137"), @r"
4138 hover: table public.users(id int, email text)
4139 ╭▸
4140 3 │ lock table users;
4141 ╰╴ ─ hover
4142 ");
4143 }
4144
4145 #[test]
4146 fn hover_on_lock_table_without_table_keyword() {
4147 assert_snapshot!(check_hover("
4148create table users(id int, email text);
4149lock users$0;
4150"), @r"
4151 hover: table public.users(id int, email text)
4152 ╭▸
4153 3 │ lock users;
4154 ╰╴ ─ hover
4155 ");
4156 }
4157
4158 #[test]
4159 fn hover_on_vacuum_table() {
4160 assert_snapshot!(check_hover("
4161create table users(id int, email text);
4162vacuum users$0;
4163"), @r"
4164 hover: table public.users(id int, email text)
4165 ╭▸
4166 3 │ vacuum users;
4167 ╰╴ ─ hover
4168 ");
4169 }
4170
4171 #[test]
4172 fn hover_on_vacuum_with_analyze() {
4173 assert_snapshot!(check_hover("
4174create table users(id int, email text);
4175vacuum analyze users$0;
4176"), @r"
4177 hover: table public.users(id int, email text)
4178 ╭▸
4179 3 │ vacuum analyze users;
4180 ╰╴ ─ hover
4181 ");
4182 }
4183
4184 #[test]
4185 fn hover_on_alter_table() {
4186 assert_snapshot!(check_hover("
4187create table users(id int, email text);
4188alter table users$0 alter email set not null;
4189"), @r"
4190 hover: table public.users(id int, email text)
4191 ╭▸
4192 3 │ alter table users alter email set not null;
4193 ╰╴ ─ hover
4194 ");
4195 }
4196
4197 #[test]
4198 fn hover_on_alter_table_column() {
4199 assert_snapshot!(check_hover("
4200create table users(id int, email text);
4201alter table users alter email$0 set not null;
4202"), @r"
4203 hover: column public.users.email text
4204 ╭▸
4205 3 │ alter table users alter email set not null;
4206 ╰╴ ─ hover
4207 ");
4208 }
4209
4210 #[test]
4211 fn hover_on_refresh_materialized_view() {
4212 assert_snapshot!(check_hover("
4213create materialized view mv as select 1;
4214refresh materialized view mv$0;
4215"), @r"
4216 hover: materialized view public.mv as select 1
4217 ╭▸
4218 3 │ refresh materialized view mv;
4219 ╰╴ ─ hover
4220 ");
4221 }
4222
4223 #[test]
4224 fn hover_on_reindex_table() {
4225 assert_snapshot!(check_hover("
4226create table users(id int);
4227reindex table users$0;
4228"), @r"
4229 hover: table public.users(id int)
4230 ╭▸
4231 3 │ reindex table users;
4232 ╰╴ ─ hover
4233 ");
4234 }
4235
4236 #[test]
4237 fn hover_on_reindex_index() {
4238 assert_snapshot!(check_hover("
4239create table t(c int);
4240create index idx on t(c);
4241reindex index idx$0;
4242"), @r"
4243 hover: index public.idx on public.t(c)
4244 ╭▸
4245 4 │ reindex index idx;
4246 ╰╴ ─ hover
4247 ");
4248 }
4249
4250 #[test]
4251 fn hover_merge_returning_star_from_cte() {
4252 assert_snapshot!(check_hover("
4253create table t(a int, b int);
4254with u(x, y) as (
4255 select 1, 2
4256),
4257merged as (
4258 merge into t
4259 using u
4260 on t.a = u.x
4261 when matched then
4262 do nothing
4263 when not matched then
4264 do nothing
4265 returning a as x, b as y
4266)
4267select *$0 from merged;
4268"), @r"
4269 hover: column merged.x
4270 column merged.y
4271 ╭▸
4272 16 │ select * from merged;
4273 ╰╴ ─ hover
4274 ");
4275 }
4276
4277 #[test]
4278 fn hover_update_returning_star() {
4279 assert_snapshot!(check_hover("
4280create table t(a int, b int);
4281update t set a = 1
4282returning *$0;
4283"), @r"
4284 hover: column public.t.a int
4285 column public.t.b int
4286 ╭▸
4287 4 │ returning *;
4288 ╰╴ ─ hover
4289 ");
4290 }
4291
4292 #[test]
4293 fn hover_insert_returning_star() {
4294 assert_snapshot!(check_hover("
4295create table t(a int, b int);
4296insert into t values (1, 2)
4297returning *$0;
4298"), @r"
4299 hover: column public.t.a int
4300 column public.t.b int
4301 ╭▸
4302 4 │ returning *;
4303 ╰╴ ─ hover
4304 ");
4305 }
4306
4307 #[test]
4308 fn hover_delete_returning_star() {
4309 assert_snapshot!(check_hover("
4310create table t(a int, b int);
4311delete from t
4312returning *$0;
4313"), @r"
4314 hover: column public.t.a int
4315 column public.t.b int
4316 ╭▸
4317 4 │ returning *;
4318 ╰╴ ─ hover
4319 ");
4320 }
4321
4322 #[test]
4323 fn hover_merge_returning_star() {
4324 assert_snapshot!(check_hover("
4325create table t(a int, b int);
4326merge into t
4327 using (select 1 as x, 2 as y) u
4328 on t.a = u.x
4329 when matched then
4330 do nothing
4331returning *$0;
4332"), @r"
4333 hover: column public.t.a int
4334 column public.t.b int
4335 ╭▸
4336 8 │ returning *;
4337 ╰╴ ─ hover
4338 ");
4339 }
4340
4341 #[test]
4342 fn hover_merge_returning_qualified_star_old() {
4343 assert_snapshot!(check_hover("
4344create table t(a int, b int);
4345merge into t
4346 using (select 1 as x, 2 as y) u
4347 on t.a = u.x
4348 when matched then
4349 update set a = 99
4350returning old$0.*;
4351"), @r"
4352 hover: table public.t(a int, b int)
4353 ╭▸
4354 8 │ returning old.*;
4355 ╰╴ ─ hover
4356 ");
4357 }
4358
4359 #[test]
4360 fn hover_merge_returning_qualified_star_new() {
4361 assert_snapshot!(check_hover("
4362create table t(a int, b int);
4363merge into t
4364 using (select 1 as x, 2 as y) u
4365 on t.a = u.x
4366 when matched then
4367 update set a = 99
4368returning new$0.*;
4369"), @r"
4370 hover: table public.t(a int, b int)
4371 ╭▸
4372 8 │ returning new.*;
4373 ╰╴ ─ hover
4374 ");
4375 }
4376
4377 #[test]
4378 fn hover_merge_returning_qualified_star_table() {
4379 assert_snapshot!(check_hover("
4380create table t(a int, b int);
4381merge into t
4382 using (select 1 as x, 2 as y) u
4383 on t.a = u.x
4384 when matched then
4385 update set a = 99
4386returning t$0.*;
4387"), @r"
4388 hover: table public.t(a int, b int)
4389 ╭▸
4390 8 │ returning t.*;
4391 ╰╴ ─ hover
4392 ");
4393 }
4394
4395 #[test]
4396 fn hover_merge_returning_qualified_star_old_on_star() {
4397 assert_snapshot!(check_hover("
4398create table t(a int, b int);
4399merge into t
4400 using (select 1 as x, 2 as y) u
4401 on t.a = u.x
4402 when matched then
4403 update set a = 99
4404returning old.*$0;
4405"), @r"
4406 hover: column public.t.a int
4407 column public.t.b int
4408 ╭▸
4409 8 │ returning old.*;
4410 ╰╴ ─ hover
4411 ");
4412 }
4413
4414 #[test]
4415 fn hover_merge_returning_qualified_star_new_on_star() {
4416 assert_snapshot!(check_hover("
4417create table t(a int, b int);
4418merge into t
4419 using (select 1 as x, 2 as y) u
4420 on t.a = u.x
4421 when matched then
4422 update set a = 99
4423returning new.*$0;
4424"), @r"
4425 hover: column public.t.a int
4426 column public.t.b int
4427 ╭▸
4428 8 │ returning new.*;
4429 ╰╴ ─ hover
4430 ");
4431 }
4432
4433 #[test]
4434 fn hover_merge_returning_qualified_star_table_on_star() {
4435 assert_snapshot!(check_hover("
4436create table t(a int, b int);
4437merge into t
4438 using (select 1 as x, 2 as y) u
4439 on t.a = u.x
4440 when matched then
4441 update set a = 99
4442returning t.*$0;
4443"), @r"
4444 hover: column public.t.a int
4445 column public.t.b int
4446 ╭▸
4447 8 │ returning t.*;
4448 ╰╴ ─ hover
4449 ");
4450 }
4451
4452 #[test]
4453 fn hover_partition_table_column() {
4454 assert_snapshot!(check_hover("
4455create table part (
4456 a int,
4457 inserted_at timestamptz not null default now()
4458) partition by range (inserted_at);
4459create table part_2026_01_02 partition of part
4460 for values from ('2026-01-02') to ('2026-01-03');
4461select a$0 from part_2026_01_02;
4462"), @r"
4463 hover: column public.part.a int
4464 ╭▸
4465 8 │ select a from part_2026_01_02;
4466 ╰╴ ─ hover
4467 ");
4468 }
4469
4470 #[test]
4471 fn hover_create_table_like_multi_star() {
4472 assert_snapshot!(check_hover("
4473create table t(a int, b int);
4474create table u(x int, y int);
4475create table k(like t, like u, c int);
4476select *$0 from k;
4477"), @r"
4478 hover: column public.k.a int
4479 column public.k.b int
4480 column public.k.x int
4481 column public.k.y int
4482 column public.k.c int
4483 ╭▸
4484 5 │ select * from k;
4485 ╰╴ ─ hover
4486 ");
4487 }
4488
4489 #[test]
4490 fn hover_create_table_inherits_star() {
4491 assert_snapshot!(check_hover("
4492create table t (
4493 a int, b text
4494);
4495create table u (
4496 c int
4497) inherits (t);
4498select *$0 from u;
4499"), @r"
4500 hover: column public.u.a int
4501 column public.u.b text
4502 column public.u.c int
4503 ╭▸
4504 8 │ select * from u;
4505 ╰╴ ─ hover
4506 ");
4507 }
4508
4509 #[test]
4510 fn hover_create_table_inherits_column() {
4511 assert_snapshot!(check_hover("
4512create table t (
4513 a int, b text
4514);
4515create table u (
4516 c int
4517) inherits (t);
4518select a$0 from u;
4519"), @r"
4520 hover: column public.t.a int
4521 ╭▸
4522 8 │ select a from u;
4523 ╰╴ ─ hover
4524 ");
4525 }
4526
4527 #[test]
4528 fn hover_create_table_inherits_local_column() {
4529 assert_snapshot!(check_hover("
4530create table t (
4531 a int, b text
4532);
4533create table u (
4534 c int
4535) inherits (t);
4536select c$0 from u;
4537"), @r"
4538 hover: column public.u.c int
4539 ╭▸
4540 8 │ select c from u;
4541 ╰╴ ─ hover
4542 ");
4543 }
4544
4545 #[test]
4546 fn hover_create_table_inherits_multiple_parents() {
4547 assert_snapshot!(check_hover("
4548create table t1 (
4549 a int
4550);
4551create table t2 (
4552 b text
4553);
4554create table u (
4555 c int
4556) inherits (t1, t2);
4557select b$0 from u;
4558"), @r"
4559 hover: column public.t2.b text
4560 ╭▸
4561 11 │ select b from u;
4562 ╰╴ ─ hover
4563 ");
4564 }
4565
4566 #[test]
4567 fn hover_create_foreign_table_inherits_column() {
4568 assert_snapshot!(check_hover("
4569create server myserver foreign data wrapper postgres_fdw;
4570create table t (
4571 a int, b text
4572);
4573create foreign table u (
4574 c int
4575) inherits (t) server myserver;
4576select a$0 from u;
4577"), @r"
4578 hover: column public.t.a int
4579 ╭▸
4580 9 │ select a from u;
4581 ╰╴ ─ hover
4582 ");
4583 }
4584
4585 #[test]
4586 fn hover_extension_on_create() {
4587 assert_snapshot!(check_hover("
4588create extension my$0ext;
4589"), @r"
4590 hover: extension myext
4591 ╭▸
4592 2 │ create extension myext;
4593 ╰╴ ─ hover
4594 ");
4595 }
4596
4597 #[test]
4598 fn hover_extension_on_drop() {
4599 assert_snapshot!(check_hover("
4600create extension myext;
4601drop extension my$0ext;
4602"), @r"
4603 hover: extension myext
4604 ╭▸
4605 3 │ drop extension myext;
4606 ╰╴ ─ hover
4607 ");
4608 }
4609
4610 #[test]
4611 fn hover_extension_on_alter() {
4612 assert_snapshot!(check_hover("
4613create extension myext;
4614alter extension my$0ext update to '2.0';
4615"), @r"
4616 hover: extension myext
4617 ╭▸
4618 3 │ alter extension myext update to '2.0';
4619 ╰╴ ─ hover
4620 ");
4621 }
4622
4623 #[test]
4624 fn hover_role_on_create() {
4625 assert_snapshot!(check_hover("
4626create role read$0er;
4627"), @r"
4628 hover: role reader
4629 ╭▸
4630 2 │ create role reader;
4631 ╰╴ ─ hover
4632 ");
4633 }
4634
4635 #[test]
4636 fn hover_role_on_alter() {
4637 assert_snapshot!(check_hover("
4638create role reader;
4639alter role read$0er rename to writer;
4640"), @r"
4641 hover: role reader
4642 ╭▸
4643 3 │ alter role reader rename to writer;
4644 ╰╴ ─ hover
4645 ");
4646 }
4647
4648 #[test]
4649 fn hover_role_on_drop() {
4650 assert_snapshot!(check_hover("
4651create role reader;
4652drop role read$0er;
4653"), @r"
4654 hover: role reader
4655 ╭▸
4656 3 │ drop role reader;
4657 ╰╴ ─ hover
4658 ");
4659 }
4660
4661 #[test]
4662 fn hover_role_on_set() {
4663 assert_snapshot!(check_hover("
4664create role reader;
4665set role read$0er;
4666"), @r"
4667 hover: role reader
4668 ╭▸
4669 3 │ set role reader;
4670 ╰╴ ─ hover
4671 ");
4672 }
4673
4674 #[test]
4675 fn hover_role_on_create_tablespace_owner() {
4676 assert_snapshot!(check_hover("
4677create role reader;
4678create tablespace t owner read$0er location 'foo';
4679"), @r"
4680 hover: role reader
4681 ╭▸
4682 3 │ create tablespace t owner reader location 'foo';
4683 ╰╴ ─ hover
4684 ");
4685 }
4686
4687 #[test]
4688 fn hover_on_fetch_cursor() {
4689 assert_snapshot!(check_hover("
4690declare c scroll cursor for select * from t;
4691fetch forward 5 from c$0;
4692"), @r"
4693 hover: cursor c for select * from t
4694 ╭▸
4695 3 │ fetch forward 5 from c;
4696 ╰╴ ─ hover
4697 ");
4698 }
4699
4700 #[test]
4701 fn hover_on_close_cursor() {
4702 assert_snapshot!(check_hover("
4703declare c scroll cursor for select * from t;
4704close c$0;
4705"), @r"
4706 hover: cursor c for select * from t
4707 ╭▸
4708 3 │ close c;
4709 ╰╴ ─ hover
4710 ");
4711 }
4712
4713 #[test]
4714 fn hover_on_move_cursor() {
4715 assert_snapshot!(check_hover("
4716declare c scroll cursor for select * from t;
4717move forward 10 from c$0;
4718"), @r"
4719 hover: cursor c for select * from t
4720 ╭▸
4721 3 │ move forward 10 from c;
4722 ╰╴ ─ hover
4723 ");
4724 }
4725
4726 #[test]
4727 fn hover_on_prepare_statement() {
4728 assert_snapshot!(check_hover("
4729prepare stmt$0 as select 1;
4730"), @r"
4731 hover: prepare stmt as select 1
4732 ╭▸
4733 2 │ prepare stmt as select 1;
4734 ╰╴ ─ hover
4735 ");
4736 }
4737
4738 #[test]
4739 fn hover_on_execute_prepared_statement() {
4740 assert_snapshot!(check_hover("
4741prepare stmt as select 1;
4742execute stmt$0;
4743"), @r"
4744 hover: prepare stmt as select 1
4745 ╭▸
4746 3 │ execute stmt;
4747 ╰╴ ─ hover
4748 ");
4749 }
4750
4751 #[test]
4752 fn hover_on_deallocate_prepared_statement() {
4753 assert_snapshot!(check_hover("
4754prepare stmt as select 1;
4755deallocate stmt$0;
4756"), @r"
4757 hover: prepare stmt as select 1
4758 ╭▸
4759 3 │ deallocate stmt;
4760 ╰╴ ─ hover
4761 ");
4762 }
4763
4764 #[test]
4765 fn hover_on_listen_definition() {
4766 assert_snapshot!(check_hover("
4767listen updates$0;
4768"), @r"
4769 hover: listen updates
4770 ╭▸
4771 2 │ listen updates;
4772 ╰╴ ─ hover
4773 ");
4774 }
4775
4776 #[test]
4777 fn hover_on_notify_channel() {
4778 assert_snapshot!(check_hover("
4779listen updates;
4780notify updates$0;
4781"), @r"
4782 hover: listen updates
4783 ╭▸
4784 3 │ notify updates;
4785 ╰╴ ─ hover
4786 ");
4787 }
4788
4789 #[test]
4790 fn hover_on_unlisten_channel() {
4791 assert_snapshot!(check_hover("
4792listen updates;
4793unlisten updates$0;
4794"), @r"
4795 hover: listen updates
4796 ╭▸
4797 3 │ unlisten updates;
4798 ╰╴ ─ hover
4799 ");
4800 }
4801}