diff --git a/build.gradle b/build.gradle index fdafea122..6001e62e9 100644 --- a/build.gradle +++ b/build.gradle @@ -180,15 +180,12 @@ spotbugs { pmd { consoleOutput = false - toolVersion = "6.46.0" - sourceSets = [sourceSets.main] // clear the ruleset in order to use configured rules only ruleSets = [] //rulesMinimumPriority = 1 - ruleSetFiles = files("config/pmd/ruleset.xml") pmdMain { diff --git a/config/pmd/ruleset.xml b/config/pmd/ruleset.xml index c4826a9a6..fdfa1169d 100644 --- a/config/pmd/ruleset.xml +++ b/config/pmd/ruleset.xml @@ -48,8 +48,8 @@ under the License. - - + + diff --git a/pom.xml b/pom.xml index 8ba319c2b..76c20c84b 100644 --- a/pom.xml +++ b/pom.xml @@ -131,7 +131,7 @@ org.apache.maven.plugins maven-pmd-plugin - 3.14.0 + 3.19.0 @@ -218,7 +218,7 @@ net.java.dev.javacc javacc - 7.0.11 + 7.0.12 @@ -418,92 +418,11 @@ 3.3.0 - - org.codehaus.mojo findbugs-maven-plugin 3.0.5 - - - - - - org.javacc.plugin - javacc-maven-plugin - 3.0.3 - - - false - - - false - - - false - - - - - ${project.reporting.outputDirectory} - - @@ -628,7 +547,7 @@ UTF-8 - 6.46.0 + 6.53.0 JSqlParser parses an SQL statement and translate it into a hierarchy of Java classes. diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java index 23272a0c1..5cd8a1667 100644 --- a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java +++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java @@ -36,6 +36,10 @@ public P withUnsupportedStatements(boolean allowUnsupportedStatements) { public P withTimeOut(int timeOutMillSeconds) { return withFeature(Feature.timeOut, timeOutMillSeconds); } + + public P withBackslashEscapeCharacter(boolean allowBackslashEscapeCharacter) { + return withFeature(Feature.allowBackslashEscapeCharacter, allowBackslashEscapeCharacter); + } public P withFeature(Feature f, boolean enabled) { getConfiguration().setValue(f, enabled); diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index e231a446a..d7ae1b6c8 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -21,8 +21,8 @@ import net.sf.jsqlparser.statement.DeclareStatement; import net.sf.jsqlparser.statement.DescribeStatement; import net.sf.jsqlparser.statement.ExplainStatement; -import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ResetStatement; +import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ShowColumnsStatement; import net.sf.jsqlparser.statement.ShowStatement; import net.sf.jsqlparser.statement.UseStatement; @@ -447,6 +447,7 @@ public enum Feature { * * @see Replace */ + @Deprecated replace, /** * SQL "DROP" statement is allowed @@ -758,7 +759,12 @@ public enum Feature { */ allowUnsupportedStatements(false), - timeOut( 6000) + timeOut( 6000), + + /** + * allows Backslash '\' as Escape Character + */ + allowBackslashEscapeCharacter(false), ; private Object value; diff --git a/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java b/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java index 17ef20e22..402574d26 100644 --- a/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java +++ b/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java @@ -30,6 +30,8 @@ public class Drop implements Statement { private boolean ifExists = false; private boolean materialized = false; + private boolean isUsingTemporary; + @Override public void accept(StatementVisitor statementVisitor) { statementVisitor.visit(this); @@ -67,6 +69,19 @@ public void setIfExists(boolean ifExists) { this.ifExists = ifExists; } + public boolean isUsingTemporary() { + return isUsingTemporary; + } + + public void setUsingTemporary(boolean useTemporary) { + this.isUsingTemporary=useTemporary; + } + + public Drop withUsingTemporary(boolean useTemporary) { + setUsingTemporary(useTemporary); + return this; + } + public boolean isMaterialized() { return materialized; } @@ -85,7 +100,8 @@ public void setTypeToParameters(Map> typeToParameters) { @Override public String toString() { - String sql = "DROP " + String sql = "DROP " + + (isUsingTemporary ? "TEMPORARY " : "") + (materialized ? "MATERIALIZED " : "") + type + " " + (ifExists ? "IF EXISTS " : "") + name.toString(); diff --git a/src/main/java/net/sf/jsqlparser/statement/replace/Replace.java b/src/main/java/net/sf/jsqlparser/statement/replace/Replace.java index e62b7ddb7..3c1f6a289 100644 --- a/src/main/java/net/sf/jsqlparser/statement/replace/Replace.java +++ b/src/main/java/net/sf/jsqlparser/statement/replace/Replace.java @@ -9,179 +9,75 @@ */ package net.sf.jsqlparser.statement.replace; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.statement.upsert.Upsert; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.operators.relational.ItemsList; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.StatementVisitor; -import net.sf.jsqlparser.statement.select.PlainSelect; - -public class Replace implements Statement { - - private Table table; - private List columns; - private ItemsList itemsList; - private List expressions; - private boolean useValues = true; - private boolean useIntoTables = false; - - @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); - } - public Table getTable() { - return table; - } +/** + * Not Standard compliant REPLACE Statement + * @deprecated + * This class has been merged into the UPSERT statement and should not longer been used. + *

Use {@link Upsert} instead. + * + */ - public void setTable(Table name) { - table = name; - } +@Deprecated +public class Replace extends Upsert { + @Deprecated public boolean isUseIntoTables() { - return useIntoTables; + return super.isUsingInto(); } + @Deprecated public void setUseIntoTables(boolean useIntoTables) { - this.useIntoTables = useIntoTables; - } - - public List getColumns() { - return columns; - } - - public ItemsList getItemsList() { - return itemsList; - } - - public void setColumns(List list) { - columns = list; - } - - public void setItemsList(ItemsList list) { - itemsList = list; + super.setUsingInto( useIntoTables ); } + @Deprecated /** * A list of {@link net.sf.jsqlparser.expression.Expression}s (from a "REPLACE mytab SET * col1=exp1, col2=exp2").
* it is null in case of a "REPLACE mytab (col1, col2) [...]" */ public List getExpressions() { - return expressions; + return super.getSetExpressions(); } + @Deprecated public void setExpressions(List list) { - expressions = list; - } - - public boolean isUseValues() { - return useValues; - } - - public void setUseValues(boolean useValues) { - this.useValues = useValues; - } - - @Override - public String toString() { - StringBuilder sql = new StringBuilder(); - sql.append("REPLACE "); - if (isUseIntoTables()) { - sql.append("INTO "); - } - sql.append(table); - - if (expressions != null && columns != null) { - // the SET col1=exp1, col2=exp2 case - sql.append(" SET "); - // each element from expressions match up with a column from columns. - for (int i = 0, s = columns.size(); i < s; i++) { - sql.append(columns.get(i)).append("=").append(expressions.get(i)); - sql.append( i < s - 1 - ? ", " - : "" ); - } - } else if (columns != null) { - // the REPLACE mytab (col1, col2) [...] case - sql.append(" ").append(PlainSelect.getStringList(columns, true, true)); - } - - if (itemsList != null) { - // REPLACE mytab SELECT * FROM mytab2 - // or VALUES ('as', ?, 565) - - if (useValues) { - sql.append(" VALUES"); - } - - sql.append(" ").append(itemsList); - } - - return sql.toString(); - } - - public Replace withUseValues(boolean useValues) { - this.setUseValues(useValues); - return this; + super.setItemsList( new ExpressionList(list) ); } + @Deprecated public Replace withUseIntoTables(boolean useIntoTables) { - this.setUseIntoTables(useIntoTables); - return this; - } - - public Replace withTable(Table table) { - this.setTable(table); - return this; - } - - public Replace withColumns(List columns) { - this.setColumns(columns); - return this; - } - - public Replace withItemsList(ItemsList itemsList) { - this.setItemsList(itemsList); + super.setUsingInto(useIntoTables); return this; } + @Deprecated public Replace withExpressions(List expressions) { - this.setExpressions(expressions); + super.setItemsList( new ExpressionList(expressions) ); return this; } - public Replace addColumns(Column... columns) { - List collection = Optional.ofNullable(getColumns()).orElseGet(ArrayList::new); - Collections.addAll(collection, columns); - return this.withColumns(collection); - } - - public Replace addColumns(Collection columns) { - List collection = Optional.ofNullable(getColumns()).orElseGet(ArrayList::new); - collection.addAll(columns); - return this.withColumns(collection); - } - + @Deprecated public Replace addExpressions(Expression... expressions) { - List collection = Optional.ofNullable(getExpressions()).orElseGet(ArrayList::new); + List collection = Optional.ofNullable( super.getSetExpressions() ).orElseGet(ArrayList::new); Collections.addAll(collection, expressions); return this.withExpressions(collection); } + @Deprecated public Replace addExpressions(Collection expressions) { - List collection = Optional.ofNullable(getExpressions()).orElseGet(ArrayList::new); + List collection = Optional.ofNullable( super.getSetExpressions() ).orElseGet(ArrayList::new); collection.addAll(expressions); return this.withExpressions(collection); } - - public E getItemsList(Class type) { - return type.cast(getItemsList()); - } } diff --git a/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java b/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java index e68969691..ed602836e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java +++ b/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java @@ -9,12 +9,8 @@ */ package net.sf.jsqlparser.statement.upsert; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Optional; import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ItemsList; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; @@ -23,6 +19,12 @@ import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + public class Upsert implements Statement { private Table table; @@ -35,10 +37,40 @@ public class Upsert implements Statement { private List duplicateUpdateColumns; private List duplicateUpdateExpressionList; + private UpsertType upsertType = UpsertType.UPSERT; + + private boolean isUsingInto; + @Override public void accept(StatementVisitor statementVisitor) { statementVisitor.visit(this); } + + public UpsertType getUpsertType() { + return upsertType; + } + + public void setUpsertType(UpsertType upsertType) { + this.upsertType=upsertType; + } + + public Upsert withUpsertType(UpsertType upsertType) { + setUpsertType(upsertType); + return this; + } + + public boolean isUsingInto() { + return isUsingInto; + } + + public void setUsingInto(boolean useInto) { + this.isUsingInto = useInto; + } + + public Upsert withUsingInto(boolean useInto) { + setUsingInto(useInto); + return this; + } public void setTable(Table name) { table = name; @@ -63,6 +95,15 @@ public void setItemsList(ItemsList list) { public ItemsList getItemsList() { return itemsList; } + + public List getSetExpressions() { + List expressions = null; + if (itemsList instanceof ExpressionList) { + ExpressionList expressionList = (ExpressionList) itemsList; + expressions= expressionList.getExpressions(); + } + return expressions; + } public void setUseValues(boolean useValues) { this.useValues = useValues; @@ -113,30 +154,70 @@ public List getDuplicateUpdateExpressionList() { } @Override - @SuppressWarnings({"PMD.CyclomaticComplexity"}) + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public String toString() { StringBuilder sb = new StringBuilder(); - - sb.append("UPSERT INTO "); - sb.append(table).append(" "); - if (columns != null) { - sb.append(PlainSelect.getStringList(columns, true, true)).append(" "); - } - if (useValues) { - sb.append("VALUES "); + + switch (upsertType) { + case REPLACE: + case REPLACE_SET: + sb.append("REPLACE "); + break; + case INSERT_OR_ABORT: + sb.append("INSERT OR ABORT "); + break; + case INSERT_OR_FAIL: + sb.append("INSERT OR FAIL "); + break; + case INSERT_OR_IGNORE: + sb.append("INSERT OR IGNORE "); + break; + case INSERT_OR_REPLACE: + sb.append("INSERT OR REPLACE "); + break; + case INSERT_OR_ROLLBACK: + sb.append("INSERT OR ROLLBACK "); + break; + case UPSERT: + default: + sb.append("UPSERT "); } - if (itemsList != null) { - sb.append(itemsList); + if (isUsingInto) { + sb.append("INTO "); + } + sb.append(table).append(" "); + + if (upsertType==UpsertType.REPLACE_SET) { + sb.append("SET "); + // each element from expressions match up with a column from columns. + List expressions = getSetExpressions(); + for (int i = 0, s = columns.size(); i < s; i++) { + sb.append(columns.get(i)).append("=").append(expressions.get(i)); + sb.append( i < s - 1 + ? ", " + : "" ); + } } else { - if (useSelectBrackets) { - sb.append("("); + if (columns != null) { + sb.append(PlainSelect.getStringList(columns, true, true)).append(" "); } - if (select != null) { - sb.append(select); + if (useValues) { + sb.append("VALUES "); } - if (useSelectBrackets) { - sb.append(")"); + + if (itemsList != null) { + sb.append(itemsList); + } else { + if (useSelectBrackets) { + sb.append("("); + } + if (select != null) { + sb.append(select); + } + if (useSelectBrackets) { + sb.append(")"); + } } } diff --git a/src/main/java/net/sf/jsqlparser/statement/upsert/UpsertType.java b/src/main/java/net/sf/jsqlparser/statement/upsert/UpsertType.java new file mode 100644 index 000000000..63f34785a --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/upsert/UpsertType.java @@ -0,0 +1,21 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.upsert; + +public enum UpsertType { + UPSERT + , REPLACE + , REPLACE_SET + , INSERT_OR_ABORT + , INSERT_OR_FAIL + , INSERT_OR_IGNORE + , INSERT_OR_REPLACE + , INSERT_OR_ROLLBACK +} diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java index 849165dd7..090a2cad1 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java @@ -21,6 +21,9 @@ public DropDeParser(StringBuilder buffer) { @Override public void deParse(Drop drop) { buffer.append("DROP "); + if (drop.isUsingTemporary()) { + buffer.append("TEMPORARY "); + } if (drop.isMaterialized()) { buffer.append("MATERIALIZED "); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java index 32311c47b..05e42053e 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java @@ -9,8 +9,6 @@ */ package net.sf.jsqlparser.util.deparser; -import java.util.Iterator; - import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; @@ -22,6 +20,10 @@ import net.sf.jsqlparser.statement.select.SubSelect; import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.upsert.Upsert; +import net.sf.jsqlparser.statement.upsert.UpsertType; + +import java.util.Iterator; +import java.util.List; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class UpsertDeParser extends AbstractDeParser implements ItemsListVisitor { @@ -36,26 +38,69 @@ public UpsertDeParser(ExpressionVisitor expressionVisitor, SelectVisitor selectV } @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(Upsert upsert) { - buffer.append("UPSERT INTO "); - - buffer.append(upsert.getTable().getFullyQualifiedName()); - if (upsert.getColumns() != null) { - appendColumns(upsert); + switch (upsert.getUpsertType()) { + case REPLACE: + case REPLACE_SET: + buffer.append("REPLACE "); + break; + case INSERT_OR_ABORT: + buffer.append("INSERT OR ABORT "); + break; + case INSERT_OR_FAIL: + buffer.append("INSERT OR FAIL "); + break; + case INSERT_OR_IGNORE: + buffer.append("INSERT OR IGNORE "); + break; + case INSERT_OR_REPLACE: + buffer.append("INSERT OR REPLACE "); + break; + case INSERT_OR_ROLLBACK: + buffer.append("INSERT OR ROLLBACK "); + break; + case UPSERT: + default: + buffer.append("UPSERT "); } - if (upsert.getItemsList() != null) { - upsert.getItemsList().accept(this); + if (upsert.isUsingInto()) { + buffer.append("INTO "); } + buffer.append(upsert.getTable().getFullyQualifiedName()); - if (upsert.getSelect() != null) { - appendSelect(upsert); - } + if (upsert.getUpsertType() == UpsertType.REPLACE_SET) { + appendReplaceSetClause(upsert); + } else { + if (upsert.getColumns() != null) { + appendColumns(upsert); + } + + if (upsert.getItemsList() != null) { + upsert.getItemsList().accept(this); + } + + if (upsert.getSelect() != null) { + appendSelect(upsert); + } - if (upsert.isUseDuplicate()) { - appendDuplicate(upsert); + if (upsert.isUseDuplicate()) { + appendDuplicate(upsert); + } } + } + private void appendReplaceSetClause(Upsert upsert) { + buffer.append(" SET "); + // each element from expressions match up with a column from columns. + List expressions = upsert.getSetExpressions(); + for (int i = 0, s = upsert.getColumns().size(); i < s; i++) { + buffer.append(upsert.getColumns().get(i)).append("=").append(expressions.get(i)); + buffer.append( i < s - 1 + ? ", " + : "" ); + } } private void appendColumns(Upsert upsert) { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java index 118febfd4..0fc5210a3 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java @@ -9,12 +9,12 @@ */ package net.sf.jsqlparser.util.validation.feature; +import net.sf.jsqlparser.parser.feature.Feature; + import java.util.Collections; import java.util.EnumSet; import java.util.Set; -import net.sf.jsqlparser.parser.feature.Feature; - /** * Please add Features supported and place a link to public documentation * @@ -99,7 +99,7 @@ public enum MariaDbVersion implements Version { Feature.dropViewIfExists, Feature.dropSchemaIfExists, Feature.dropSequenceIfExists, // https://mariadb.com/kb/en/replace/ - Feature.replace, + Feature.upsert, // https://mariadb.com/kb/en/alter/ Feature.alterTable, diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java index 23fdb74cb..e234721e0 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java @@ -9,10 +9,11 @@ */ package net.sf.jsqlparser.util.validation.feature; +import net.sf.jsqlparser.parser.feature.Feature; + import java.util.Collections; import java.util.EnumSet; import java.util.Set; -import net.sf.jsqlparser.parser.feature.Feature; /** * Please add Features supported and place a link to public documentation @@ -65,7 +66,7 @@ public enum MySqlVersion implements Version { Feature.update, Feature.updateJoins, Feature.updateOrderBy, Feature.updateLimit, // https://dev.mysql.com/doc/refman/8.0/en/replace.html - Feature.replace, + Feature.upsert, // https://dev.mysql.com/doc/refman/8.0/en/delete.html Feature.delete, Feature.deleteJoin, Feature.deleteTables, Feature.deleteLimit, diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidator.java index 48904dc14..0c1323339 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidator.java @@ -9,25 +9,10 @@ */ package net.sf.jsqlparser.util.validation.validator; -import net.sf.jsqlparser.parser.feature.Feature; -import net.sf.jsqlparser.statement.replace.Replace; -import net.sf.jsqlparser.util.validation.ValidationCapability; - +@Deprecated /** * @author gitmotte */ -public class ReplaceValidator extends AbstractValidator { - - - @Override - public void validate(Replace replace) { - for (ValidationCapability c : getCapabilities()) { - validateFeature(c, Feature.replace); - } - validateOptionalFromItem(replace.getTable()); - validateOptionalItemsList(replace.getItemsList()); - validateOptionalExpressions(replace.getExpressions()); - validateOptionalExpressions(replace.getColumns()); - } +public class ReplaceValidator extends UpsertValidator { } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 2803374b6..b30298a6b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -489,21 +489,64 @@ SPECIAL_TOKEN: TOKEN: { ()*> -| <#LETTER: ["$","A"-"Z","_","#","a"-"z","\u00a2"-"\u00a5","\u00aa","\u00b5","\u00ba","\u00c0"-"\u00d6","\u00d8"-"\u00f6","\u00f8"-"\u021f","\u0222"-"\u0233","\u0250"-"\u02ad","\u02b0"-"\u02b8","\u02bb"-"\u02c1","\u02d0"-"\u02d1","\u02e0"-"\u02e4","\u02ee","\u037a","\u0386","\u0388"-"\u038a","\u038c","\u038e"-"\u03a1","\u03a3"-"\u03ce","\u03d0"-"\u03d7","\u03da"-"\u03f3","\u0400"-"\u0481","\u048c"-"\u04c4","\u04c7"-"\u04c8","\u04cb"-"\u04cc","\u04d0"-"\u04f5","\u04f8"-"\u04f9","\u0531"-"\u0556","\u0559","\u0561"-"\u0587","\u05d0"-"\u05ea","\u05f0"-"\u05f2","\u0621"-"\u063a","\u0640"-"\u064a","\u0671"-"\u06d3","\u06d5","\u06e5"-"\u06e6","\u06fa"-"\u06fc","\u0710","\u0712"-"\u072c","\u0780"-"\u07a5","\u0905"-"\u0939","\u093d","\u0950","\u0958"-"\u0961","\u0985"-"\u098c","\u098f"-"\u0990","\u0993"-"\u09a8","\u09aa"-"\u09b0","\u09b2","\u09b6"-"\u09b9","\u09dc"-"\u09dd","\u09df"-"\u09e1","\u09f0"-"\u09f3","\u0a05"-"\u0a0a","\u0a0f"-"\u0a10","\u0a13"-"\u0a28","\u0a2a"-"\u0a30","\u0a32"-"\u0a33","\u0a35"-"\u0a36","\u0a38"-"\u0a39","\u0a59"-"\u0a5c","\u0a5e","\u0a72"-"\u0a74","\u0a85"-"\u0a8b","\u0a8d","\u0a8f"-"\u0a91","\u0a93"-"\u0aa8","\u0aaa"-"\u0ab0","\u0ab2"-"\u0ab3","\u0ab5"-"\u0ab9","\u0abd","\u0ad0","\u0ae0","\u0b05"-"\u0b0c","\u0b0f"-"\u0b10","\u0b13"-"\u0b28","\u0b2a"-"\u0b30","\u0b32"-"\u0b33","\u0b36"-"\u0b39","\u0b3d","\u0b5c"-"\u0b5d","\u0b5f"-"\u0b61","\u0b85"-"\u0b8a","\u0b8e"-"\u0b90","\u0b92"-"\u0b95","\u0b99"-"\u0b9a","\u0b9c","\u0b9e"-"\u0b9f","\u0ba3"-"\u0ba4","\u0ba8"-"\u0baa","\u0bae"-"\u0bb5","\u0bb7"-"\u0bb9","\u0c05"-"\u0c0c","\u0c0e"-"\u0c10","\u0c12"-"\u0c28","\u0c2a"-"\u0c33","\u0c35"-"\u0c39","\u0c60"-"\u0c61","\u0c85"-"\u0c8c","\u0c8e"-"\u0c90","\u0c92"-"\u0ca8","\u0caa"-"\u0cb3","\u0cb5"-"\u0cb9","\u0cde","\u0ce0"-"\u0ce1","\u0d05"-"\u0d0c","\u0d0e"-"\u0d10","\u0d12"-"\u0d28","\u0d2a"-"\u0d39","\u0d60"-"\u0d61","\u0d85"-"\u0d96","\u0d9a"-"\u0db1","\u0db3"-"\u0dbb","\u0dbd","\u0dc0"-"\u0dc6","\u0e01"-"\u0e30","\u0e32"-"\u0e33","\u0e3f"-"\u0e46","\u0e81"-"\u0e82","\u0e84","\u0e87"-"\u0e88","\u0e8a","\u0e8d","\u0e94"-"\u0e97","\u0e99"-"\u0e9f","\u0ea1"-"\u0ea3","\u0ea5","\u0ea7","\u0eaa"-"\u0eab","\u0ead"-"\u0eb0","\u0eb2"-"\u0eb3","\u0ebd","\u0ec0"-"\u0ec4","\u0ec6","\u0edc"-"\u0edd","\u0f00","\u0f40"-"\u0f47","\u0f49"-"\u0f6a","\u0f88"-"\u0f8b","\u1000"-"\u1021","\u1023"-"\u1027","\u1029"-"\u102a","\u1050"-"\u1055","\u10a0"-"\u10c5","\u10d0"-"\u10f6","\u1100"-"\u1159","\u115f"-"\u11a2","\u11a8"-"\u11f9","\u1200"-"\u1206","\u1208"-"\u1246","\u1248","\u124a"-"\u124d","\u1250"-"\u1256","\u1258","\u125a"-"\u125d","\u1260"-"\u1286","\u1288","\u128a"-"\u128d","\u1290"-"\u12ae","\u12b0","\u12b2"-"\u12b5","\u12b8"-"\u12be","\u12c0","\u12c2"-"\u12c5","\u12c8"-"\u12ce","\u12d0"-"\u12d6","\u12d8"-"\u12ee","\u12f0"-"\u130e","\u1310","\u1312"-"\u1315","\u1318"-"\u131e","\u1320"-"\u1346","\u1348"-"\u135a","\u13a0"-"\u13f4","\u1401"-"\u166c","\u166f"-"\u1676","\u1681"-"\u169a","\u16a0"-"\u16ea","\u1780"-"\u17b3","\u17db","\u1820"-"\u1877","\u1880"-"\u18a8","\u1e00"-"\u1e9b","\u1ea0"-"\u1ef9","\u1f00"-"\u1f15","\u1f18"-"\u1f1d","\u1f20"-"\u1f45","\u1f48"-"\u1f4d","\u1f50"-"\u1f57","\u1f59","\u1f5b","\u1f5d","\u1f5f"-"\u1f7d","\u1f80"-"\u1fb4","\u1fb6"-"\u1fbc","\u1fbe","\u1fc2"-"\u1fc4","\u1fc6"-"\u1fcc","\u1fd0"-"\u1fd3","\u1fd6"-"\u1fdb","\u1fe0"-"\u1fec","\u1ff2"-"\u1ff4","\u1ff6"-"\u1ffc","\u203f"-"\u2040","\u207f","\u20a0"-"\u20af","\u2102","\u2107","\u210a"-"\u2113","\u2115","\u2119"-"\u211d","\u2124","\u2126","\u2128","\u212a"-"\u212d","\u212f"-"\u2131","\u2133"-"\u2139","\u2160"-"\u2183","\u3005"-"\u3007","\u3021"-"\u3029","\u3031"-"\u3035","\u3038"-"\u303a","\u3041"-"\u3094","\u309d"-"\u309e","\u30a1"-"\u30fe","\u3105"-"\u312c","\u3131"-"\u318e","\u31a0"-"\u31b7","\u3400"-"\u4db5","\u4e00"-"\u9fa5","\ua000"-"\ua48c","\uac00"-"\ud7a3","\uf900"-"\ufa2d","\ufb00"-"\ufb06","\ufb13"-"\ufb17","\ufb1d","\ufb1f"-"\ufb28","\ufb2a"-"\ufb36","\ufb38"-"\ufb3c","\ufb3e","\ufb40"-"\ufb41","\ufb43"-"\ufb44","\ufb46"-"\ufbb1","\ufbd3"-"\ufd3d","\ufd50"-"\ufd8f","\ufd92"-"\ufdc7","\ufdf0"-"\ufdfb","\ufe33"-"\ufe34","\ufe4d"-"\ufe4f","\ufe69","\ufe70"-"\ufe72","\ufe74","\ufe76"-"\ufefc","\uff04","\uff21"-"\uff3a","\uff3f","\uff41"-"\uff5a","\uff65"-"\uffbe","\uffc2"-"\uffc7","\uffca"-"\uffcf","\uffd2"-"\uffd7","\uffda"-"\uffdc","\uffe0"-"\uffe1","\uffe5"-"\uffe6"]> -| <#PART_LETTER: ["\u0000"-"\b","\u000e"-"\u001b","$","#","@","0"-"9","A"-"Z","_","a"-"z","\u007f"-"\u009f","\u00a2"-"\u00a5","\u00aa","\u00b5","\u00ba","\u00c0"-"\u00d6","\u00d8"-"\u00f6","\u00f8"-"\u021f","\u0222"-"\u0233","\u0250"-"\u02ad","\u02b0"-"\u02b8","\u02bb"-"\u02c1","\u02d0"-"\u02d1","\u02e0"-"\u02e4","\u02ee","\u0300"-"\u034e","\u0360"-"\u0362","\u037a","\u0386","\u0388"-"\u038a","\u038c","\u038e"-"\u03a1","\u03a3"-"\u03ce","\u03d0"-"\u03d7","\u03da"-"\u03f3","\u0400"-"\u0481","\u0483"-"\u0486","\u048c"-"\u04c4","\u04c7"-"\u04c8","\u04cb"-"\u04cc","\u04d0"-"\u04f5","\u04f8"-"\u04f9","\u0531"-"\u0556","\u0559","\u0561"-"\u0587","\u0591"-"\u05a1","\u05a3"-"\u05b9","\u05bb"-"\u05bd","\u05bf","\u05c1"-"\u05c2","\u05c4","\u05d0"-"\u05ea","\u05f0"-"\u05f2","\u0621"-"\u063a","\u0640"-"\u0655","\u0660"-"\u0669","\u0670"-"\u06d3","\u06d5"-"\u06dc","\u06df"-"\u06e8","\u06ea"-"\u06ed","\u06f0"-"\u06fc","\u070f"-"\u072c","\u0730"-"\u074a","\u0780"-"\u07b0","\u0901"-"\u0903","\u0905"-"\u0939","\u093c"-"\u094d","\u0950"-"\u0954","\u0958"-"\u0963","\u0966"-"\u096f","\u0981"-"\u0983","\u0985"-"\u098c","\u098f"-"\u0990","\u0993"-"\u09a8","\u09aa"-"\u09b0","\u09b2","\u09b6"-"\u09b9","\u09bc","\u09be"-"\u09c4","\u09c7"-"\u09c8","\u09cb"-"\u09cd","\u09d7","\u09dc"-"\u09dd","\u09df"-"\u09e3","\u09e6"-"\u09f3","\u0a02","\u0a05"-"\u0a0a","\u0a0f"-"\u0a10","\u0a13"-"\u0a28","\u0a2a"-"\u0a30","\u0a32"-"\u0a33","\u0a35"-"\u0a36","\u0a38"-"\u0a39","\u0a3c","\u0a3e"-"\u0a42","\u0a47"-"\u0a48","\u0a4b"-"\u0a4d","\u0a59"-"\u0a5c","\u0a5e","\u0a66"-"\u0a74","\u0a81"-"\u0a83","\u0a85"-"\u0a8b","\u0a8d","\u0a8f"-"\u0a91","\u0a93"-"\u0aa8","\u0aaa"-"\u0ab0","\u0ab2"-"\u0ab3","\u0ab5"-"\u0ab9","\u0abc"-"\u0ac5","\u0ac7"-"\u0ac9","\u0acb"-"\u0acd","\u0ad0","\u0ae0","\u0ae6"-"\u0aef","\u0b01"-"\u0b03","\u0b05"-"\u0b0c","\u0b0f"-"\u0b10","\u0b13"-"\u0b28","\u0b2a"-"\u0b30","\u0b32"-"\u0b33","\u0b36"-"\u0b39","\u0b3c"-"\u0b43","\u0b47"-"\u0b48","\u0b4b"-"\u0b4d","\u0b56"-"\u0b57","\u0b5c"-"\u0b5d","\u0b5f"-"\u0b61","\u0b66"-"\u0b6f","\u0b82"-"\u0b83","\u0b85"-"\u0b8a","\u0b8e"-"\u0b90","\u0b92"-"\u0b95","\u0b99"-"\u0b9a","\u0b9c","\u0b9e"-"\u0b9f","\u0ba3"-"\u0ba4","\u0ba8"-"\u0baa","\u0bae"-"\u0bb5","\u0bb7"-"\u0bb9","\u0bbe"-"\u0bc2","\u0bc6"-"\u0bc8","\u0bca"-"\u0bcd","\u0bd7","\u0be7"-"\u0bef","\u0c01"-"\u0c03","\u0c05"-"\u0c0c","\u0c0e"-"\u0c10","\u0c12"-"\u0c28","\u0c2a"-"\u0c33","\u0c35"-"\u0c39","\u0c3e"-"\u0c44","\u0c46"-"\u0c48","\u0c4a"-"\u0c4d","\u0c55"-"\u0c56","\u0c60"-"\u0c61","\u0c66"-"\u0c6f","\u0c82"-"\u0c83","\u0c85"-"\u0c8c","\u0c8e"-"\u0c90","\u0c92"-"\u0ca8","\u0caa"-"\u0cb3","\u0cb5"-"\u0cb9","\u0cbe"-"\u0cc4","\u0cc6"-"\u0cc8","\u0cca"-"\u0ccd","\u0cd5"-"\u0cd6","\u0cde","\u0ce0"-"\u0ce1","\u0ce6"-"\u0cef","\u0d02"-"\u0d03","\u0d05"-"\u0d0c","\u0d0e"-"\u0d10","\u0d12"-"\u0d28","\u0d2a"-"\u0d39","\u0d3e"-"\u0d43","\u0d46"-"\u0d48","\u0d4a"-"\u0d4d","\u0d57","\u0d60"-"\u0d61","\u0d66"-"\u0d6f","\u0d82"-"\u0d83","\u0d85"-"\u0d96","\u0d9a"-"\u0db1","\u0db3"-"\u0dbb","\u0dbd","\u0dc0"-"\u0dc6","\u0dca","\u0dcf"-"\u0dd4","\u0dd6","\u0dd8"-"\u0ddf","\u0df2"-"\u0df3","\u0e01"-"\u0e3a","\u0e3f"-"\u0e4e","\u0e50"-"\u0e59","\u0e81"-"\u0e82","\u0e84","\u0e87"-"\u0e88","\u0e8a","\u0e8d","\u0e94"-"\u0e97","\u0e99"-"\u0e9f","\u0ea1"-"\u0ea3","\u0ea5","\u0ea7","\u0eaa"-"\u0eab","\u0ead"-"\u0eb9","\u0ebb"-"\u0ebd","\u0ec0"-"\u0ec4","\u0ec6","\u0ec8"-"\u0ecd","\u0ed0"-"\u0ed9","\u0edc"-"\u0edd","\u0f00","\u0f18"-"\u0f19","\u0f20"-"\u0f29","\u0f35","\u0f37","\u0f39","\u0f3e"-"\u0f47","\u0f49"-"\u0f6a","\u0f71"-"\u0f84","\u0f86"-"\u0f8b","\u0f90"-"\u0f97","\u0f99"-"\u0fbc","\u0fc6","\u1000"-"\u1021","\u1023"-"\u1027","\u1029"-"\u102a","\u102c"-"\u1032","\u1036"-"\u1039","\u1040"-"\u1049","\u1050"-"\u1059","\u10a0"-"\u10c5","\u10d0"-"\u10f6","\u1100"-"\u1159","\u115f"-"\u11a2","\u11a8"-"\u11f9","\u1200"-"\u1206","\u1208"-"\u1246","\u1248","\u124a"-"\u124d","\u1250"-"\u1256","\u1258","\u125a"-"\u125d","\u1260"-"\u1286","\u1288","\u128a"-"\u128d","\u1290"-"\u12ae","\u12b0","\u12b2"-"\u12b5","\u12b8"-"\u12be","\u12c0","\u12c2"-"\u12c5","\u12c8"-"\u12ce","\u12d0"-"\u12d6","\u12d8"-"\u12ee","\u12f0"-"\u130e","\u1310","\u1312"-"\u1315","\u1318"-"\u131e","\u1320"-"\u1346","\u1348"-"\u135a","\u1369"-"\u1371","\u13a0"-"\u13f4","\u1401"-"\u166c","\u166f"-"\u1676","\u1681"-"\u169a","\u16a0"-"\u16ea","\u1780"-"\u17d3","\u17db","\u17e0"-"\u17e9","\u180b"-"\u180e","\u1810"-"\u1819","\u1820"-"\u1877","\u1880"-"\u18a9","\u1e00"-"\u1e9b","\u1ea0"-"\u1ef9","\u1f00"-"\u1f15","\u1f18"-"\u1f1d","\u1f20"-"\u1f45","\u1f48"-"\u1f4d","\u1f50"-"\u1f57","\u1f59","\u1f5b","\u1f5d","\u1f5f"-"\u1f7d","\u1f80"-"\u1fb4","\u1fb6"-"\u1fbc","\u1fbe","\u1fc2"-"\u1fc4","\u1fc6"-"\u1fcc","\u1fd0"-"\u1fd3","\u1fd6"-"\u1fdb","\u1fe0"-"\u1fec","\u1ff2"-"\u1ff4","\u1ff6"-"\u1ffc","\u200c"-"\u200f","\u202a"-"\u202e","\u203f"-"\u2040","\u206a"-"\u206f","\u207f","\u20a0"-"\u20af","\u20d0"-"\u20dc","\u20e1","\u2102","\u2107","\u210a"-"\u2113","\u2115","\u2119"-"\u211d","\u2124","\u2126","\u2128","\u212a"-"\u212d","\u212f"-"\u2131","\u2133"-"\u2139","\u2160"-"\u2183","\u3005"-"\u3007","\u3021"-"\u302f","\u3031"-"\u3035","\u3038"-"\u303a","\u3041"-"\u3094","\u3099"-"\u309a","\u309d"-"\u309e","\u30a1"-"\u30fe","\u3105"-"\u312c","\u3131"-"\u318e","\u31a0"-"\u31b7","\u3400"-"\u4db5","\u4e00"-"\u9fa5","\ua000"-"\ua48c","\uac00"-"\ud7a3","\uf900"-"\ufa2d","\ufb00"-"\ufb06","\ufb13"-"\ufb17","\ufb1d"-"\ufb28","\ufb2a"-"\ufb36","\ufb38"-"\ufb3c","\ufb3e","\ufb40"-"\ufb41","\ufb43"-"\ufb44","\ufb46"-"\ufbb1","\ufbd3"-"\ufd3d","\ufd50"-"\ufd8f","\ufd92"-"\ufdc7","\ufdf0"-"\ufdfb","\ufe20"-"\ufe23","\ufe33"-"\ufe34","\ufe4d"-"\ufe4f","\ufe69","\ufe70"-"\ufe72","\ufe74","\ufe76"-"\ufefc","\ufeff","\uff04","\uff10"-"\uff19","\uff21"-"\uff3a","\uff3f","\uff41"-"\uff5a","\uff65"-"\uffbe","\uffc2"-"\uffc7","\uffca"-"\uffcf","\uffd2"-"\uffd7","\uffda"-"\uffdc","\uffe0"-"\uffe1","\uffe5"-"\uffe6","\ufff9"-"\ufffb"]> -| < S_CHAR_LITERAL: (["U","E","N","R","B"]|"RB"|"_utf8")? (("'" ( | ~["'", "\\", "\n", "\r"] )* "'") | ("'" ("''" | ~["'"])* "'")) > -| < S_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])* "\"" | "$$" (~["\n","\r","\""])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > - { if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { - matchedToken.image = "["; - for (int i=0;i + | | [ "$" , "#", "_" ] // Not SQL:2016 compliant! + > +| <#PART_LETTER: | | [ "$" , "#", "_" , "@" ] > + +// Unicode characters and categories are defined here: https://www.unicode.org/Public/UNIDATA/UnicodeData.txt +// SQL:2016 states: +// An is any character in the Unicode General Category classes “Lu”, “Ll”, “Lt”, “Lm”, “Lo”, or “Nl”. +// An is U+00B7, “Middle Dot”, or any character in the Unicode General Category classes “Mn”, “Mc”, “Nd”, “Pc”, or “Cf”. + +// unicode_identifier_start +| <#UnicodeIdentifierStart: ("\u00B7" | | | | | | ) > +| <#Ll: ["a"-"z","µ","ß"-"ö","ø"-"ÿ","ā","ă","ą","ć","ĉ","ċ","č","ď","đ","ē","ĕ","ė","ę","ě","ĝ","ğ","ġ","ģ","ĥ","ħ","ĩ","ī","ĭ","į","ı","ij","ĵ","ķ"-"ĸ","ĺ","ļ","ľ","ŀ","ł","ń","ņ","ň"-"ʼn","ŋ","ō","ŏ","ő","œ","ŕ","ŗ","ř","ś","ŝ","ş","š","ţ","ť","ŧ","ũ","ū","ŭ","ů","ű","ų","ŵ","ŷ","ź","ż","ž"-"ƀ","ƃ","ƅ","ƈ","ƌ"-"ƍ","ƒ","ƕ","ƙ"-"ƛ","ƞ","ơ","ƣ","ƥ","ƨ","ƪ"-"ƫ","ƭ","ư","ƴ","ƶ","ƹ"-"ƺ","ƽ"-"ƿ","dž","lj","nj","ǎ","ǐ","ǒ","ǔ","ǖ","ǘ","ǚ","ǜ"-"ǝ","ǟ","ǡ","ǣ","ǥ","ǧ","ǩ","ǫ","ǭ","ǯ"-"ǰ","dz","ǵ","ǹ","ǻ","ǽ","ǿ","ȁ","ȃ","ȅ","ȇ","ȉ","ȋ","ȍ","ȏ","ȑ","ȓ","ȕ","ȗ","ș","ț","ȝ","ȟ","ȡ","ȣ","ȥ","ȧ","ȩ","ȫ","ȭ","ȯ","ȱ","ȳ"-"ȹ","ȼ","ȿ"-"ɀ","ɂ","ɇ","ɉ","ɋ","ɍ","ɏ"-"ʓ","ʕ"-"ʯ","ͱ","ͳ","ͷ","ͻ"-"ͽ","ΐ","ά"-"ώ","ϐ"-"ϑ","ϕ"-"ϗ","ϙ","ϛ","ϝ","ϟ","ϡ","ϣ","ϥ","ϧ","ϩ","ϫ","ϭ","ϯ"-"ϳ","ϵ","ϸ","ϻ"-"ϼ","а"-"џ","ѡ","ѣ","ѥ","ѧ","ѩ","ѫ","ѭ","ѯ","ѱ","ѳ","ѵ","ѷ","ѹ","ѻ","ѽ","ѿ","ҁ","ҋ","ҍ","ҏ","ґ","ғ","ҕ","җ","ҙ","қ","ҝ","ҟ","ҡ","ң","ҥ","ҧ","ҩ","ҫ","ҭ","ү","ұ","ҳ","ҵ","ҷ","ҹ","һ","ҽ","ҿ","ӂ","ӄ","ӆ","ӈ","ӊ","ӌ","ӎ"-"ӏ","ӑ","ӓ","ӕ","ӗ","ә","ӛ","ӝ","ӟ","ӡ","ӣ","ӥ","ӧ","ө","ӫ","ӭ","ӯ","ӱ","ӳ","ӵ","ӷ","ӹ","ӻ","ӽ","ӿ","ԁ","ԃ","ԅ","ԇ","ԉ","ԋ","ԍ","ԏ","ԑ","ԓ","ԕ","ԗ","ԙ","ԛ","ԝ","ԟ","ԡ","ԣ","ԥ","ԧ","ԩ","ԫ","ԭ","ԯ","ՠ"-"ֈ","ა"-"ჺ","ჽ"-"ჿ","ᏸ"-"ᏽ","ᲀ"-"ᲈ","ᴀ"-"ᴫ","ᵫ"-"ᵷ","ᵹ"-"ᶚ","ḁ","ḃ","ḅ","ḇ","ḉ","ḋ","ḍ","ḏ","ḑ","ḓ","ḕ","ḗ","ḙ","ḛ","ḝ","ḟ","ḡ","ḣ","ḥ","ḧ","ḩ","ḫ","ḭ","ḯ","ḱ","ḳ","ḵ","ḷ","ḹ","ḻ","ḽ","ḿ","ṁ","ṃ","ṅ","ṇ","ṉ","ṋ","ṍ","ṏ","ṑ","ṓ","ṕ","ṗ","ṙ","ṛ","ṝ","ṟ","ṡ","ṣ","ṥ","ṧ","ṩ","ṫ","ṭ","ṯ","ṱ","ṳ","ṵ","ṷ","ṹ","ṻ","ṽ","ṿ","ẁ","ẃ","ẅ","ẇ","ẉ","ẋ","ẍ","ẏ","ẑ","ẓ","ẕ"-"ẝ","ẟ","ạ","ả","ấ","ầ","ẩ","ẫ","ậ","ắ","ằ","ẳ","ẵ","ặ","ẹ","ẻ","ẽ","ế","ề","ể","ễ","ệ","ỉ","ị","ọ","ỏ","ố","ồ","ổ","ỗ","ộ","ớ","ờ","ở","ỡ","ợ","ụ","ủ","ứ","ừ","ử","ữ","ự","ỳ","ỵ","ỷ","ỹ","ỻ","ỽ","ỿ"-"ἇ","ἐ"-"ἕ","ἠ"-"ἧ","ἰ"-"ἷ","ὀ"-"ὅ","ὐ"-"ὗ","ὠ"-"ὧ","ὰ"-"ώ","ᾀ"-"ᾇ","ᾐ"-"ᾗ","ᾠ"-"ᾧ","ᾰ"-"ᾴ","ᾶ"-"ᾷ","ι","ῂ"-"ῄ","ῆ"-"ῇ","ῐ"-"ΐ","ῖ"-"ῗ","ῠ"-"ῧ","ῲ"-"ῴ","ῶ"-"ῷ","ℊ","ℎ"-"ℏ","ℓ","ℯ","ℴ","ℹ","ℼ"-"ℽ","ⅆ"-"ⅉ","ⅎ","ↄ","ⰰ"-"ⱟ","ⱡ","ⱥ"-"ⱦ","ⱨ","ⱪ","ⱬ","ⱱ","ⱳ"-"ⱴ","ⱶ"-"ⱻ","ⲁ","ⲃ","ⲅ","ⲇ","ⲉ","ⲋ","ⲍ","ⲏ","ⲑ","ⲓ","ⲕ","ⲗ","ⲙ","ⲛ","ⲝ","ⲟ","ⲡ","ⲣ","ⲥ","ⲧ","ⲩ","ⲫ","ⲭ","ⲯ","ⲱ","ⲳ","ⲵ","ⲷ","ⲹ","ⲻ","ⲽ","ⲿ","ⳁ","ⳃ","ⳅ","ⳇ","ⳉ","ⳋ","ⳍ","ⳏ","ⳑ","ⳓ","ⳕ","ⳗ","ⳙ","ⳛ","ⳝ","ⳟ","ⳡ","ⳣ"-"ⳤ","ⳬ","ⳮ","ⳳ","ⴀ"-"ⴥ","ⴧ","ⴭ","ꙁ","ꙃ","ꙅ","ꙇ","ꙉ","ꙋ","ꙍ","ꙏ","ꙑ","ꙓ","ꙕ","ꙗ","ꙙ","ꙛ","ꙝ","ꙟ","ꙡ","ꙣ","ꙥ","ꙧ","ꙩ","ꙫ","ꙭ","ꚁ","ꚃ","ꚅ","ꚇ","ꚉ","ꚋ","ꚍ","ꚏ","ꚑ","ꚓ","ꚕ","ꚗ","ꚙ","ꚛ","ꜣ","ꜥ","ꜧ","ꜩ","ꜫ","ꜭ","ꜯ"-"ꜱ","ꜳ","ꜵ","ꜷ","ꜹ","ꜻ","ꜽ","ꜿ","ꝁ","ꝃ","ꝅ","ꝇ","ꝉ","ꝋ","ꝍ","ꝏ","ꝑ","ꝓ","ꝕ","ꝗ","ꝙ","ꝛ","ꝝ","ꝟ","ꝡ","ꝣ","ꝥ","ꝧ","ꝩ","ꝫ","ꝭ","ꝯ","ꝱ"-"ꝸ","ꝺ","ꝼ","ꝿ","ꞁ","ꞃ","ꞅ","ꞇ","ꞌ","ꞎ","ꞑ","ꞓ"-"ꞕ","ꞗ","ꞙ","ꞛ","ꞝ","ꞟ","ꞡ","ꞣ","ꞥ","ꞧ","ꞩ","ꞯ","ꞵ","ꞷ","ꞹ","ꞻ","ꞽ","ꞿ","ꟁ","ꟃ","ꟈ","ꟊ","ꟑ","ꟓ","ꟕ","ꟗ","ꟙ","ꟶ","ꟺ","ꬰ"-"ꭚ","ꭠ"-"ꭨ","ꭰ"-"ꮿ","ff"-"st","ﬓ"-"ﬗ","a"-"z"]> +| <#Lm: ["ʰ"-"ˁ","ˆ"-"ˑ","ˠ"-"ˤ","ˬ","ˮ","ʹ","ͺ","ՙ","ـ","ۥ"-"ۦ","ߴ"-"ߵ","ߺ","ࠚ","ࠤ","ࠨ","ࣉ","ॱ","ๆ","ໆ","ჼ","ៗ","ᡃ","ᪧ","ᱸ"-"ᱽ","ᴬ"-"ᵪ","ᵸ","ᶛ"-"ᶿ","ⁱ","ⁿ","ₐ"-"ₜ","ⱼ"-"ⱽ","ⵯ","ⸯ","々","〱"-"〵","〻","ゝ"-"ゞ","ー"-"ヾ","ꀕ","ꓸ"-"ꓽ","ꘌ","ꙿ","ꚜ"-"ꚝ","ꜗ"-"ꜟ","ꝰ","ꞈ","ꟲ"-"ꟴ","ꟸ"-"ꟹ","ꧏ","ꧦ","ꩰ","ꫝ","ꫳ"-"ꫴ","ꭜ"-"ꭟ","ꭩ","ー","゙"-"゚"]> +| <#Lo: ["ª","º","ƻ","ǀ"-"ǃ","ʔ","א"-"ת","ׯ"-"ײ","ؠ"-"ؿ","ف"-"ي","ٮ"-"ٯ","ٱ"-"ۓ","ە","ۮ"-"ۯ","ۺ"-"ۼ","ۿ","ܐ","ܒ"-"ܯ","ݍ"-"ޥ","ޱ","ߊ"-"ߪ","ࠀ"-"ࠕ","ࡀ"-"ࡘ","ࡠ"-"ࡪ","ࡰ"-"ࢇ","ࢉ"-"ࢎ","ࢠ"-"ࣈ","ऄ"-"ह","ऽ","ॐ","क़"-"ॡ","ॲ"-"ঀ","অ"-"ঌ","এ"-"ঐ","ও"-"ন","প"-"র","ল","শ"-"হ","ঽ","ৎ","ড়"-"ঢ়","য়"-"ৡ","ৰ"-"ৱ","ৼ","ਅ"-"ਊ","ਏ"-"ਐ","ਓ"-"ਨ","ਪ"-"ਰ","ਲ"-"ਲ਼","ਵ"-"ਸ਼","ਸ"-"ਹ","ਖ਼"-"ੜ","ਫ਼","ੲ"-"ੴ","અ"-"ઍ","એ"-"ઑ","ઓ"-"ન","પ"-"ર","લ"-"ળ","વ"-"હ","ઽ","ૐ","ૠ"-"ૡ","ૹ","ଅ"-"ଌ","ଏ"-"ଐ","ଓ"-"ନ","ପ"-"ର","ଲ"-"ଳ","ଵ"-"ହ","ଽ","ଡ଼"-"ଢ଼","ୟ"-"ୡ","ୱ","ஃ","அ"-"ஊ","எ"-"ஐ","ஒ"-"க","ங"-"ச","ஜ","ஞ"-"ட","ண"-"த","ந"-"ப","ம"-"ஹ","ௐ","అ"-"ఌ","ఎ"-"ఐ","ఒ"-"న","ప"-"హ","ఽ","ౘ"-"ౚ","ౝ","ౠ"-"ౡ","ಀ","ಅ"-"ಌ","ಎ"-"ಐ","ಒ"-"ನ","ಪ"-"ಳ","ವ"-"ಹ","ಽ","ೝ"-"ೞ","ೠ"-"ೡ","ೱ"-"ೲ","ഄ"-"ഌ","എ"-"ഐ","ഒ"-"ഺ","ഽ","ൎ","ൔ"-"ൖ","ൟ"-"ൡ","ൺ"-"ൿ","අ"-"ඖ","ක"-"න","ඳ"-"ර","ල","ව"-"ෆ","ก"-"ะ","า"-"ำ","เ"-"ๅ","ກ"-"ຂ","ຄ","ຆ"-"ຊ","ຌ"-"ຣ","ລ","ວ"-"ະ","າ"-"ຳ","ຽ","ເ"-"ໄ","ໜ"-"ໟ","ༀ","ཀ"-"ཇ","ཉ"-"ཬ","ྈ"-"ྌ","က"-"ဪ","ဿ","ၐ"-"ၕ","ၚ"-"ၝ","ၡ","ၥ"-"ၦ","ၮ"-"ၰ","ၵ"-"ႁ","ႎ","ᄀ"-"ቈ","ቊ"-"ቍ","ቐ"-"ቖ","ቘ","ቚ"-"ቝ","በ"-"ኈ","ኊ"-"ኍ","ነ"-"ኰ","ኲ"-"ኵ","ኸ"-"ኾ","ዀ","ዂ"-"ዅ","ወ"-"ዖ","ዘ"-"ጐ","ጒ"-"ጕ","ጘ"-"ፚ","ᎀ"-"ᎏ","ᐁ"-"ᙬ","ᙯ"-"ᙿ","ᚁ"-"ᚚ","ᚠ"-"ᛪ","ᛱ"-"ᛸ","ᜀ"-"ᜑ","ᜟ"-"ᜱ","ᝀ"-"ᝑ","ᝠ"-"ᝬ","ᝮ"-"ᝰ","ក"-"ឳ","ៜ","ᠠ"-"ᡂ","ᡄ"-"ᡸ","ᢀ"-"ᢄ","ᢇ"-"ᢨ","ᢪ","ᢰ"-"ᣵ","ᤀ"-"ᤞ","ᥐ"-"ᥭ","ᥰ"-"ᥴ","ᦀ"-"ᦫ","ᦰ"-"ᧉ","ᨀ"-"ᨖ","ᨠ"-"ᩔ","ᬅ"-"ᬳ","ᭅ"-"ᭌ","ᮃ"-"ᮠ","ᮮ"-"ᮯ","ᮺ"-"ᯥ","ᰀ"-"ᰣ","ᱍ"-"ᱏ","ᱚ"-"ᱷ","ᳩ"-"ᳬ","ᳮ"-"ᳳ","ᳵ"-"ᳶ","ᳺ","ℵ"-"ℸ","ⴰ"-"ⵧ","ⶀ"-"ⶖ","ⶠ"-"ⶦ","ⶨ"-"ⶮ","ⶰ"-"ⶶ","ⶸ"-"ⶾ","ⷀ"-"ⷆ","ⷈ"-"ⷎ","ⷐ"-"ⷖ","ⷘ"-"ⷞ","〆","〼","ぁ"-"ゖ","ゟ","ァ"-"ヺ","ヿ","ㄅ"-"ㄯ","ㄱ"-"ㆎ","ㆠ"-"ㆿ","ㇰ"-"ㇿ","䶿","鿿"-"ꀔ","ꀖ"-"ꒌ","ꓐ"-"ꓷ","ꔀ"-"ꘋ","ꘐ"-"ꘟ","ꘪ"-"ꘫ","ꙮ","ꚠ"-"ꛥ","ꞏ","ꟷ","ꟻ"-"ꠁ","ꠃ"-"ꠅ","ꠇ"-"ꠊ","ꠌ"-"ꠢ","ꡀ"-"ꡳ","ꢂ"-"ꢳ","ꣲ"-"ꣷ","ꣻ","ꣽ"-"ꣾ","ꤊ"-"ꤥ","ꤰ"-"ꥆ","ꥠ"-"ꥼ","ꦄ"-"ꦲ","ꧠ"-"ꧤ","ꧧ"-"ꧯ","ꧺ"-"ꧾ","ꨀ"-"ꨨ","ꩀ"-"ꩂ","ꩄ"-"ꩋ","ꩠ"-"ꩯ","ꩱ"-"ꩶ","ꩺ","ꩾ"-"ꪯ","ꪱ","ꪵ"-"ꪶ","ꪹ"-"ꪽ","ꫀ","ꫂ","ꫛ"-"ꫜ","ꫠ"-"ꫪ","ꫲ","ꬁ"-"ꬆ","ꬉ"-"ꬎ","ꬑ"-"ꬖ","ꬠ"-"ꬦ","ꬨ"-"ꬮ","ꯀ"-"ꯢ","힣","ힰ"-"ퟆ","ퟋ"-"ퟻ","豈"-"舘","並"-"龎","יִ","ײַ"-"ﬨ","שׁ"-"זּ","טּ"-"לּ","מּ","נּ"-"סּ","ףּ"-"פּ","צּ"-"ﮱ","ﯓ"-"ﴽ","ﵐ"-"ﶏ","ﶒ"-"ﷇ","ﷰ"-"ﷻ","ﹰ"-"ﹴ","ﹶ"-"ﻼ","ヲ"-"ッ","ア"-"ン","ᅠ"-"ᄒ","ᅡ"-"ᅦ","ᅧ"-"ᅬ","ᅭ"-"ᅲ","ᅳ"-"ᅵ"]> +| <#Lt: ["Dž","Lj","Nj","Dz","ᾈ"-"ᾏ","ᾘ"-"ᾟ","ᾨ"-"ᾯ","ᾼ","ῌ","ῼ"]> +| <#Lu: ["A"-"Z","À"-"Ö","Ø"-"Þ","Ā","Ă","Ą","Ć","Ĉ","Ċ","Č","Ď","Đ","Ē","Ĕ","Ė","Ę","Ě","Ĝ","Ğ","Ġ","Ģ","Ĥ","Ħ","Ĩ","Ī","Ĭ","Į","İ","IJ","Ĵ","Ķ","Ĺ","Ļ","Ľ","Ŀ","Ł","Ń","Ņ","Ň","Ŋ","Ō","Ŏ","Ő","Œ","Ŕ","Ŗ","Ř","Ś","Ŝ","Ş","Š","Ţ","Ť","Ŧ","Ũ","Ū","Ŭ","Ů","Ű","Ų","Ŵ","Ŷ","Ÿ"-"Ź","Ż","Ž","Ɓ"-"Ƃ","Ƅ","Ɔ"-"Ƈ","Ɖ"-"Ƌ","Ǝ"-"Ƒ","Ɠ"-"Ɣ","Ɩ"-"Ƙ","Ɯ"-"Ɲ","Ɵ"-"Ơ","Ƣ","Ƥ","Ʀ"-"Ƨ","Ʃ","Ƭ","Ʈ"-"Ư","Ʊ"-"Ƴ","Ƶ","Ʒ"-"Ƹ","Ƽ","DŽ","LJ","NJ","Ǎ","Ǐ","Ǒ","Ǔ","Ǖ","Ǘ","Ǚ","Ǜ","Ǟ","Ǡ","Ǣ","Ǥ","Ǧ","Ǩ","Ǫ","Ǭ","Ǯ","DZ","Ǵ","Ƕ"-"Ǹ","Ǻ","Ǽ","Ǿ","Ȁ","Ȃ","Ȅ","Ȇ","Ȉ","Ȋ","Ȍ","Ȏ","Ȑ","Ȓ","Ȕ","Ȗ","Ș","Ț","Ȝ","Ȟ","Ƞ","Ȣ","Ȥ","Ȧ","Ȩ","Ȫ","Ȭ","Ȯ","Ȱ","Ȳ","Ⱥ"-"Ȼ","Ƚ"-"Ⱦ","Ɂ","Ƀ"-"Ɇ","Ɉ","Ɋ","Ɍ","Ɏ","Ͱ","Ͳ","Ͷ","Ϳ","Ά","Έ"-"Ί","Ό","Ύ"-"Ώ","Α"-"Ρ","Σ"-"Ϋ","Ϗ","ϒ"-"ϔ","Ϙ","Ϛ","Ϝ","Ϟ","Ϡ","Ϣ","Ϥ","Ϧ","Ϩ","Ϫ","Ϭ","Ϯ","ϴ","Ϸ","Ϲ"-"Ϻ","Ͻ"-"Я","Ѡ","Ѣ","Ѥ","Ѧ","Ѩ","Ѫ","Ѭ","Ѯ","Ѱ","Ѳ","Ѵ","Ѷ","Ѹ","Ѻ","Ѽ","Ѿ","Ҁ","Ҋ","Ҍ","Ҏ","Ґ","Ғ","Ҕ","Җ","Ҙ","Қ","Ҝ","Ҟ","Ҡ","Ң","Ҥ","Ҧ","Ҩ","Ҫ","Ҭ","Ү","Ұ","Ҳ","Ҵ","Ҷ","Ҹ","Һ","Ҽ","Ҿ","Ӏ"-"Ӂ","Ӄ","Ӆ","Ӈ","Ӊ","Ӌ","Ӎ","Ӑ","Ӓ","Ӕ","Ӗ","Ә","Ӛ","Ӝ","Ӟ","Ӡ","Ӣ","Ӥ","Ӧ","Ө","Ӫ","Ӭ","Ӯ","Ӱ","Ӳ","Ӵ","Ӷ","Ӹ","Ӻ","Ӽ","Ӿ","Ԁ","Ԃ","Ԅ","Ԇ","Ԉ","Ԋ","Ԍ","Ԏ","Ԑ","Ԓ","Ԕ","Ԗ","Ԙ","Ԛ","Ԝ","Ԟ","Ԡ","Ԣ","Ԥ","Ԧ","Ԩ","Ԫ","Ԭ","Ԯ","Ա"-"Ֆ","Ⴀ"-"Ⴥ","Ⴧ","Ⴭ","Ꭰ"-"Ᏽ","Ა"-"Ჺ","Ჽ"-"Ჿ","Ḁ","Ḃ","Ḅ","Ḇ","Ḉ","Ḋ","Ḍ","Ḏ","Ḑ","Ḓ","Ḕ","Ḗ","Ḙ","Ḛ","Ḝ","Ḟ","Ḡ","Ḣ","Ḥ","Ḧ","Ḩ","Ḫ","Ḭ","Ḯ","Ḱ","Ḳ","Ḵ","Ḷ","Ḹ","Ḻ","Ḽ","Ḿ","Ṁ","Ṃ","Ṅ","Ṇ","Ṉ","Ṋ","Ṍ","Ṏ","Ṑ","Ṓ","Ṕ","Ṗ","Ṙ","Ṛ","Ṝ","Ṟ","Ṡ","Ṣ","Ṥ","Ṧ","Ṩ","Ṫ","Ṭ","Ṯ","Ṱ","Ṳ","Ṵ","Ṷ","Ṹ","Ṻ","Ṽ","Ṿ","Ẁ","Ẃ","Ẅ","Ẇ","Ẉ","Ẋ","Ẍ","Ẏ","Ẑ","Ẓ","Ẕ","ẞ","Ạ","Ả","Ấ","Ầ","Ẩ","Ẫ","Ậ","Ắ","Ằ","Ẳ","Ẵ","Ặ","Ẹ","Ẻ","Ẽ","Ế","Ề","Ể","Ễ","Ệ","Ỉ","Ị","Ọ","Ỏ","Ố","Ồ","Ổ","Ỗ","Ộ","Ớ","Ờ","Ở","Ỡ","Ợ","Ụ","Ủ","Ứ","Ừ","Ử","Ữ","Ự","Ỳ","Ỵ","Ỷ","Ỹ","Ỻ","Ỽ","Ỿ","Ἀ"-"Ἇ","Ἐ"-"Ἕ","Ἠ"-"Ἧ","Ἰ"-"Ἷ","Ὀ"-"Ὅ","Ὑ","Ὓ","Ὕ","Ὗ","Ὠ"-"Ὧ","Ᾰ"-"Ά","Ὲ"-"Ή","Ῐ"-"Ί","Ῠ"-"Ῥ","Ὸ"-"Ώ","ℂ","ℇ","ℋ"-"ℍ","ℐ"-"ℒ","ℕ","ℙ"-"ℝ","ℤ","Ω","ℨ","K"-"ℭ","ℰ"-"ℳ","ℾ"-"ℿ","ⅅ","Ↄ","Ⰰ"-"Ⱟ","Ⱡ","Ɫ"-"Ɽ","Ⱨ","Ⱪ","Ⱬ","Ɑ"-"Ɒ","Ⱳ","Ⱶ","Ȿ"-"Ⲁ","Ⲃ","Ⲅ","Ⲇ","Ⲉ","Ⲋ","Ⲍ","Ⲏ","Ⲑ","Ⲓ","Ⲕ","Ⲗ","Ⲙ","Ⲛ","Ⲝ","Ⲟ","Ⲡ","Ⲣ","Ⲥ","Ⲧ","Ⲩ","Ⲫ","Ⲭ","Ⲯ","Ⲱ","Ⲳ","Ⲵ","Ⲷ","Ⲹ","Ⲻ","Ⲽ","Ⲿ","Ⳁ","Ⳃ","Ⳅ","Ⳇ","Ⳉ","Ⳋ","Ⳍ","Ⳏ","Ⳑ","Ⳓ","Ⳕ","Ⳗ","Ⳙ","Ⳛ","Ⳝ","Ⳟ","Ⳡ","Ⳣ","Ⳬ","Ⳮ","Ⳳ","Ꙁ","Ꙃ","Ꙅ","Ꙇ","Ꙉ","Ꙋ","Ꙍ","Ꙏ","Ꙑ","Ꙓ","Ꙕ","Ꙗ","Ꙙ","Ꙛ","Ꙝ","Ꙟ","Ꙡ","Ꙣ","Ꙥ","Ꙧ","Ꙩ","Ꙫ","Ꙭ","Ꚁ","Ꚃ","Ꚅ","Ꚇ","Ꚉ","Ꚋ","Ꚍ","Ꚏ","Ꚑ","Ꚓ","Ꚕ","Ꚗ","Ꚙ","Ꚛ","Ꜣ","Ꜥ","Ꜧ","Ꜩ","Ꜫ","Ꜭ","Ꜯ","Ꜳ","Ꜵ","Ꜷ","Ꜹ","Ꜻ","Ꜽ","Ꜿ","Ꝁ","Ꝃ","Ꝅ","Ꝇ","Ꝉ","Ꝋ","Ꝍ","Ꝏ","Ꝑ","Ꝓ","Ꝕ","Ꝗ","Ꝙ","Ꝛ","Ꝝ","Ꝟ","Ꝡ","Ꝣ","Ꝥ","Ꝧ","Ꝩ","Ꝫ","Ꝭ","Ꝯ","Ꝺ","Ꝼ","Ᵹ"-"Ꝿ","Ꞁ","Ꞃ","Ꞅ","Ꞇ","Ꞌ","Ɥ","Ꞑ","Ꞓ","Ꞗ","Ꞙ","Ꞛ","Ꞝ","Ꞟ","Ꞡ","Ꞣ","Ꞥ","Ꞧ","Ꞩ","Ɦ"-"Ɪ","Ʞ"-"Ꞵ","Ꞷ","Ꞹ","Ꞻ","Ꞽ","Ꞿ","Ꟁ","Ꟃ","Ꞔ"-"Ꟈ","Ꟊ","Ꟑ","Ꟗ","Ꟙ","Ꟶ","A"-"Z"]> +| <#Nl: ["ᛮ"-"ᛰ","Ⅰ"-"ↂ","ↅ"-"ↈ","〇","〡"-"〩","〸"-"〺","ꛦ"-"ꛯ"]> + +// unicode_identifier_extend +| <#UnicodeIdentifierExtend: (||||)> +| <#Cf: ["­","؀"-"؅","؜","۝","܏","࢐"-"࢑","࣢","᠎","​"-"‏","‪"-"‮","⁠"-"⁤","⁦"-"","",""-""]> +| <#Mc: ["ः","ऻ","ा"-"ी","ॉ"-"ौ","ॎ"-"ॏ","ং"-"ঃ","া"-"ী","ে"-"ৈ","ো"-"ৌ","ৗ","ਃ","ਾ"-"ੀ","ઃ","ા"-"ી","ૉ","ો"-"ૌ","ଂ"-"ଃ","ା","ୀ","େ"-"ୈ","ୋ"-"ୌ","ୗ","ா"-"ி","ு"-"ூ","ெ"-"ை","ொ"-"ௌ","ௗ","ఁ"-"ః","ు"-"ౄ","ಂ"-"ಃ","ಾ","ೀ"-"ೄ","ೇ"-"ೈ","ೊ"-"ೋ","ೕ"-"ೖ","ೳ","ം"-"ഃ","ാ"-"ീ","െ"-"ൈ","ൊ"-"ൌ","ൗ","ං"-"ඃ","ා"-"ෑ","ෘ"-"ෟ","ෲ"-"ෳ","༾"-"༿","ཿ","ါ"-"ာ","ေ","း","ျ"-"ြ","ၖ"-"ၗ","ၢ"-"ၤ","ၧ"-"ၭ","ႃ"-"ႄ","ႇ"-"ႌ","ႏ","ႚ"-"ႜ","᜕","᜴","ា","ើ"-"ៅ","ះ"-"ៈ","ᤣ"-"ᤦ","ᤩ"-"ᤫ","ᤰ"-"ᤱ","ᤳ"-"ᤸ","ᨙ"-"ᨚ","ᩕ","ᩗ","ᩡ","ᩣ"-"ᩤ","ᩭ"-"ᩲ","ᬄ","ᬵ","ᬻ","ᬽ"-"ᭁ","ᭃ"-"᭄","ᮂ","ᮡ","ᮦ"-"ᮧ","᮪","ᯧ","ᯪ"-"ᯬ","ᯮ","᯲"-"᯳","ᰤ"-"ᰫ","ᰴ"-"ᰵ","᳡","᳷","〮"-"〯","ꠣ"-"ꠤ","ꠧ","ꢀ"-"ꢁ","ꢴ"-"ꣃ","ꥒ"-"꥓","ꦃ","ꦴ"-"ꦵ","ꦺ"-"ꦻ","ꦾ"-"꧀","ꨯ"-"ꨰ","ꨳ"-"ꨴ","ꩍ","ꩻ","ꩽ","ꫫ","ꫮ"-"ꫯ","ꫵ","ꯣ"-"ꯤ","ꯦ"-"ꯧ","ꯩ"-"ꯪ","꯬"]> +| <#Mn: ["̀"-"ͯ","҃"-"҇","֑"-"ֽ","ֿ","ׁ"-"ׂ","ׄ"-"ׅ","ׇ","ؐ"-"ؚ","ً"-"ٟ","ٰ","ۖ"-"ۜ","۟"-"ۤ","ۧ"-"ۨ","۪"-"ۭ","ܑ","ܰ"-"݊","ަ"-"ް","߫"-"߳","߽","ࠖ"-"࠙","ࠛ"-"ࠣ","ࠥ"-"ࠧ","ࠩ"-"࠭","࡙"-"࡛","࢘"-"࢟","࣊"-"࣡","ࣣ"-"ं","ऺ","़","ु"-"ै","्","॑"-"ॗ","ॢ"-"ॣ","ঁ","়","ু"-"ৄ","্","ৢ"-"ৣ","৾","ਁ"-"ਂ","਼","ੁ"-"ੂ","ੇ"-"ੈ","ੋ"-"੍","ੑ","ੰ"-"ੱ","ੵ","ઁ"-"ં","઼","ુ"-"ૅ","ે"-"ૈ","્","ૢ"-"ૣ","ૺ"-"૿","ଁ","଼","ି","ୁ"-"ୄ","୍","୕"-"ୖ","ୢ"-"ୣ","ஂ","ீ","்","ఀ","ఄ","఼","ా"-"ీ","ె"-"ై","ొ"-"్","ౕ"-"ౖ","ౢ"-"ౣ","ಁ","಼","ಿ","ೆ","ೌ"-"್","ೢ"-"ೣ","ഀ"-"ഁ","഻"-"഼","ു"-"ൄ","്","ൢ"-"ൣ","ඁ","්","ි"-"ු","ූ","ั","ิ"-"ฺ","็"-"๎","ັ","ິ"-"ຼ","່"-"໎","༘"-"༙","༵","༷","༹","ཱ"-"ཾ","ྀ"-"྄","྆"-"྇","ྍ"-"ྗ","ྙ"-"ྼ","࿆","ိ"-"ူ","ဲ"-"့","္"-"်","ွ"-"ှ","ၘ"-"ၙ","ၞ"-"ၠ","ၱ"-"ၴ","ႂ","ႅ"-"ႆ","ႍ","ႝ","፝"-"፟","ᜒ"-"᜔","ᜲ"-"ᜳ","ᝒ"-"ᝓ","ᝲ"-"ᝳ","឴"-"឵","ិ"-"ួ","ំ","៉"-"៓","៝","᠋"-"᠍","᠏","ᢅ"-"ᢆ","ᢩ","ᤠ"-"ᤢ","ᤧ"-"ᤨ","ᤲ","᤹"-"᤻","ᨗ"-"ᨘ","ᨛ","ᩖ","ᩘ"-"ᩞ","᩠","ᩢ","ᩥ"-"ᩬ","ᩳ"-"᩼","᩿","᪰"-"᪽","ᪿ"-"ᫎ","ᬀ"-"ᬃ","᬴","ᬶ"-"ᬺ","ᬼ","ᭂ","᭫"-"᭳","ᮀ"-"ᮁ","ᮢ"-"ᮥ","ᮨ"-"ᮩ","᮫"-"ᮭ","᯦","ᯨ"-"ᯩ","ᯭ","ᯯ"-"ᯱ","ᰬ"-"ᰳ","ᰶ"-"᰷","᳐"-"᳒","᳔"-"᳠","᳢"-"᳨","᳭","᳴","᳸"-"᳹","᷀"-"᷿","⃐"-"⃜","⃡","⃥"-"⃰","⳯"-"⳱","⵿","ⷠ"-"ⷿ","〪"-"〭","゙"-"゚","꙯","ꙴ"-"꙽","ꚞ"-"ꚟ","꛰"-"꛱","ꠂ","꠆","ꠋ","ꠥ"-"ꠦ","꠬","꣄"-"ꣅ","꣠"-"꣱","ꣿ","ꤦ"-"꤭","ꥇ"-"ꥑ","ꦀ"-"ꦂ","꦳","ꦶ"-"ꦹ","ꦼ"-"ꦽ","ꧥ","ꨩ"-"ꨮ","ꨱ"-"ꨲ","ꨵ"-"ꨶ","ꩃ","ꩌ","ꩼ","ꪰ","ꪲ"-"ꪴ","ꪷ"-"ꪸ","ꪾ"-"꪿","꫁","ꫬ"-"ꫭ","꫶","ꯥ","ꯨ","꯭","ﬞ","︀"-"️","︠"-"︯"]> +| <#Nd: ["0"-"9","٠"-"٩","۰"-"۹","߀"-"߉","०"-"९","০"-"৯","੦"-"੯","૦"-"૯","୦"-"୯","௦"-"௯","౦"-"౯","೦"-"೯","൦"-"൯","෦"-"෯","๐"-"๙","໐"-"໙","༠"-"༩","၀"-"၉","႐"-"႙","០"-"៩","᠐"-"᠙","᥆"-"᥏","᧐"-"᧙","᪀"-"᪉","᪐"-"᪙","᭐"-"᭙","᮰"-"᮹","᱀"-"᱉","᱐"-"᱙","꘠"-"꘩","꣐"-"꣙","꤀"-"꤉","꧐"-"꧙","꧰"-"꧹","꩐"-"꩙","꯰"-"꯹","0"-"9"]> +| <#Pc: ["‿"-"⁀","⁔","︳"-"︴","﹍"-"﹏","_"]> + +| < #SPECIAL_ESC: "\\'" > /* Allowing this will break LIKE ... ESCAPE ... */ +| < #ESC: "\\" ["n","t","b","r","f","\\","\""] > +| < S_CHAR_LITERAL: (["U","E","N","R","B"]|"RB"|"_utf8")? (("'" ( | | ~["'", "\\"] )* "'") | ("'" ("''" | ~["'"])* "'")) > + { + // contains the token and always the longest match is returned + // So when Backslash is explicitly not allowed as an Escape Character and a is found + // which contains the , then we will need to + // 1) break the at close it with a "'" + // 2) continue tokenizing after that with a new or any other Token + if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\'") ) { + matchedToken.image = image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; + for (int i=0;i") ) { + matchedToken.kind = i; + } } - } - input_stream.backup(image.length() - 1); - } + input_stream.backup(image.length() - matchedToken.image.length() ); + } + } +| < S_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])* "\"" | "$$" (~["\n","\r","\""])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > + { + if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { + matchedToken.image = "["; + for (int i=0;i } @@ -577,7 +620,7 @@ Statement SingleStatement() : ")" ) | - ( + LOOKAHEAD(2) ( [ with=WithList() ] ( stm = Select( with ) @@ -592,10 +635,7 @@ Statement SingleStatement() : ) ) | - stm = Upsert() - | - LOOKAHEAD(3) - stm = Replace() + LOOKAHEAD(3) stm = Upsert() | LOOKAHEAD(2) stm = AlterTable() @@ -1278,64 +1318,6 @@ Update Update( List with ): } } -Replace Replace(): -{ - Replace replace = new Replace(); - Table table = null; - Column tableColumn = null; - Expression value = null; - - List columns = new ArrayList(); - List expList = new ArrayList(); - MultiExpressionList multiExpr = null; - ItemsList itemsList = null; - Expression exp = null; -} -{ - ( [LOOKAHEAD(2) { replace.setUseIntoTables(true); }] table=Table() ) - - ( - ( - tableColumn=Column() "=" value=SimpleExpression() { columns.add(tableColumn); expList.add(value); } - ("," tableColumn=Column() "=" value=SimpleExpression() { columns.add(tableColumn); expList.add(value); } )* - { - replace.setExpressions(expList); - } - ) - | - - ( - [LOOKAHEAD(2) "(" tableColumn=Column() { columns.add(tableColumn); } ("," tableColumn=Column() { columns.add(tableColumn); } )* ")" ] - ( - LOOKAHEAD(2) [ | ] "(" exp=PrimaryExpression() { expList.add(exp); } - ("," exp=PrimaryExpression() { expList.add(exp); } )* ")" { itemsList = new ExpressionList(expList); } - ("," "(" exp=SimpleExpression() { - if (multiExpr==null) { - multiExpr=new MultiExpressionList(); - multiExpr.addExpressionList((ExpressionList)itemsList); - itemsList = multiExpr; - } - expList = new ArrayList(); - expList.add(exp); } - ("," exp=SimpleExpression() { expList.add(exp); } )* ")" { multiExpr.addExpressionList(expList); } )* - | - { replace.setUseValues(false); } - itemsList=SubSelect() - { ((SubSelect)itemsList).setUseBrackets(false); } - ) - { - replace.setItemsList(itemsList); - } - ) - ) - { - if (!columns.isEmpty()) { - replace.withColumns(columns); - } - return replace.withTable(table); - } -} - List ListExpressionItem(): { List retval = new ArrayList(); @@ -1607,26 +1589,48 @@ Upsert Upsert(): Token tk = null; } { - - [ LOOKAHEAD(2) ] table=Table() - - - [LOOKAHEAD(2) "(" tableColumn=Column() { columns.add(tableColumn); } ("," tableColumn=Column() { columns.add(tableColumn); } )* ")" ] ( + { upsert.setUpsertType(UpsertType.UPSERT); } + | + { upsert.setUpsertType(UpsertType.REPLACE); } + | + ( + { upsert.setUpsertType(UpsertType.INSERT_OR_REPLACE); } + ) + ) + [ LOOKAHEAD(2) { upsert.setUsingInto(true); } ] table=Table() + [ + LOOKAHEAD(2) "(" tableColumn=Column() { columns.add(tableColumn); } + ("," tableColumn=Column() { columns.add(tableColumn); } )* ")" + ] + ( + ( + { upsert.setUpsertType(UpsertType.REPLACE_SET); } + tableColumn=Column() "=" exp=SimpleExpression() { columns.add(tableColumn); primaryExpList.add(exp); } + ("," tableColumn=Column() "=" exp=SimpleExpression() { columns.add(tableColumn); primaryExpList.add(exp); } )* + { + itemsList = new ExpressionList(primaryExpList); + } + ) + | LOOKAHEAD(2) [ | ] "(" exp=SimpleExpression() { primaryExpList.add(exp); } - ("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { itemsList = new ExpressionList(primaryExpList); } - ("," "(" exp=SimpleExpression() { - if (multiExpr==null) { - multiExpr=new MultiExpressionList(); - multiExpr.addExpressionList((ExpressionList)itemsList); - itemsList = multiExpr; - } - primaryExpList = new ArrayList(); - primaryExpList.add(exp); } - ("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { multiExpr.addExpressionList(primaryExpList); } )* - | + ( "," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { itemsList = new ExpressionList(primaryExpList); } + ("," "(" exp=SimpleExpression() + { + if (multiExpr==null) { + multiExpr=new MultiExpressionList(); + multiExpr.addExpressionList((ExpressionList)itemsList); + itemsList = multiExpr; + } + primaryExpList = new ArrayList(); + primaryExpList.add(exp); + } + ("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" + { multiExpr.addExpressionList(primaryExpList); } + )* + | ( LOOKAHEAD(2) "(" { useSelectBrackets = true; } { upsert.setUseValues(false); } @@ -1895,7 +1899,7 @@ String RelObjectNameExt2(): { return tk!=null ? tk.image : result; } } -Table Table() #Table : +Table Table() #TableName : { //String serverName = null, databaseName = null, schemaName = null, tableName = null; List data = new ArrayList(); @@ -3466,10 +3470,17 @@ Expression LikeExpression(Expression leftExpression) #LikeExpression: LikeExpression result = new LikeExpression(); Expression rightExpression = null; Expression escape; + Token token; } { [ { result.setNot(true); } ] ( | { result.setCaseInsensitive(true); } ) rightExpression=SimpleExpression() - [ LOOKAHEAD(2) escape=Expression() { result.setEscape(escape); }] + [ LOOKAHEAD(2) + ( + LOOKAHEAD(2) token = { result.setEscape( new StringValue( token.image ) ); } + | + escape=Expression() { result.setEscape(escape); } + ) + ] { result.setLeftExpression(leftExpression); result.setRightExpression(rightExpression); @@ -4155,7 +4166,7 @@ DateTimeLiteralExpression DateTimeLiteralExpression() : { t= { expr.setValue(t.image); return expr; } } -ArrayConstructor ArrayConstructor(final boolean arrayKeyword) : { +ArrayConstructor ArrayConstructor(boolean arrayKeyword) : { ArrayList expList = new ArrayList(); ArrayConstructor array = new ArrayConstructor(expList, arrayKeyword); Expression exp = null; @@ -5768,6 +5779,7 @@ Drop Drop(): Table name; List dropArgs = new ArrayList(); List funcArgs = null; + boolean useTemporary = false; } { @@ -5775,7 +5787,9 @@ Drop Drop(): ( tk= | - tk= + ( + [ {useTemporary=true;} ] tk= + ) | tk= | @@ -5803,6 +5817,8 @@ Drop Drop(): drop.getTypeToParameters().put("FUNCTION", funcArgs); } + drop.setUsingTemporary(useTemporary); + return drop; } } diff --git a/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java index 0ff94ff8b..3840d0935 100644 --- a/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java @@ -10,8 +10,11 @@ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; /** * @@ -25,4 +28,117 @@ public void testLikeWithEscapeExpressionIssue420() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("select * from dual where a LIKE ?1 ESCAPE ?2", true); } + + @Test + public void testEscapeExpressionIssue1638() throws JSQLParserException { + String sqlStr = "select case \n" + + " when id_portfolio like '%\\_1' escape '\\' then '1'\n" + + " end"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + + Assertions.assertThrows(JSQLParserException.class, new Executable() { + @Override + public void execute() throws Throwable { + CCJSqlParserUtil.parse( + sqlStr + , parser -> parser.withBackslashEscapeCharacter(true) + ); + } + }); + } + + @Test + public void testEscapingIssue1209() throws JSQLParserException { + String sqlStr="INSERT INTO \"a\".\"b\"(\"c\", \"d\", \"e\") VALUES ('c c\\', 'dd', 'ee\\')"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + } + + @Test + public void testEscapingIssue1173() throws JSQLParserException { + String sqlStr="update PARAM_TBL set PARA_DESC = null where PARA_DESC = '\\' and DEFAULT_VALUE = '\\'"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + } + + @Test + public void testEscapingIssue1172() throws JSQLParserException { + String sqlStr="SELECT A ALIA1, CASE WHEN B LIKE 'ABC\\_%' ESCAPE '\\' THEN 'DEF' ELSE 'CCCC' END AS OBJ_SUB_TYPE FROM TABLE2"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + } + + @Test + public void testEscapingIssue832() throws JSQLParserException { + String sqlStr="SELECT * FROM T1 WHERE (name LIKE ? ESCAPE '\\') AND (description LIKE ? ESCAPE '\\')"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + } + + @Test + public void testEscapingIssue827() throws JSQLParserException { + String sqlStr="INSERT INTO my_table (my_column_1, my_column_2) VALUES ('my_value_1\\', 'my_value_2')"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + } + + @Test + public void testEscapingIssue578() throws JSQLParserException { + String sqlStr="SELECT * FROM t1 WHERE UPPER(t1.TIPCOR_A8) like ? ESCAPE '' ORDER BY PERFILB2||TRANSLATE(UPPER(AP1SOL10 || ' ' || AP2SOL10 || ',' || NOMSOL10), '?', 'A') asc"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + } + + @Test + public void testEscapingIssue875() throws JSQLParserException { + String sqlStr="insert into standard_table(gmt_create, gmt_modified, config_name, standard_code) values (now(), now(), null, 'if \n" + + "@fac.sql_type in \n" + + "[ ''UPDATE'', ''DELETE'', ''INSERT'', ''INSERT_SELECT''] \n" + + "then \n" + + "@act.allow_submit \n" + + "end \n" + + "')" + ; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(false) + ); + + sqlStr="insert into standard_table(gmt_create, gmt_modified, config_name, standard_code) values (now(), now(), null, 'if \n" + + "@fac.sql_type in \n" + + "[ \\'UPDATE\\', \\'DELETE\\', \\'INSERT\\', \\'INSERT_SELECT\\'] \n" + + "then \n" + + "@act.allow_submit \n" + + "end \n" + + "')" + ; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java index 60ab4a28e..faeb75b92 100644 --- a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java @@ -9,17 +9,19 @@ */ package net.sf.jsqlparser.statement.builder; -import java.util.List; import net.sf.jsqlparser.expression.AnyType; import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperatorType; import net.sf.jsqlparser.schema.Sequence.ParameterType; import net.sf.jsqlparser.statement.ExplainStatement.OptionType; import net.sf.jsqlparser.statement.create.table.ColDataType; import net.sf.jsqlparser.statement.select.SubSelect; -import static net.sf.jsqlparser.test.TestUtils.*; import net.sf.jsqlparser.util.ReflectionTestUtils; import org.junit.jupiter.api.Test; +import java.util.List; + +import static net.sf.jsqlparser.test.TestUtils.asList; + /** * Testing of setters, getters, with-/add-methods by calling them with random parameter-values *

    @@ -148,7 +150,7 @@ public class ReflectionModelTest { new net.sf.jsqlparser.statement.drop.Drop(), new net.sf.jsqlparser.statement.execute.Execute(), new net.sf.jsqlparser.statement.grant.Grant(), new net.sf.jsqlparser.statement.insert.Insert(), new net.sf.jsqlparser.statement.merge.Merge(), - new net.sf.jsqlparser.statement.merge.MergeUpdate(), new net.sf.jsqlparser.statement.replace.Replace(), + new net.sf.jsqlparser.statement.merge.MergeUpdate(), new net.sf.jsqlparser.statement.select.AllColumns(), new net.sf.jsqlparser.statement.select.AllTableColumns(), new net.sf.jsqlparser.statement.select.Distinct(), new net.sf.jsqlparser.statement.select.ExceptOp(), diff --git a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java index 7087dc2b3..062374f39 100644 --- a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java @@ -132,4 +132,10 @@ public void testDropFunctionWithNameAndType() throws JSQLParserException { public void testDropFunctionWithNameAndParameterizedType() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("DROP FUNCTION myFunc(amount integer, name varchar(255))"); } + + @Test + void dropTemporaryTableTestIssue1712() throws JSQLParserException { + String sqlStr="drop temporary table if exists tmp_MwYT8N0z"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java index aa39c7c83..c99c624bc 100644 --- a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java @@ -309,7 +309,12 @@ public void testModifierPriority3() throws JSQLParserException { @Test public void testIssue223() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("INSERT INTO user VALUES (2001, '\\'Clark\\'', 'Kent')"); + String sqlStr="INSERT INTO user VALUES (2001, '\\'Clark\\'', 'Kent')"; + assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/replace/ReplaceTest.java b/src/test/java/net/sf/jsqlparser/statement/replace/ReplaceTest.java index c729ff6a7..180bee0ff 100644 --- a/src/test/java/net/sf/jsqlparser/statement/replace/ReplaceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/replace/ReplaceTest.java @@ -9,67 +9,60 @@ */ package net.sf.jsqlparser.statement.replace; -import java.io.StringReader; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.statement.select.SubSelect; +import net.sf.jsqlparser.statement.upsert.Upsert; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; public class ReplaceTest { - - private static final CCJSqlParserManager PARSER_MANAGER = new CCJSqlParserManager(); - @Test public void testReplaceSyntax1() throws JSQLParserException { String statement = "REPLACE mytable SET col1='as', col2=?, col3=565"; - Replace replace = (Replace) PARSER_MANAGER.parse(new StringReader(statement)); - assertEquals("mytable", replace.getTable().getName()); - assertEquals(3, replace.getColumns().size()); - assertEquals("col1", ((Column) replace.getColumns().get(0)).getColumnName()); - assertEquals("col2", ((Column) replace.getColumns().get(1)).getColumnName()); - assertEquals("col3", ((Column) replace.getColumns().get(2)).getColumnName()); - assertEquals("as", ((StringValue) replace.getExpressions().get(0)).getValue()); - assertTrue(replace.getExpressions().get(1) instanceof JdbcParameter); - assertEquals(565, ((LongValue) replace.getExpressions().get(2)).getValue()); - assertEquals(statement, "" + replace); - + Upsert upsert = (Upsert) TestUtils.assertSqlCanBeParsedAndDeparsed(statement, true); + assertEquals("mytable", upsert.getTable().getName()); + assertEquals(3, upsert.getColumns().size()); + assertEquals("col1", ((Column) upsert.getColumns().get(0)).getColumnName()); + assertEquals("col2", ((Column) upsert.getColumns().get(1)).getColumnName()); + assertEquals("col3", ((Column) upsert.getColumns().get(2)).getColumnName()); + assertEquals("as", ((StringValue) upsert.getSetExpressions().get(0)).getValue()); + assertTrue( upsert.getSetExpressions().get(1) instanceof JdbcParameter); + assertEquals(565, ((LongValue) upsert.getSetExpressions().get(2)).getValue()); + assertEquals(statement, "" + upsert); } @Test public void testReplaceSyntax2() throws JSQLParserException { String statement = "REPLACE mytable (col1, col2, col3) VALUES ('as', ?, 565)"; - Replace replace = (Replace) PARSER_MANAGER.parse(new StringReader(statement)); + Upsert replace = (Upsert) TestUtils.assertSqlCanBeParsedAndDeparsed(statement, true); assertEquals("mytable", replace.getTable().getName()); assertEquals(3, replace.getColumns().size()); assertEquals("col1", ((Column) replace.getColumns().get(0)).getColumnName()); assertEquals("col2", ((Column) replace.getColumns().get(1)).getColumnName()); assertEquals("col3", ((Column) replace.getColumns().get(2)).getColumnName()); - assertEquals("as", ((StringValue) ((ExpressionList) replace.getItemsList()).getExpressions(). - get(0)).getValue()); - assertTrue(((ExpressionList) replace.getItemsList()).getExpressions().get(1) instanceof JdbcParameter); - assertEquals(565, ((LongValue) ((ExpressionList) replace.getItemsList()).getExpressions(). - get(2)).getValue()); + assertEquals("as", ((StringValue) replace.getSetExpressions().get(0) ).getValue() ); + assertTrue( replace.getSetExpressions().get(1) instanceof JdbcParameter); + assertEquals(565, ((LongValue) replace.getSetExpressions().get(2)).getValue()); assertEquals(statement, "" + replace); } @Test public void testReplaceSyntax3() throws JSQLParserException { String statement = "REPLACE mytable (col1, col2, col3) SELECT * FROM mytable3"; - Replace replace = (Replace) PARSER_MANAGER.parse(new StringReader(statement)); + Upsert replace = (Upsert) TestUtils.assertSqlCanBeParsedAndDeparsed(statement, true); assertEquals("mytable", replace.getTable().getName()); assertEquals(3, replace.getColumns().size()); assertEquals("col1", ((Column) replace.getColumns().get(0)).getColumnName()); assertEquals("col2", ((Column) replace.getColumns().get(1)).getColumnName()); assertEquals("col3", ((Column) replace.getColumns().get(2)).getColumnName()); - assertTrue(replace.getItemsList() instanceof SubSelect); + assertNotNull(replace.getSelect()); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java new file mode 100644 index 000000000..cd8e41c95 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java @@ -0,0 +1,22 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +public class SQLiteTest { + @Test + void testInsertOrReplaceUpsert() throws JSQLParserException { + String sqlString="INSERT OR REPLACE INTO kjobLocks VALUES (?, ?, ?)"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlString, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java index dd7090fc3..b27cf993b 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -42,6 +42,7 @@ import static net.sf.jsqlparser.test.TestUtils.*; import net.sf.jsqlparser.test.MemoryLeakVerifier; +import net.sf.jsqlparser.test.TestUtils; import org.apache.commons.io.IOUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -3066,29 +3067,53 @@ public void testIssue162_doubleUserVar() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT @@SPID AS ID, SYSTEM_USER AS \"Login Name\", USER AS \"User Name\""); } - @Test - public void testIssue167_singleQuoteEscape() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT 'a'"); - assertSqlCanBeParsedAndDeparsed("SELECT ''''"); - assertSqlCanBeParsedAndDeparsed("SELECT '\\''"); - assertSqlCanBeParsedAndDeparsed("SELECT 'ab''ab'"); - assertSqlCanBeParsedAndDeparsed("SELECT 'ab\\'ab'"); + @ParameterizedTest + @ValueSource(strings = { + "SELECT 'a'" + , "SELECT ''''" + , "SELECT '\\''" + , "SELECT 'ab''ab'" + , "SELECT 'ab\\'ab'" + }) + public void testIssue167_singleQuoteEscape(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); } - @Test - public void testIssue167_singleQuoteEscape2() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT '\\'''"); - assertSqlCanBeParsedAndDeparsed("SELECT '\\\\\\''"); + @ParameterizedTest + @ValueSource(strings = { + "SELECT '\\'''" + , "SELECT '\\\\\\''" + }) + public void testIssue167_singleQuoteEscape2(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); } @Test public void testIssue77_singleQuoteEscape2() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT 'test\\'' FROM dual"); + String sqlStr ="SELECT 'test\\'' FROM dual"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); } @Test public void testIssue223_singleQuoteEscape() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT '\\'test\\''"); + String sqlStr = "SELECT '\\'test\\''"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java index f06de1401..fb830110d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java @@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; public class UpdateTest { @@ -79,7 +80,13 @@ public void testUpdateWithSelect2() throws JSQLParserException { @Test public void testUpdateIssue167_SingleQuotes() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("UPDATE tablename SET NAME = 'Customer 2', ADDRESS = 'Address \\' ddad2', AUTH_KEY = 'samplekey' WHERE ID = 2"); + String sqlStr = "UPDATE tablename SET NAME = 'Customer 2', ADDRESS = 'Address \\' ddad2', AUTH_KEY = 'samplekey' WHERE ID = 2"; + + assertSqlCanBeParsedAndDeparsed( + sqlStr + , true + , parser -> parser.withBackslashEscapeCharacter(true) + ); } @Test diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index 261688e5a..72645c4b0 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -9,11 +9,6 @@ */ package net.sf.jsqlparser.util; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.util.Iterator; -import java.util.List; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.OracleHint; @@ -29,18 +24,24 @@ import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.merge.MergeInsert; -import net.sf.jsqlparser.statement.replace.Replace; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.simpleparsing.CCJSqlParserManagerTest; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; import net.sf.jsqlparser.test.TestException; +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.util.Iterator; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; public class TablesNamesFinderTest { @@ -275,7 +276,7 @@ public void testGetTableListFromReplace() throws Exception { String sql = "REPLACE INTO MY_TABLE1 (a) VALUES ((SELECT a from MY_TABLE2 WHERE a = 1))"; net.sf.jsqlparser.statement.Statement statement = pm.parse(new StringReader(sql)); - Replace replaceStatement = (Replace) statement; + Upsert replaceStatement = (Upsert) statement; TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); List tableList = tablesNamesFinder.getTableList(replaceStatement); assertEquals(2, tableList.size()); diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidatorTest.java index ff7c39f82..25f25c7d1 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/ReplaceValidatorTest.java @@ -9,7 +9,6 @@ */ package net.sf.jsqlparser.util.validation.validator; -import java.util.Arrays; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.util.validation.ValidationTestAsserts; @@ -17,6 +16,8 @@ import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; import org.junit.jupiter.api.Test; +import java.util.Arrays; + public class ReplaceValidatorTest extends ValidationTestAsserts { @Test @@ -33,7 +34,7 @@ public void testValidateReplaceNotAllowed() throws JSQLParserException { for (String sql : Arrays.asList("REPLACE mytable SET col1='as', col2=?, col3=565", "REPLACE mytable (col1, col2, col3) VALUES ('as', ?, 565)", "REPLACE mytable (col1, col2, col3) SELECT * FROM mytable3")) { - validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), Feature.replace); + validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), Feature.upsert); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/UpsertValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/UpsertValidatorTest.java index bdce72845..2e5c3b5f7 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/UpsertValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/UpsertValidatorTest.java @@ -9,16 +9,19 @@ */ package net.sf.jsqlparser.util.validation.validator; -import java.util.Arrays; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.util.validation.ValidationTestAsserts; import net.sf.jsqlparser.util.validation.feature.DatabaseType; import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import java.util.Arrays; + public class UpsertValidatorTest extends ValidationTestAsserts { @Test + @Disabled public void testValidationExecuteNotSupported() throws Exception { for (String sql : Arrays.asList("UPSERT INTO TEST (NAME, ID) VALUES ('foo', 123)", "UPSERT INTO TEST (ID, COUNTER) VALUES (123, 0) ON DUPLICATE KEY UPDATE COUNTER = COUNTER + 1", diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql index 5a3b59e59..2564f35d4 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql @@ -14,4 +14,5 @@ insert into t2 ( x, y ) values ( s.nextval, created ) select object_id, created from all_objects ---@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql index 927a36124..3435fa022 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql @@ -23,4 +23,5 @@ else values (empno,ename,job,mgr,sal,deptno) select * from emp ---@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/numbers01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/numbers01.sql index cf909d5db..38a5cd90d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/numbers01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/numbers01.sql @@ -32,4 +32,5 @@ select 25 from dual ---@FAILURE: Encountered unexpected token: "d" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "d" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: select 25,+6.34,0.5,25e-03,-1,25f,+6.34 f,0.5 d,-1d,1.,.5,(sysdate-1d),sysdate-1m,sysdate-1dm,1.-+.5,1.+.5,1.+.5 d,1.+.5 dm,1. d,1. m,.5 m,.5 dm from dual recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file