Skip to main content

sqlparser/ast/helpers/
stmt_data_loading.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! AST types specific to loading and unloading syntax, like one available in Snowflake which
19//! contains: STAGE ddl operations, PUT upload or COPY INTO
20//! See [this page](https://docs.snowflake.com/en/sql-reference/commands-data-loading) for more details.
21
22#[cfg(not(feature = "std"))]
23use alloc::string::String;
24use core::fmt;
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29use crate::ast::helpers::key_value_options::KeyValueOptions;
30use crate::ast::{Ident, ObjectName, SelectItem};
31#[cfg(feature = "visitor")]
32use sqlparser_derive::{Visit, VisitMut};
33
34#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
37/// Parameters for a named stage object used in data loading/unloading.
38pub struct StageParamsObject {
39    /// Optional URL for the stage.
40    pub url: Option<String>,
41    /// Encryption-related key/value options.
42    pub encryption: KeyValueOptions,
43    /// Optional endpoint string.
44    pub endpoint: Option<String>,
45    /// Optional storage integration identifier.
46    pub storage_integration: Option<String>,
47    /// Credentials for accessing the stage.
48    pub credentials: KeyValueOptions,
49}
50
51/// This enum enables support for both standard SQL select item expressions
52/// and Snowflake-specific ones for data loading.
53#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
54#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
55#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
56pub enum StageLoadSelectItemKind {
57    /// A standard SQL select item expression.
58    SelectItem(SelectItem),
59    /// A Snowflake-specific select item used for stage loading.
60    StageLoadSelectItem(StageLoadSelectItem),
61}
62
63impl fmt::Display for StageLoadSelectItemKind {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        match &self {
66            StageLoadSelectItemKind::SelectItem(item) => write!(f, "{item}"),
67            StageLoadSelectItemKind::StageLoadSelectItem(item) => write!(f, "{item}"),
68        }
69    }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
75/// A single item in the `SELECT` list for data loading from staged files.
76pub struct StageLoadSelectItem {
77    /// Optional alias for the input source.
78    pub alias: Option<Ident>,
79    /// Column number within the staged file (1-based).
80    pub file_col_num: i32,
81    /// Optional element identifier following the column reference.
82    pub element: Option<Ident>,
83    /// Optional alias for the item (AS clause).
84    pub item_as: Option<Ident>,
85}
86
87impl fmt::Display for StageParamsObject {
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        let url = &self.url.as_ref();
90        let storage_integration = &self.storage_integration.as_ref();
91        let endpoint = &self.endpoint.as_ref();
92
93        if url.is_some() {
94            write!(f, " URL='{}'", url.unwrap())?;
95        }
96        if storage_integration.is_some() {
97            write!(f, " STORAGE_INTEGRATION={}", storage_integration.unwrap())?;
98        }
99        if endpoint.is_some() {
100            write!(f, " ENDPOINT='{}'", endpoint.unwrap())?;
101        }
102        if !self.credentials.options.is_empty() {
103            write!(f, " CREDENTIALS=({})", self.credentials)?;
104        }
105        if !self.encryption.options.is_empty() {
106            write!(f, " ENCRYPTION=({})", self.encryption)?;
107        }
108
109        Ok(())
110    }
111}
112
113impl fmt::Display for StageLoadSelectItem {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        if let Some(alias) = &self.alias {
116            write!(f, "{alias}.")?;
117        }
118        write!(f, "${}", self.file_col_num)?;
119        if let Some(element) = &self.element {
120            write!(f, ":{element}")?;
121        }
122        if let Some(item_as) = &self.item_as {
123            write!(f, " AS {item_as}")?;
124        }
125        Ok(())
126    }
127}
128
129#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
130#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
131#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
132/// A command to stage files to a named stage.
133pub struct FileStagingCommand {
134    /// The stage to which files are being staged.
135    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
136    pub stage: ObjectName,
137    /// Optional file matching `PATTERN` expression.
138    pub pattern: Option<String>,
139}
140
141impl fmt::Display for FileStagingCommand {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        write!(f, "{}", self.stage)?;
144        if let Some(pattern) = self.pattern.as_ref() {
145            write!(f, " PATTERN='{pattern}'")?;
146        }
147        Ok(())
148    }
149}