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