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