Skip to main content

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