Skip to main content

squawk_ide/
hover.rs

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