Skip to main content

squawk_ide/
hover.rs

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