Skip to main content

squawk_ide/
hover.rs

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