diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java
index b4e63851d..8d4e72ea4 100644
--- a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java
+++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java
@@ -13,7 +13,10 @@
import net.sf.jsqlparser.parser.feature.FeatureConfiguration;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
public abstract class AbstractJSqlParser
{
@@ -22,7 +25,21 @@ public abstract class AbstractJSqlParser
{
protected List parseErrors = new ArrayList<>();
public enum Dialect {
- ORACLE, EXASOL
+ ANSI_SQL, ORACLE, MYSQL(Feature.allowBackslashEscapeCharacter,
+ Feature.allowHashLineComments), MARIADB(Feature.allowBackslashEscapeCharacter,
+ Feature.allowHashLineComments), SQLSERVER(
+ Feature.allowSquareBracketQuotation), POSTGRESQL, H2, EXASOL;
+
+ private final Set lexerFeatures;
+
+ Dialect(Feature... lexerFeatures) {
+ this.lexerFeatures = lexerFeatures.length == 0 ? EnumSet.noneOf(Feature.class)
+ : EnumSet.copyOf(Arrays.asList(lexerFeatures));
+ }
+
+ public Set getLexerFeatures() {
+ return lexerFeatures;
+ }
}
public P withSquareBracketQuotation() {
@@ -62,7 +79,11 @@ public P withTimeOut(long timeOutMillSeconds) {
}
public P withDialect(Dialect dialect) {
- return withFeature(Feature.dialect, dialect.name());
+ withFeature(Feature.dialect, dialect.name());
+ for (Feature lexerFeature : dialect.getLexerFeatures()) {
+ withFeature(lexerFeature, true);
+ }
+ return me();
}
public P withAllowedNestingDepth(int allowedNestingDepth) {
diff --git a/src/site/sphinx/usage.rst b/src/site/sphinx/usage.rst
index c0bcdac88..d989b010b 100644
--- a/src/site/sphinx/usage.rst
+++ b/src/site/sphinx/usage.rst
@@ -317,4 +317,16 @@ Additionally there are Features to control the Parser's effort at the cost of th
sqlStr
, parser -> parser
.withBackslashEscapeCharacter(true)
- );
\ No newline at end of file
+ );
+
+Instead of turning the individual Parser Features on one by one, a ``Dialect`` preset selects the features of that database dialect: ``withDialect(Dialect.MYSQL)`` turns on ``withBackslashEscapeCharacter`` and ``withHashLineComments`` (both MySQL and MariaDB syntax), ``withDialect(Dialect.SQLSERVER)`` turns on ``withSquareBracketQuotation``. Features set explicitly after the dialect preset win over the preset.
+
+.. code-block:: java
+
+ // Select the Database Dialect: turns on that dialect's parser features
+ sqlStr="SELECT `col` FROM t WHERE a = 'x\\'yz' AND b = 42#24";
+ Statement stmt3 = CCJSqlParserUtil.parse(
+ sqlStr
+ , parser -> parser
+ .withDialect(Dialect.MYSQL)
+ );
diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java
index 4a7258707..6addd7f83 100644
--- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java
+++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java
@@ -564,4 +564,51 @@ public void testHashLineCommentsMySQLStatementSemantics() throws Exception {
assertEquals("SELECT 1 # comment",
CCJSqlParserUtil.parse("SELECT 1 # comment").toString());
}
+
+ @Test
+ public void testDialectPresets() throws Exception {
+ // MYSQL and MARIADB: backslash escapes and # line comments (MySQL 8
+ // manual "Comments" and "String Literals", MariaDB KB "Comment Syntax"
+ // and "String Literals"); backticks are always on, brackets are not
+ // MySQL syntax
+ for (AbstractJSqlParser.Dialect dialect : new AbstractJSqlParser.Dialect[] {
+ AbstractJSqlParser.Dialect.MYSQL, AbstractJSqlParser.Dialect.MARIADB}) {
+ assertEquals("SELECT `col` FROM t WHERE a = 'x\\'yz' AND b = 42", CCJSqlParserUtil
+ .parse("SELECT `col` FROM t WHERE a = 'x\\'yz' AND b = 42#24",
+ p -> p.withDialect(dialect))
+ .toString());
+ }
+ // SQLSERVER: bracket quotation only (Microsoft Learn "Database
+ // Identifiers"), `#` stays available for identifiers (temp tables)
+ assertEquals("SELECT [my column] FROM t",
+ CCJSqlParserUtil.parse("SELECT [my column] FROM t",
+ p -> p.withDialect(AbstractJSqlParser.Dialect.SQLSERVER)).toString());
+ // empty presets keep the defaults: the #2507 operator, no backslash
+ // escapes
+ for (AbstractJSqlParser.Dialect dialect : new AbstractJSqlParser.Dialect[] {
+ AbstractJSqlParser.Dialect.ANSI_SQL, AbstractJSqlParser.Dialect.ORACLE,
+ AbstractJSqlParser.Dialect.POSTGRESQL, AbstractJSqlParser.Dialect.H2,
+ AbstractJSqlParser.Dialect.EXASOL}) {
+ assertEquals("SELECT 42 # 24",
+ CCJSqlParserUtil.parse("SELECT 42 # 24", p -> p.withDialect(dialect))
+ .toString());
+ assertThrows(JSQLParserException.class, () -> CCJSqlParserUtil
+ .parse("SELECT 'a\\'b'", p -> p.withDialect(dialect)));
+ }
+ }
+
+ @Test
+ public void testDialectPresetSwitchOverrides() throws Exception {
+ // an explicit switch after the preset wins: `#` is the #2507
+ // operator again
+ assertEquals("SELECT 1 # comment", CCJSqlParserUtil.parse("SELECT 1 # comment",
+ p -> p.withDialect(AbstractJSqlParser.Dialect.MYSQL).withHashLineComments(false))
+ .toString());
+ // the preset never turns a previously enabled switch off
+ assertEquals("SELECT [my column] FROM mytable",
+ CCJSqlParserUtil.parse("SELECT [my column] FROM mytable",
+ p -> p.withSquareBracketQuotation(true)
+ .withDialect(AbstractJSqlParser.Dialect.MYSQL))
+ .toString());
+ }
}