LCOV - code coverage report
Current view: top level - dashql-core/src/analyzer - parameters.rs Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 39 39
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : //! Collect the parameters of a script.
       2              : //!
       3              : //! A parameter stands for a table when it is the table of a table reference (`from :source`,
       4              : //! `insert into :target`), and for a scalar value everywhere else (`where x > :min`). A scalar parameter that is
       5              : //! the value of a cast (`:min::int`, `cast(:day as date)`) has the type of the cast.
       6              : 
       7              : use super::sql_types::{read_sql_type, SqlType};
       8              : use super::state::AnalysisState;
       9              : use super::types::*;
      10              : use dashql_buffers::parser::{AttributeKey as K, Node, NodeType};
      11              : use dashql_parser::attrs;
      12              : use std::ops::Range;
      13              : use std::sync::Arc;
      14              : 
      15         3589 : pub(super) fn visit(state: &mut AnalysisState, morsel: Range<usize>) {
      16        78912 :     for node_id in morsel {
      17        78912 :         let node = &state.ast[node_id];
      18        78912 :         if node.node_type() != NodeType::OBJECT_SQL_PARAMETER_REF {
      19        78028 :             continue;
      20          884 :         }
      21          884 :         let parent = &state.ast[node.parent() as usize];
      22          884 :         let kind = if node.attribute_key() == K::SQL_TABLEREF_TABLE && parent.node_type() == NodeType::OBJECT_SQL_TABLEREF {
      23          694 :             ParameterKind::Table
      24              :         } else {
      25          190 :             ParameterKind::Scalar
      26              :         };
      27          884 :         let [name] = attrs!(state.children(node), [K::SQL_PARAMETER_NAME]);
      28          884 :         let name = name.and_then(|n| state.read_name_path(n).last().map(|&id| state.name(id).text)).map(unquote);
      29          884 :         let cast_type = match kind {
      30          190 :             ParameterKind::Scalar => cast_type(state, node, parent),
      31          694 :             ParameterKind::Table => None,
      32              :         };
      33          884 :         let node_id = node_id as u32;
      34          884 :         let parameter = Parameter {
      35          884 :             ast_node_id: node_id,
      36          884 :             ast_statement_id: state.find_statement_id(node_id),
      37          884 :             location: *node.symbol_span(),
      38          884 :             kind,
      39          884 :             name,
      40          884 :             cast_type,
      41          884 :         };
      42          884 :         state.out.parameters.push(parameter);
      43              :     }
      44         3589 : }
      45              : 
      46              : /// The type of the cast whose value is the parameter
      47          190 : fn cast_type(state: &AnalysisState, node: &Node, parent: &Node) -> Option<SqlType> {
      48          190 :     let type_key = match (parent.node_type(), node.attribute_key()) {
      49           33 :         (NodeType::OBJECT_SQL_TYPECAST_EXPRESSION, K::SQL_TYPECAST_VALUE) => K::SQL_TYPECAST_TYPE,
      50            9 :         (NodeType::OBJECT_SQL_FUNCTION_CAST_ARGS, K::SQL_FUNCTION_CAST_VALUE) => K::SQL_FUNCTION_CAST_TYPE,
      51          148 :         _ => return None,
      52              :     };
      53           84 :     let type_node = state.children(parent).iter().find(|c| c.attribute_key() == type_key)?;
      54           42 :     read_sql_type(state.parsed, type_node)
      55          190 : }
      56              : 
      57              : /// The parser keeps the quotes of names from string literals (`:'mode'`, see docs/design/core_quirks.md)
      58          874 : fn unquote(name: Arc<str>) -> Arc<str> {
      59          874 :     match name.strip_prefix('\'').and_then(|n| n.strip_suffix('\'')) {
      60            1 :         Some(inner) => inner.into(),
      61          873 :         None => name,
      62              :     }
      63          874 : }
        

Generated by: LCOV version 2.0-1