15
15
// specific language governing permissions and limitations
16
16
// under the License.
17
17
18
+ use super :: keywords:: RESERVED_FOR_IDENTIFIER ;
18
19
#[ cfg( not( feature = "std" ) ) ]
19
20
use crate :: alloc:: string:: ToString ;
20
21
use crate :: ast:: helpers:: key_value_options:: { KeyValueOption , KeyValueOptionType , KeyValueOptions } ;
@@ -24,10 +25,11 @@ use crate::ast::helpers::stmt_data_loading::{
24
25
FileStagingCommand , StageLoadSelectItem , StageParamsObject ,
25
26
} ;
26
27
use crate :: ast:: {
27
- CatalogSyncNamespaceMode , ColumnOption , ColumnPolicy , ColumnPolicyProperty , ContactEntry ,
28
- CopyIntoSnowflakeKind , Ident , IdentityParameters , IdentityProperty , IdentityPropertyFormatKind ,
29
- IdentityPropertyKind , IdentityPropertyOrder , ObjectName , RowAccessPolicy , ShowObjects ,
30
- Statement , StorageSerializationPolicy , TagsColumnOption , WrappedCollection ,
28
+ CatalogSyncNamespaceMode , CloudProviderParams , ColumnOption , ColumnPolicy ,
29
+ ColumnPolicyProperty , ContactEntry , CopyIntoSnowflakeKind , Ident , IdentityParameters ,
30
+ IdentityProperty , IdentityPropertyFormatKind , IdentityPropertyKind , IdentityPropertyOrder ,
31
+ ObjectName , RowAccessPolicy , ShowObjects , Statement , StorageSerializationPolicy ,
32
+ TagsColumnOption , WrappedCollection ,
31
33
} ;
32
34
use crate :: dialect:: { Dialect , Precedence } ;
33
35
use crate :: keywords:: Keyword ;
@@ -42,8 +44,6 @@ use alloc::vec::Vec;
42
44
#[ cfg( not( feature = "std" ) ) ]
43
45
use alloc:: { format, vec} ;
44
46
45
- use super :: keywords:: RESERVED_FOR_IDENTIFIER ;
46
-
47
47
/// A [`Dialect`] for [Snowflake](https://www.snowflake.com/)
48
48
#[ derive( Debug , Default ) ]
49
49
pub struct SnowflakeDialect ;
@@ -179,6 +179,8 @@ impl Dialect for SnowflakeDialect {
179
179
) ) ;
180
180
} else if parser. parse_keyword ( Keyword :: DATABASE ) {
181
181
return Some ( parse_create_database ( or_replace, transient, parser) ) ;
182
+ } else if parser. parse_keywords ( & [ Keyword :: EXTERNAL , Keyword :: VOLUME ] ) {
183
+ return Some ( parse_create_external_volume ( or_replace, parser) ) ;
182
184
} else {
183
185
// need to go back with the cursor
184
186
let mut back = 1 ;
@@ -702,6 +704,146 @@ pub fn parse_create_database(
702
704
Ok ( builder. build ( ) )
703
705
}
704
706
707
+ fn parse_create_external_volume (
708
+ or_replace : bool ,
709
+ parser : & mut Parser ,
710
+ ) -> Result < Statement , ParserError > {
711
+ let if_not_exists = parser. parse_keywords ( & [ Keyword :: IF , Keyword :: NOT , Keyword :: EXISTS ] ) ;
712
+ let name = parser. parse_object_name ( false ) ?;
713
+ let mut comment = None ;
714
+ let mut allow_writes = None ;
715
+ let mut storage_locations = Vec :: new ( ) ;
716
+
717
+ // STORAGE_LOCATIONS (...)
718
+ if parser. parse_keywords ( & [ Keyword :: STORAGE_LOCATIONS ] ) {
719
+ parser. expect_token ( & Token :: Eq ) ?;
720
+ storage_locations = parse_storage_locations ( parser) ?;
721
+ } ;
722
+
723
+ // ALLOW_WRITES [ = true | false ]
724
+ if parser. parse_keyword ( Keyword :: ALLOW_WRITES ) {
725
+ parser. expect_token ( & Token :: Eq ) ?;
726
+ allow_writes = Some ( parser. parse_boolean_string ( ) ?) ;
727
+ }
728
+
729
+ // COMMENT = '...'
730
+ if parser. parse_keyword ( Keyword :: COMMENT ) {
731
+ parser. expect_token ( & Token :: Eq ) ?;
732
+ comment = Some ( parser. parse_literal_string ( ) ?) ;
733
+ }
734
+
735
+ if storage_locations. is_empty ( ) {
736
+ return Err ( ParserError :: ParserError (
737
+ "STORAGE_LOCATIONS is required for CREATE EXTERNAL VOLUME" . to_string ( ) ,
738
+ ) ) ;
739
+ }
740
+
741
+ Ok ( Statement :: CreateExternalVolume {
742
+ or_replace,
743
+ if_not_exists,
744
+ name,
745
+ allow_writes,
746
+ comment,
747
+ storage_locations,
748
+ } )
749
+ }
750
+
751
+ fn parse_storage_locations ( parser : & mut Parser ) -> Result < Vec < CloudProviderParams > , ParserError > {
752
+ let mut locations = Vec :: new ( ) ;
753
+ parser. expect_token ( & Token :: LParen ) ?;
754
+
755
+ loop {
756
+ parser. expect_token ( & Token :: LParen ) ?;
757
+
758
+ // START OF ONE CloudProviderParams BLOCK
759
+ let mut name = None ;
760
+ let mut provider = None ;
761
+ let mut base_url = None ;
762
+ let mut aws_role_arn = None ;
763
+ let mut aws_access_point_arn = None ;
764
+ let mut aws_external_id = None ;
765
+ let mut azure_tenant_id = None ;
766
+ let mut storage_endpoint = None ;
767
+ let mut use_private_link_endpoint = None ;
768
+ let mut encryption: KeyValueOptions = KeyValueOptions { options : vec ! [ ] } ;
769
+ let mut credentials: KeyValueOptions = KeyValueOptions { options : vec ! [ ] } ;
770
+
771
+ loop {
772
+ if parser. parse_keyword ( Keyword :: NAME ) {
773
+ parser. expect_token ( & Token :: Eq ) ?;
774
+ name = Some ( parser. parse_literal_string ( ) ?) ;
775
+ } else if parser. parse_keyword ( Keyword :: STORAGE_PROVIDER ) {
776
+ parser. expect_token ( & Token :: Eq ) ?;
777
+ provider = Some ( parser. parse_literal_string ( ) ?) ;
778
+ } else if parser. parse_keyword ( Keyword :: STORAGE_BASE_URL ) {
779
+ parser. expect_token ( & Token :: Eq ) ?;
780
+ base_url = Some ( parser. parse_literal_string ( ) ?) ;
781
+ } else if parser. parse_keyword ( Keyword :: STORAGE_AWS_ROLE_ARN ) {
782
+ parser. expect_token ( & Token :: Eq ) ?;
783
+ aws_role_arn = Some ( parser. parse_literal_string ( ) ?) ;
784
+ } else if parser. parse_keyword ( Keyword :: STORAGE_AWS_ACCESS_POINT_ARN ) {
785
+ parser. expect_token ( & Token :: Eq ) ?;
786
+ aws_access_point_arn = Some ( parser. parse_literal_string ( ) ?) ;
787
+ } else if parser. parse_keyword ( Keyword :: STORAGE_AWS_EXTERNAL_ID ) {
788
+ parser. expect_token ( & Token :: Eq ) ?;
789
+ aws_external_id = Some ( parser. parse_literal_string ( ) ?) ;
790
+ } else if parser. parse_keyword ( Keyword :: AZURE_TENANT_ID ) {
791
+ parser. expect_token ( & Token :: Eq ) ?;
792
+ azure_tenant_id = Some ( parser. parse_literal_string ( ) ?) ;
793
+ } else if parser. parse_keyword ( Keyword :: STORAGE_ENDPOINT ) {
794
+ parser. expect_token ( & Token :: Eq ) ?;
795
+ storage_endpoint = Some ( parser. parse_literal_string ( ) ?) ;
796
+ } else if parser. parse_keyword ( Keyword :: USE_PRIVATELINK_ENDPOINT ) {
797
+ parser. expect_token ( & Token :: Eq ) ?;
798
+ use_private_link_endpoint = Some ( parser. parse_boolean_string ( ) ?) ;
799
+ } else if parser. parse_keyword ( Keyword :: ENCRYPTION ) {
800
+ parser. expect_token ( & Token :: Eq ) ?;
801
+ encryption = KeyValueOptions {
802
+ options : parse_parentheses_options ( parser) ?,
803
+ } ;
804
+ } else if parser. parse_keyword ( Keyword :: CREDENTIALS ) {
805
+ parser. expect_token ( & Token :: Eq ) ?;
806
+ credentials = KeyValueOptions {
807
+ options : parse_parentheses_options ( parser) ?,
808
+ } ;
809
+ } else if parser. consume_token ( & Token :: RParen ) {
810
+ break ;
811
+ } else {
812
+ return parser. expected ( "a valid key or closing paren" , parser. peek_token ( ) ) ;
813
+ }
814
+ }
815
+
816
+ let Some ( name) = name else {
817
+ return parser. expected ( "NAME = '...'" , parser. peek_token ( ) ) ;
818
+ } ;
819
+
820
+ let Some ( provider) = provider else {
821
+ return parser. expected ( "STORAGE_PROVIDER = '...'" , parser. peek_token ( ) ) ;
822
+ } ;
823
+
824
+ locations. push ( CloudProviderParams {
825
+ name,
826
+ provider,
827
+ base_url,
828
+ aws_role_arn,
829
+ aws_access_point_arn,
830
+ aws_external_id,
831
+ azure_tenant_id,
832
+ storage_endpoint,
833
+ use_private_link_endpoint,
834
+ encryption,
835
+ credentials,
836
+ } ) ;
837
+ // EXIT if next token is RParen
838
+ if parser. consume_token ( & Token :: RParen ) {
839
+ break ;
840
+ }
841
+ // Otherwise expect a comma before next object
842
+ parser. expect_token ( & Token :: Comma ) ?;
843
+ }
844
+ Ok ( locations)
845
+ }
846
+
705
847
pub fn parse_storage_serialization_policy (
706
848
parser : & mut Parser ,
707
849
) -> Result < StorageSerializationPolicy , ParserError > {
0 commit comments