squawk_ide/
hover.rs

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