Snowflake: Fix stage delimiter handling and gate stage table factor on dialect

- Gate parse_snowflake_stage_table_factor behind Dialect::supports_stages(),
  preventing non-Snowflake dialects (such as PostgreSQL) from parsing @stage as
  a table factor.
- In parse_stage_name_identifier, handle ',' and ';' delimiters without consuming
  them, and reject empty or bare '@' stage names.
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 1af0022..0f3f564 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -1608,6 +1608,13 @@
         false
     }
 
+    /// Returns true if this dialect supports Snowflake-style stages in table factors (e.g. `@stage`).
+    ///
+    /// [Snowflake](https://docs.snowflake.com/en/user-guide/querying-stage)
+    fn supports_stages(&self) -> bool {
+        false
+    }
+
     /// Support quote delimited string literals, e.g. `Q'{...}'`
     ///
     /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Literals.html#GUID-1824CBAA-6E16-4921-B2A6-112FB02248DA)
diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs
index 0bbd859..41a8f87 100644
--- a/src/dialect/snowflake.rs
+++ b/src/dialect/snowflake.rs
@@ -672,6 +672,10 @@
         true
     }
 
+    fn supports_stages(&self) -> bool {
+        true
+    }
+
     /// See <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
     fn supports_select_wildcard_replace(&self) -> bool {
         true
@@ -1314,12 +1318,8 @@
     let mut ident = String::new();
     while let Some(next_token) = parser.next_token_no_skip() {
         match &next_token.token {
-            Token::Whitespace(_) | Token::SemiColon => break,
-            Token::Period => {
-                parser.prev_token();
-                break;
-            }
-            Token::LParen | Token::RParen => {
+            Token::Whitespace(_) => break,
+            Token::Period | Token::Comma | Token::SemiColon | Token::LParen | Token::RParen => {
                 parser.prev_token();
                 break;
             }
@@ -1336,6 +1336,9 @@
             _ => return parser.expected_ref("stage name identifier", parser.peek_token_ref()),
         }
     }
+    if ident.is_empty() || ident == "@" {
+        return parser.expected_ref("stage name identifier", parser.peek_token_ref());
+    }
     Ok(Ident::new(ident))
 }
 
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index e1e397f..eb435f1 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -16714,7 +16714,7 @@
             && self.peek_keyword_with_tokens(Keyword::SEMANTIC_VIEW, &[Token::LParen])
         {
             self.parse_semantic_view_table_factor()
-        } else if self.peek_token_ref().token == Token::AtSign {
+        } else if self.dialect.supports_stages() && self.peek_token_ref().token == Token::AtSign {
             // Stage reference: @mystage or @namespace.stage (e.g. Snowflake)
             self.parse_snowflake_stage_table_factor()
         } else {
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 722cc14..9fb208b 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -20128,3 +20128,18 @@
     all_dialects().verified_stmt("SELECT X'ab''cd'");
     all_dialects().one_statement_parses_to("SELECT x'''' N", "SELECT X'''' AS N");
 }
+
+#[test]
+fn parse_stage_table_factor() {
+    let supported = all_dialects_where(|d| d.supports_stages());
+    supported.verified_stmt("SELECT * FROM @stage");
+    supported.verified_stmt("SELECT * FROM @stage, my_table");
+
+    let unsupported = all_dialects_where(|d| !d.supports_stages() && !d.is_identifier_start('@'));
+    assert_eq!(
+        unsupported
+            .parse_sql_statements("SELECT * FROM @stage")
+            .unwrap_err(),
+        ParserError::ParserError("Expected: identifier, found: @".to_string()),
+    );
+}
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index d0027b0..0d08dc0 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -10022,3 +10022,12 @@
     pg().verified_stmt("SELECT ||/ -2");
     pg().verified_stmt("SELECT |/ ||/ 2");
 }
+
+#[test]
+fn parse_stage_table_factor_rejected() {
+    let sql = "SELECT * FROM @stage";
+    assert_eq!(
+        pg().parse_sql_statements(sql).unwrap_err(),
+        ParserError::ParserError("Expected: identifier, found: @".to_string()),
+    );
+}
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index 2b16ffe..3722234 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -4919,3 +4919,43 @@
     snowflake().one_statement_parses_to("RM @````", "REMOVE @````");
     snowflake().verified_stmt(r#"REMOVE @"stage""name""#);
 }
+
+#[test]
+fn test_stage_name_delimiters() {
+    snowflake().verified_stmt("SELECT * FROM @stage1, @stage2");
+    snowflake().verified_stmt("SELECT * FROM @stage, my_table");
+    snowflake().verified_stmt("SELECT * FROM my_table, @stage");
+    snowflake().verified_stmt("SELECT * FROM @namespace.stage_name, item");
+    snowflake().verified_stmt("SELECT * FROM @stage(file_format => 'myformat'), my_table");
+    snowflake().verified_stmt("SELECT * FROM @stage AS s, my_table");
+    snowflake().verified_stmt("SELECT * FROM @stage s, my_table");
+    let stmts = snowflake()
+        .parse_sql_statements("SELECT * FROM @stage; SELECT 1")
+        .unwrap();
+    assert_eq!(stmts.len(), 2);
+
+    assert_eq!(
+        snowflake()
+            .parse_sql_statements("SELECT * FROM @")
+            .unwrap_err(),
+        ParserError::ParserError("Expected: stage name identifier, found: EOF".to_string()),
+    );
+    assert_eq!(
+        snowflake()
+            .parse_sql_statements("SELECT * FROM @;")
+            .unwrap_err(),
+        ParserError::ParserError("Expected: stage name identifier, found: ;".to_string()),
+    );
+    assert_eq!(
+        snowflake()
+            .parse_sql_statements("SELECT * FROM @, item")
+            .unwrap_err(),
+        ParserError::ParserError("Expected: stage name identifier, found: ,".to_string()),
+    );
+    assert_eq!(
+        snowflake()
+            .parse_sql_statements("SELECT * FROM @.stage")
+            .unwrap_err(),
+        ParserError::ParserError("Expected: stage name identifier, found: .".to_string()),
+    );
+}