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