diff --git a/build.gradle b/build.gradle index 1f0924c03..e9401a2c0 100644 --- a/build.gradle +++ b/build.gradle @@ -114,8 +114,10 @@ dependencies { xmlDoclet 'com.manticore-projects.tools:xml-doclet:+' // enforce latest version of JavaCC - testImplementation 'net.java.dev.javacc:javacc:+' - javacc 'net.java.dev.javacc:javacc:+' + testImplementation 'org.javacc:core:8.0.1' + testImplementation 'org.javacc.generator:java:8.0.1' + javacc 'org.javacc:core:8.0.1' + javacc 'org.javacc.generator:java:8.0.1' } diff --git a/pom.xml b/pom.xml index 98d67faa3..d988080b8 100644 --- a/pom.xml +++ b/pom.xml @@ -27,10 +27,16 @@ - net.java.dev.javacc - javacc - [7.0.13,) - test + org.javacc + core + 8.0.1 + pom + + + org.javacc.generator + java + 8.0.1 + pom commons-io @@ -59,7 +65,7 @@ org.assertj assertj-core - [3.25.3,) + 3.25.3 test @@ -216,17 +222,20 @@ jjtree-javacc - UTF-8 - false - 1.8 + java - net.java.dev.javacc - javacc - [7.0.13,) + org.javacc.generator + java + 8.0.1 + + + org.javacc + core + 8.0.1 diff --git a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java index 3510fe6d3..adc1b5fbc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java @@ -39,7 +39,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { @Override public String toString() { - return type.name() + " " + value; + return type!=null ? type.name() + " " + value : value; } public DateTimeLiteralExpression withValue(String value) { diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java index 2abbae1db..5efb04359 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java @@ -11,7 +11,7 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.parser.SimpleNode; +import net.sf.jsqlparser.parser.Node; import java.io.Serializable; import java.util.ArrayList; @@ -24,7 +24,7 @@ */ public class ExpressionList extends ArrayList implements Expression, Serializable { - private transient SimpleNode node; + private transient Node node; public ExpressionList(Collection expressions) { addAll(expressions); @@ -96,12 +96,12 @@ public String toString() { @Override - public SimpleNode getASTNode() { + public Node getASTNode() { return node; } @Override - public void setASTNode(SimpleNode node) { + public void setASTNode(Node node) { this.node = node; } diff --git a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java index 6b4993ed9..53eb89bb7 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java @@ -13,7 +13,7 @@ public interface ASTNodeAccess extends Serializable { - SimpleNode getASTNode(); + Node getASTNode(); - void setASTNode(SimpleNode node); + void setASTNode(Node node); } diff --git a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java index fb26ff2c2..6ef61996b 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java @@ -14,15 +14,15 @@ public class ASTNodeAccessImpl implements ASTNodeAccess { - private transient SimpleNode node; + private transient Node node; @Override - public SimpleNode getASTNode() { + public Node getASTNode() { return node; } @Override - public void setASTNode(SimpleNode node) { + public void setASTNode(Node node) { this.node = node; } @@ -30,10 +30,10 @@ public StringBuilder appendTo(StringBuilder builder) { // don't add spaces around the following punctuation final Set punctuation = new TreeSet<>(Set.of(".", "[", "]")); - SimpleNode simpleNode = getASTNode(); - if (simpleNode != null) { - Token token = simpleNode.jjtGetFirstToken(); - Token lastToken = simpleNode.jjtGetLastToken(); + Node Node = getASTNode(); + if (Node != null) { + Token token = Node.jjtGetFirstToken(); + Token lastToken = Node.jjtGetLastToken(); Token prevToken = null; while (token.next != null && token.absoluteEnd <= lastToken.absoluteEnd) { if (!punctuation.contains(token.image) @@ -49,18 +49,18 @@ public StringBuilder appendTo(StringBuilder builder) { } public ASTNodeAccess getParent() { - SimpleNode parent = (SimpleNode) node.jjtGetParent(); + Node parent = (Node) node.jjtGetParent(); while (parent.jjtGetValue() == null) { - parent = (SimpleNode) parent.jjtGetParent(); + parent = (Node) parent.jjtGetParent(); } return ASTNodeAccess.class.cast(parent.jjtGetValue()); } public T getParent(Class clazz) { - SimpleNode parent = (SimpleNode) node.jjtGetParent(); + Node parent = (Node) node.jjtGetParent(); while (parent.jjtGetValue() == null || !clazz.isInstance(parent.jjtGetValue())) { - parent = (SimpleNode) parent.jjtGetParent(); + parent = (Node) parent.jjtGetParent(); } return clazz.cast(parent.jjtGetValue()); diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java deleted file mode 100644 index 6e6019a64..000000000 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ /dev/null @@ -1,425 +0,0 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2021 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.parser; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ParserKeywordsUtils { - public final static CharsetEncoder CHARSET_ENCODER = StandardCharsets.US_ASCII.newEncoder(); - - public final static int RESTRICTED_FUNCTION = 1; - public final static int RESTRICTED_SCHEMA = 2; - public final static int RESTRICTED_TABLE = 4; - public final static int RESTRICTED_COLUMN = 8; - public final static int RESTRICTED_EXPRESSION = 16; - public final static int RESTRICTED_ALIAS = 32; - public final static int RESTRICTED_SQL2016 = 64; - - public final static int RESTRICTED_JSQLPARSER = 128 - | RESTRICTED_FUNCTION - | RESTRICTED_SCHEMA - | RESTRICTED_TABLE - | RESTRICTED_COLUMN - | RESTRICTED_EXPRESSION - | RESTRICTED_ALIAS - | RESTRICTED_SQL2016; - - - // Classification follows http://www.h2database.com/html/advanced.html#keywords - public final static Object[][] ALL_RESERVED_KEYWORDS = { - {"ABSENT", RESTRICTED_JSQLPARSER}, - {"ALL", RESTRICTED_SQL2016}, - {"AND", RESTRICTED_SQL2016}, - {"ANY", RESTRICTED_JSQLPARSER}, - {"AS", RESTRICTED_SQL2016}, - {"BETWEEN", RESTRICTED_SQL2016}, - {"BOTH", RESTRICTED_SQL2016}, - {"CASEWHEN", RESTRICTED_ALIAS}, - {"CHECK", RESTRICTED_SQL2016}, - {"CONNECT", RESTRICTED_ALIAS}, - {"CONNECT_BY_ROOT", RESTRICTED_JSQLPARSER}, - {"PRIOR", RESTRICTED_JSQLPARSER}, - {"CONSTRAINT", RESTRICTED_SQL2016}, - {"CREATE", RESTRICTED_ALIAS}, - {"CROSS", RESTRICTED_SQL2016}, - {"CURRENT", RESTRICTED_JSQLPARSER}, - {"DEFAULT", RESTRICTED_ALIAS}, - {"DISTINCT", RESTRICTED_SQL2016}, - {"DOUBLE", RESTRICTED_ALIAS}, - {"ELSE", RESTRICTED_JSQLPARSER}, - {"EXCEPT", RESTRICTED_SQL2016}, - {"EXCLUDES", RESTRICTED_JSQLPARSER}, - {"EXISTS", RESTRICTED_SQL2016}, - {"EXTEND", RESTRICTED_JSQLPARSER}, - {"FALSE", RESTRICTED_SQL2016}, - {"FETCH", RESTRICTED_SQL2016}, - {"FINAL", RESTRICTED_JSQLPARSER}, - {"FOR", RESTRICTED_SQL2016}, - {"FORCE", RESTRICTED_SQL2016}, - {"FOREIGN", RESTRICTED_SQL2016}, - {"FROM", RESTRICTED_SQL2016}, - {"FULL", RESTRICTED_SQL2016}, - {"GLOBAL", RESTRICTED_ALIAS}, - {"GROUP", RESTRICTED_SQL2016}, - {"GROUPING", RESTRICTED_ALIAS}, - {"QUALIFY", RESTRICTED_ALIAS}, - {"HAVING", RESTRICTED_SQL2016}, - {"IF", RESTRICTED_SQL2016}, - {"IIF", RESTRICTED_ALIAS}, - {"IGNORE", RESTRICTED_ALIAS}, - {"ILIKE", RESTRICTED_SQL2016}, - {"IN", RESTRICTED_SQL2016}, - {"INCLUDES", RESTRICTED_JSQLPARSER}, - {"INNER", RESTRICTED_SQL2016}, - {"INTERSECT", RESTRICTED_SQL2016}, - {"INTERVAL", RESTRICTED_SQL2016}, - {"INTO", RESTRICTED_JSQLPARSER}, - {"IS", RESTRICTED_SQL2016}, - {"JOIN", RESTRICTED_JSQLPARSER}, - {"LATERAL", RESTRICTED_SQL2016}, - {"LEFT", RESTRICTED_SQL2016}, - {"LIKE", RESTRICTED_SQL2016}, - {"LIMIT", RESTRICTED_SQL2016}, - {"MINUS", RESTRICTED_SQL2016}, - {"NATURAL", RESTRICTED_SQL2016}, - {"NOCYCLE", RESTRICTED_JSQLPARSER}, - {"NOT", RESTRICTED_SQL2016}, - {"NULL", RESTRICTED_SQL2016}, - {"OFFSET", RESTRICTED_SQL2016}, - {"ON", RESTRICTED_SQL2016}, - {"ONLY", RESTRICTED_JSQLPARSER}, - {"OPTIMIZE", RESTRICTED_ALIAS}, - {"OR", RESTRICTED_SQL2016}, - {"ORDER", RESTRICTED_SQL2016}, - {"OUTER", RESTRICTED_JSQLPARSER}, - {"OUTPUT", RESTRICTED_JSQLPARSER}, - {"OPTIMIZE ", RESTRICTED_JSQLPARSER}, - {"OVERWRITE ", RESTRICTED_JSQLPARSER}, - {"PIVOT", RESTRICTED_JSQLPARSER}, - {"PREFERRING", RESTRICTED_JSQLPARSER}, - {"PRIOR", RESTRICTED_ALIAS}, - {"PROCEDURE", RESTRICTED_ALIAS}, - {"PUBLIC", RESTRICTED_ALIAS}, - {"RETURNING", RESTRICTED_JSQLPARSER}, - {"RIGHT", RESTRICTED_SQL2016}, - {"SAMPLE", RESTRICTED_ALIAS}, - {"SEL", RESTRICTED_ALIAS}, - {"SELECT", RESTRICTED_ALIAS}, - {"SEMI", RESTRICTED_JSQLPARSER}, - {"SET", RESTRICTED_JSQLPARSER}, - {"SOME", RESTRICTED_JSQLPARSER}, - {"START", RESTRICTED_JSQLPARSER}, - {"TABLES", RESTRICTED_ALIAS}, - {"TOP", RESTRICTED_SQL2016}, - {"TRAILING", RESTRICTED_SQL2016}, - {"TRUE", RESTRICTED_SQL2016}, - {"UNBOUNDED", RESTRICTED_JSQLPARSER}, - {"UNION", RESTRICTED_SQL2016}, - {"UNIQUE", RESTRICTED_SQL2016}, - {"UNKNOWN", RESTRICTED_SQL2016}, - {"UNPIVOT", RESTRICTED_JSQLPARSER}, - {"USE", RESTRICTED_JSQLPARSER}, - {"USING", RESTRICTED_SQL2016}, - {"SQL_CACHE", RESTRICTED_JSQLPARSER}, - {"SQL_CALC_FOUND_ROWS", RESTRICTED_JSQLPARSER}, - {"SQL_NO_CACHE", RESTRICTED_JSQLPARSER}, - {"STRAIGHT_JOIN", RESTRICTED_JSQLPARSER}, - {"TABLESAMPLE", RESTRICTED_ALIAS}, - {"VALUE", RESTRICTED_JSQLPARSER}, - {"VALUES", RESTRICTED_SQL2016}, - {"VARYING", RESTRICTED_JSQLPARSER}, - {"WHEN", RESTRICTED_SQL2016}, - {"WHERE", RESTRICTED_SQL2016}, - {"WINDOW", RESTRICTED_SQL2016}, - {"WITH", RESTRICTED_SQL2016}, - {"XOR", RESTRICTED_JSQLPARSER}, - {"XMLSERIALIZE", RESTRICTED_JSQLPARSER}, - - // add keywords from the composite token definitions: - // tk= | tk= | tk= - // we will use the composite tokens instead, which are always hit first before the - // simple keywords - // @todo: figure out a way to remove these composite tokens, as they do more harm than - // good - {"SEL", RESTRICTED_JSQLPARSER}, - {"SELECT", RESTRICTED_JSQLPARSER}, - {"DATE", RESTRICTED_JSQLPARSER}, - {"TIME", RESTRICTED_JSQLPARSER}, - {"TIMESTAMP", RESTRICTED_JSQLPARSER}, - {"YEAR", RESTRICTED_JSQLPARSER}, - {"MONTH", RESTRICTED_JSQLPARSER}, - {"DAY", RESTRICTED_JSQLPARSER}, - {"HOUR", RESTRICTED_JSQLPARSER}, - {"MINUTE", RESTRICTED_JSQLPARSER}, - {"SECOND", RESTRICTED_JSQLPARSER}, - {"SUBSTR", RESTRICTED_JSQLPARSER}, - {"SUBSTRING", RESTRICTED_JSQLPARSER}, - {"TRIM", RESTRICTED_JSQLPARSER}, - {"POSITION", RESTRICTED_JSQLPARSER}, - {"OVERLAY", RESTRICTED_JSQLPARSER}, - {"NEXTVAL", RESTRICTED_COLUMN}, - - // @todo: Object Names should not start with Hex-Prefix, we shall not find that Token - {"0x", RESTRICTED_JSQLPARSER} - }; - - @SuppressWarnings({"PMD.ExcessiveMethodLength"}) - public static List getReservedKeywords(int restriction) { - ArrayList keywords = new ArrayList<>(); - for (Object[] data : ALL_RESERVED_KEYWORDS) { - int value = (int) data[1]; - - // test if bit is not set - if ((value & restriction) == restriction || (restriction & value) == value) { - keywords.add((String) data[0]); - } - } - - return keywords; - } - - /** - * @param args with: Grammar File, Keyword Documentation File - * @throws Exception - */ - public static void main(String[] args) throws Exception { - if (args.length < 2) { - throw new IllegalArgumentException("No filename provided aS context ARGS[0]"); - } - - File grammarFile = new File(args[0]); - if (grammarFile.exists() && grammarFile.canRead() && grammarFile.canWrite()) { - buildGrammarForRelObjectName(grammarFile); - buildGrammarForRelObjectNameWithoutValue(grammarFile); - } else { - throw new FileNotFoundException("Can't read file " + args[0]); - } - - File keywordDocumentationFile = new File(args[1]); - keywordDocumentationFile.createNewFile(); - if (keywordDocumentationFile.canWrite()) { - writeKeywordsDocumentationFile(keywordDocumentationFile); - } else { - throw new FileNotFoundException("Can't read file " + args[1]); - } - } - - public static TreeSet getAllKeywordsUsingRegex(File file) throws IOException { - Pattern tokenBlockPattern = Pattern.compile( - "TOKEN\\s*:\\s*/\\*.*\\*/*(?:\\r?\\n|\\r)\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}", - Pattern.MULTILINE); - Pattern tokenStringValuePattern = Pattern.compile("\"(\\w{2,})\"", Pattern.MULTILINE); - - TreeSet allKeywords = new TreeSet<>(); - - Path path = file.toPath(); - Charset charset = Charset.defaultCharset(); - String content = new String(Files.readAllBytes(path), charset); - - Matcher tokenBlockmatcher = tokenBlockPattern.matcher(content); - while (tokenBlockmatcher.find()) { - String tokenBlock = tokenBlockmatcher.group(0); - // remove single and multiline comments - tokenBlock = tokenBlock.replaceAll("(?sm)((\\/\\*.*?\\*\\/)|(\\/\\/.*?$))", ""); - for (String tokenDefinition : getTokenDefinitions(tokenBlock)) { - // check if token definition is private - if (tokenDefinition.matches("(?sm)^<\\s*[^#].*")) { - Matcher tokenStringValueMatcher = - tokenStringValuePattern.matcher(tokenDefinition); - while (tokenStringValueMatcher.find()) { - String tokenValue = tokenStringValueMatcher.group(1); - // test if pure US-ASCII - if (CHARSET_ENCODER.canEncode(tokenValue) && tokenValue.matches("\\w+")) { - allKeywords.add(tokenValue); - } - } - } - } - } - return allKeywords; - } - - @SuppressWarnings({"PMD.EmptyWhileStmt"}) - private static List getTokenDefinitions(String tokenBlock) { - List tokenDefinitions = new ArrayList<>(); - int level = 0; - char openChar = '<'; - char closeChar = '>'; - char[] tokenBlockChars = tokenBlock.toCharArray(); - int tokenDefinitionStart = -1; - for (int i = 0; i < tokenBlockChars.length; ++i) { - if (isQuotationMark(i, tokenBlockChars)) { - // skip everything inside quotation marks - while (!isQuotationMark(++i, tokenBlockChars)) { - // skip until quotation ends - } - } - - char character = tokenBlockChars[i]; - if (character == openChar) { - if (level == 0) { - tokenDefinitionStart = i; - } - - ++level; - } else if (character == closeChar) { - --level; - - if (level == 0 && tokenDefinitionStart >= 0) { - tokenDefinitions.add(tokenBlock.substring(tokenDefinitionStart, i + 1)); - tokenDefinitionStart = -1; - } - } - } - - return tokenDefinitions; - } - - private static boolean isQuotationMark(int index, char[] str) { - if (str[index] == '\"') { - // check if quotation is escaped - if (index > 0 && str[index - 1] == '\\') { - return index > 1 && str[index - 2] == '\\'; - } - - return true; - } - - return false; - } - - public static void buildGrammarForRelObjectNameWithoutValue(File file) throws Exception { - Pattern methodBlockPattern = Pattern.compile( - "String\\W*RelObjectNameWithoutValue\\W*\\(\\W*\\)\\W*:\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}", - Pattern.MULTILINE); - - TreeSet allKeywords = getAllKeywords(file); - - for (String reserved : getReservedKeywords(RESTRICTED_JSQLPARSER)) { - allKeywords.remove(reserved); - } - - StringBuilder builder = new StringBuilder(); - builder.append("String RelObjectNameWithoutValue() :\n" - + "{ Token tk = null; }\n" - + "{\n" - // @todo: find a way to avoid those hardcoded compound tokens - + " ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= \n" - + " "); - - for (String keyword : allKeywords) { - builder.append(" | tk=\"").append(keyword).append("\""); - } - - builder.append(" )\n" + " { return tk.image; }\n" + "}"); - - replaceInFile(file, methodBlockPattern, builder.toString()); - } - - public static void buildGrammarForRelObjectName(File file) throws Exception { - // Pattern pattern = - // Pattern.compile("String\\W*RelObjectName\\W*\\(\\W*\\)\\W*:\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}", - // Pattern.MULTILINE); - TreeSet allKeywords = new TreeSet<>(); - for (String reserved : getReservedKeywords(RESTRICTED_ALIAS)) { - allKeywords.add(reserved); - } - - for (String reserved : getReservedKeywords(RESTRICTED_JSQLPARSER & ~RESTRICTED_ALIAS)) { - allKeywords.remove(reserved); - } - - StringBuilder builder = new StringBuilder(); - builder.append("String RelObjectName() :\n" - + "{ Token tk = null; String result = null; }\n" - + "{\n" - + " (result = RelObjectNameWithoutValue()\n" - + " "); - - for (String keyword : allKeywords) { - builder.append(" | tk=\"").append(keyword).append("\""); - } - - builder.append(" )\n" + " { return tk!=null ? tk.image : result; }\n" + "}"); - - // @todo: Needs fine-tuning, we are not replacing this part yet - // replaceInFile(file, pattern, builder.toString()); - } - - public static TreeSet getAllKeywords(File file) throws Exception { - return getAllKeywordsUsingRegex(file); - } - - private static void replaceInFile(File file, Pattern pattern, String replacement) - throws IOException { - Path path = file.toPath(); - Charset charset = Charset.defaultCharset(); - - String content = new String(Files.readAllBytes(path), charset); - content = pattern.matcher(content).replaceAll(replacement); - Files.write(file.toPath(), content.getBytes(charset)); - } - - public static String rightPadding(String input, char ch, int length) { - return String.format("%" + (-length) + "s", input).replace(' ', ch); - } - - public static void writeKeywordsDocumentationFile(File file) throws IOException { - StringBuilder builder = new StringBuilder(); - builder.append("***********************\n"); - builder.append("Restricted Keywords\n"); - builder.append("***********************\n"); - builder.append("\n"); - - builder.append( - "The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and must not be used for **Naming Objects**: \n"); - builder.append("\n"); - - builder.append("+----------------------+-------------+-----------+\n"); - builder.append("| **Keyword** | JSQL Parser | SQL:2016 |\n"); - builder.append("+----------------------+-------------+-----------+\n"); - - for (Object[] keywordDefinition : ALL_RESERVED_KEYWORDS) { - builder.append("| ").append(rightPadding(keywordDefinition[0].toString(), ' ', 20)) - .append(" | "); - - int value = (int) keywordDefinition[1]; - int restriction = RESTRICTED_JSQLPARSER; - String s = (value & restriction) == restriction || (restriction & value) == value - ? "Yes" - : ""; - builder.append(rightPadding(s, ' ', 11)).append(" | "); - - restriction = RESTRICTED_SQL2016; - s = (value & restriction) == restriction || (restriction & value) == value - ? "Yes" - : ""; - builder.append(rightPadding(s, ' ', 9)).append(" | "); - - builder.append("\n"); - builder.append("+----------------------+-------------+-----------+\n"); - } - try (FileWriter fileWriter = new FileWriter(file)) { - fileWriter.append(builder); - fileWriter.flush(); - } - } -} diff --git a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java index b96578e01..19ce1d346 100644 --- a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java +++ b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java @@ -1,30 +1,22 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2019 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ +/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 8.0.0 */ package net.sf.jsqlparser.parser; -import java.io.IOException; +/** + * An implementation of interface CharStream, where the stream is assumed to + * contain only ASCII characters (without unicode processing). + */ -@SuppressWarnings({"PMD.MethodNamingConventions", "PMD.CyclomaticComplexity"}) public class SimpleCharStream { - /** * Whether parser is static. */ - @SuppressWarnings("checkstyle:constantname") public static final boolean staticFlag = false; /** * Position in buffer. */ public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; + protected int[] bufline; + protected int[] bufcolumn; protected int column = 0; protected int line = 1; protected boolean prevCharIsCR = false; @@ -40,52 +32,30 @@ public class SimpleCharStream { int bufsize; int available; int tokenBegin; - private boolean isStringProvider; /** - * Constructor - * - * @param dstream - * @param startline - * @param startcolumn - * @param buffersize + * Constructor. */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn, int buffersize) { + public SimpleCharStream(Provider dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; - isStringProvider = dstream instanceof StringProvider; line = startline; column = startcolumn - 1; - if (isStringProvider) { - int bs = ((StringProvider) inputStream)._string.length(); - available = bufsize = bs; - bufline = new int[bs]; - bufcolumn = new int[bs]; - } else { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; } /** - * Constructor - * - * @param dstream - * @param startline - * @param startcolumn + * Constructor. */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn) { + public SimpleCharStream(Provider dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } /** - * Constructor - * - * @param dstream + * Constructor. */ public SimpleCharStream(Provider dstream) { this(dstream, 1, 1, 4096); @@ -103,10 +73,10 @@ public final int getAbsoluteTokenBegin() { return absoluteTokenBegin; } - protected void ExpandBuff(boolean wrapAround) throws IOException { + protected void ExpandBuff(boolean wrapAround) { char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; + int[] newbufline = new int[bufsize + 2048]; + int[] newbufcolumn = new int[bufsize + 2048]; try { if (wrapAround) { @@ -122,8 +92,9 @@ protected void ExpandBuff(boolean wrapAround) throws IOException { System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); bufcolumn = newbufcolumn; - maxNextCharInd = bufpos += bufsize - tokenBegin; - } else { + maxNextCharInd = (bufpos += (bufsize - tokenBegin)); + } + else { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); buffer = newbuffer; @@ -133,76 +104,72 @@ protected void ExpandBuff(boolean wrapAround) throws IOException { System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); bufcolumn = newbufcolumn; - maxNextCharInd = bufpos -= tokenBegin; + maxNextCharInd = (bufpos -= tokenBegin); } } catch (Throwable t) { - throw new IOException("Errow expanding the buffer.", t); + throw new Error(t.getMessage()); } + bufsize += 2048; available = bufsize; tokenBegin = 0; } - protected void FillBuff() throws IOException { - if (!isStringProvider && maxNextCharInd == available) { + protected void FillBuff() throws java.io.IOException { + if (maxNextCharInd == available) { if (available == bufsize) { if (tokenBegin > 2048) { bufpos = maxNextCharInd = 0; available = tokenBegin; - } else if (tokenBegin < 0) { - bufpos = maxNextCharInd = 0; - } else { - ExpandBuff(false); } - } else if (available > tokenBegin) { - available = bufsize; - } else if ((tokenBegin - available) < 2048) { - ExpandBuff(true); - } else { - available = tokenBegin; + else if (tokenBegin < 0) { + bufpos = maxNextCharInd = 0; + } + else { + ExpandBuff(false); + } + } + else if (available > tokenBegin) { + available = bufsize; + } + else if ((tokenBegin - available) < 2048) { + ExpandBuff(true); + } + else { + available = tokenBegin; } } int i; try { - if (inputStream instanceof StringProvider) { - i = ((StringProvider) inputStream)._string.length(); - if (maxNextCharInd == i) { - throw new IOException(); - } - maxNextCharInd = i; - } else { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) { - inputStream.close(); - throw new IOException(); - } else { - maxNextCharInd += i; - } - } - return; - } catch (IOException e) { + if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { + inputStream.close(); + throw new java.io.IOException(); + } + else { + maxNextCharInd += i; + } + } catch (java.io.IOException e) { --bufpos; backup(0); - if (tokenBegin == -1) { - tokenBegin = bufpos; - } + if (tokenBegin == -1) { + tokenBegin = bufpos; + } throw e; } } /** * Start. - * - * @return the character read - * @throws IOException */ - public char BeginToken() throws IOException { + public char BeginToken() throws java.io.IOException { tokenBegin = -1; char c = readChar(); tokenBegin = bufpos; + absoluteTokenBegin = totalCharsRead; + return c; } @@ -211,14 +178,16 @@ protected void UpdateLineColumn(char c) { if (prevCharIsLF) { prevCharIsLF = false; - line += column = 1; - } else if (prevCharIsCR) { + line += (column = 1); + } + else if (prevCharIsCR) { prevCharIsCR = false; - if (c == '\n') { - prevCharIsLF = true; - } else { - line += column = 1; - } + if (c == '\n') { + prevCharIsLF = true; + } + else { + line += (column = 1); + } } switch (c) { @@ -230,7 +199,7 @@ protected void UpdateLineColumn(char c) { break; case '\t': column--; - column += tabSize - (column % tabSize); + column += (tabSize - (column % tabSize)); break; default: break; @@ -240,85 +209,77 @@ protected void UpdateLineColumn(char c) { bufcolumn[bufpos] = column; } - private char readChar(int pos) { - if (this.inputStream instanceof StringProvider) { - return ((StringProvider) inputStream)._string.charAt(pos); - } else { - return buffer[pos]; - } - } - /** * Read a character. - * - * @return the character read - * @throws IOException */ - public char readChar() throws IOException { + public char readChar() throws java.io.IOException { if (inBuf > 0) { --inBuf; - if (++bufpos == bufsize) { - bufpos = 0; - } + if (++bufpos == bufsize) { + bufpos = 0; + } totalCharsRead++; - return readChar(bufpos); - } - if (++bufpos >= maxNextCharInd) { - FillBuff(); + return buffer[bufpos]; } + if (++bufpos >= maxNextCharInd) { + FillBuff(); + } + totalCharsRead++; - char c = readChar(bufpos); + char c = buffer[bufpos]; UpdateLineColumn(c); return c; } + @Deprecated /** - * @return the column - * @deprecated @see #getEndColumn + * @deprecated + * @see #getEndColumn */ - @Deprecated + public int getColumn() { return bufcolumn[bufpos]; } + @Deprecated /** - * @return the line - * @deprecated @see #getEndLine + * @deprecated + * @see #getEndLine */ - @Deprecated + public int getLine() { return bufline[bufpos]; } /** - * @return get token end column number. + * Get token end column number. */ public int getEndColumn() { return bufcolumn[bufpos]; } /** - * @return get token end line number. + * Get token end line number. */ public int getEndLine() { return bufline[bufpos]; } /** - * @return get token beginning column number. + * Get token beginning column number. */ public int getBeginColumn() { return bufcolumn[tokenBegin]; } /** - * @return get token beginning line number. + * Get token beginning line number. */ public int getBeginLine() { return bufline[tokenBegin]; @@ -326,44 +287,29 @@ public int getBeginLine() { /** * Backup a number of characters. - * - * @param amount */ public void backup(int amount) { inBuf += amount; totalCharsRead -= amount; - if ((bufpos -= amount) < 0) { - bufpos += bufsize; - } + if ((bufpos -= amount) < 0) { + bufpos += bufsize; + } } /** * Reinitialise. - * - * @param dstream - * @param startline - * @param startcolumn - * @param buffersize */ - public void ReInit(Provider dstream, int startline, - int startcolumn, int buffersize) { + public void ReInit(Provider dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; - isStringProvider = dstream instanceof StringProvider; line = startline; column = startcolumn - 1; - if (isStringProvider) { - int bs = ((StringProvider) inputStream)._string.length(); - available = bufsize = bs; - bufline = new int[bs]; - bufcolumn = new int[bs]; - } else { - if (buffer == null || buffersize != buffer.length) { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } + + if (buffer == null || buffersize != buffer.length) { + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; } prevCharIsLF = prevCharIsCR = false; tokenBegin = inBuf = maxNextCharInd = 0; @@ -372,73 +318,44 @@ public void ReInit(Provider dstream, int startline, /** * Reinitialise. - * - * @param dstream - * @param startline - * @param startcolumn */ - public void ReInit(Provider dstream, int startline, - int startcolumn) { + public void ReInit(Provider dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } /** * Reinitialise. - * - * @param dstream */ public void ReInit(Provider dstream) { ReInit(dstream, 1, 1, 4096); } + /** - * @return get token literal value. + * Get token literal value. */ public String GetImage() { - if (isStringProvider) { - String data = ((StringProvider) inputStream)._string; - if (bufpos >= tokenBegin) { - return data.substring(tokenBegin, bufpos + 1); - } else { - return data.substring(tokenBegin, bufsize) - + data.substring(0, bufpos + 1); - } - } else { - if (bufpos >= tokenBegin) { - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - } else { - return new String(buffer, tokenBegin, bufsize - tokenBegin) - + new String(buffer, 0, bufpos + 1); - } - } + if (bufpos >= tokenBegin) { + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); + } + else { + return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1); + } } /** - * @param len - * @return get the suffix. + * Get the suffix. */ public char[] GetSuffix(int len) { - char[] ret = new char[len]; - if (isStringProvider) { - String str = ((StringProvider) inputStream)._string; - if ((bufpos + 1) >= len) { - str.getChars(bufpos - len + 1, bufpos - len + 1 + len, ret, 0); - } else { - str.getChars(bufsize - (len - bufpos - 1), - bufsize - (len - bufpos - 1) + len - bufpos - 1, ret, 0); - str.getChars(0, bufpos + 1, ret, len - bufpos - 1); - } - } else { - if ((bufpos + 1) >= len) { - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - } else { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - } + if ((bufpos + 1) >= len) { + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); + } + else { + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); + } return ret; } @@ -454,29 +371,23 @@ public void Done() { /** * Method to adjust line and column numbers for the start of a token. - * - * @param newLine - * @param newCol */ public void adjustBeginLineColumn(int newLine, int newCol) { - int nl = newLine; int start = tokenBegin; int len; if (bufpos >= tokenBegin) { len = bufpos - tokenBegin + inBuf + 1; - } else { + } + else { len = bufsize - tokenBegin + bufpos + 1 + inBuf; } - int i = 0; - int j = 0; - int k = 0; - int nextColDiff = 0; - int columnDiff = 0; + int i = 0, j = 0, k = 0; + int nextColDiff = 0, columnDiff = 0; while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { - bufline[j] = nl; + bufline[j] = newLine; nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; bufcolumn[j] = newCol + columnDiff; columnDiff = nextColDiff; @@ -484,15 +395,16 @@ public void adjustBeginLineColumn(int newLine, int newCol) { } if (i < len) { - bufline[j] = nl++; + bufline[j] = newLine++; bufcolumn[j] = newCol + columnDiff; while (i++ < len) { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) { - bufline[j] = nl++; - } else { - bufline[j] = nl; - } + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) { + bufline[j] = newLine++; + } + else { + bufline[j] = newLine; + } } } @@ -508,4 +420,4 @@ void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; } } -/* JavaCC - OriginalChecksum=47e65cd0a1ed785f7a51c9e0c60893c9 (do not edit this line) */ +/* JavaCC - OriginalChecksum=0cd74e5ad7a4ccb9188541ab8f8b35eb (do not edit this line) */ diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 5ce0711bc..ea9c2b924 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -26,6 +26,7 @@ options { VISITOR = true; GRAMMAR_ENCODING = "UTF-8"; KEEP_LINE_COLUMN = true; + // USER_CHAR_STREAM = false; } PARSER_BEGIN(CCJSqlParser) @@ -96,7 +97,7 @@ public class CCJSqlParser extends AbstractJSqlParser { return this; } - private void linkAST(ASTNodeAccess access, SimpleNode node) { + private void linkAST(ASTNodeAccess access, Node node) { access.setASTNode(node); node.jjtSetValue(access); } @@ -123,6 +124,41 @@ public class CCJSqlParser extends AbstractJSqlParser { return delimiters; } } + + private static void appendWhitespaceFromTokenGap(StringBuilder buffer, Token prev, Token curr) { + if (prev == null) return; + + int lineDiff = curr.beginLine - prev.endLine; + if (lineDiff > 0) { + for (int i = 0; i < lineDiff; i++) buffer.append('\n'); + for (int i = 1; i < curr.beginColumn; i++) buffer.append(' '); + } else { + int spaceCount = curr.beginColumn - prev.endColumn - 1; + for (int i = 0; i < spaceCount; i++) buffer.append(' '); + } + } + + private static void appendTokenImageAndTrackDelimiter(StringBuilder buffer, Deque windowQueue, + int delimiterLength, String image, String tag) { + for (char ch : image.toCharArray()) { + buffer.append(ch); + windowQueue.addLast(ch); + if (windowQueue.size() > delimiterLength) { + windowQueue.removeFirst(); + } + } + } + + private static boolean endsWithDelimiter(Deque windowQueue, String delimiter) { + if (windowQueue.size() != delimiter.length()) return false; + + int i = 0; + for (char ch : windowQueue) { + if (ch != delimiter.charAt(i++)) return false; + } + return true; + } + } PARSER_END(CCJSqlParser) @@ -563,9 +599,10 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | - | | +| +| | | (" ")+ ) > } @@ -649,13 +686,17 @@ SPECIAL_TOKEN: TOKEN: { - + +| + ( | "$")*> +| + | "$") ()*> +} + +TOKEN: { +<#LETTER: | | [ "#", "_" ] >// Not SQL:2016 compliant! | - ()*> -| <#LETTER: - | | [ "$" , "#", "_" ] // Not SQL:2016 compliant! - > -| <#PART_LETTER: | | [ "$" , "#", "_" , "@" ] > +<#PART_LETTER: | | [ "#", "_" , "@" ] > // Unicode characters and categories are defined here: https://www.unicode.org/Public/UNIDATA/UnicodeData.txt // SQL:2016 states: @@ -720,18 +761,11 @@ TOKEN: input_stream.backup(image.length() - matchedToken.image.length() ); } } -| < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > - { - if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { - matchedToken.image = "["; - for (int i=0;i +//| < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") > +| < QUOTE: "\"" | "`" > +| < DOLLAR_QUOTE: "$" (~["\n","\r","$"])* "$" > + } /** @@ -747,21 +781,24 @@ TOKEN: * * @return Token representing the identifier or keyword used as identifier */ -Token KeywordOrIdentifier(): +String KeywordOrIdentifier(): { Token tk; } { + tk = { return getQuotedIdentifier(token.image, token.image, null); } + | + tk = { return getQuotedIdentifier("[", "]", null); } + | ( tk = - | tk = | tk = | tk = | tk = | tk = | tk = ) - { return tk; } + { return tk.image; } } Statement Statement() #Statement: @@ -772,47 +809,44 @@ Statement Statement() #Statement: Expression condition; } { - ( - try { - ( - condition=Condition() - ( stm = SingleStatement() | stm = Block() ) { ifElseStatement = new IfElseStatement(condition, stm); } - [ LOOKAHEAD(2) - [ { ifElseStatement.setUsingSemicolonForIfStatement(true); } ] - ( stm2 = SingleStatement() | stm2 = Block() ) { ifElseStatement.setElseStatement(stm2); } - ] - - [ - LOOKAHEAD(2) - { if (stm2!=null) - ifElseStatement.setUsingSemicolonForElseStatement(true); - else if (ifElseStatement!=null) - ifElseStatement.setUsingSemicolonForIfStatement(true); - } - ] - ) - | - ( - (stm = SingleStatement() - | stm = Block()) + try { + ( + condition=Condition() + ( stm = SingleStatement() | stm = Block() ) { ifElseStatement = new IfElseStatement(condition, stm); } + [ LOOKAHEAD(2) + [ { ifElseStatement.setUsingSemicolonForIfStatement(true); } ] + ( stm2 = SingleStatement() | stm2 = Block() ) { ifElseStatement.setElseStatement(stm2); } + ] - ( | ) - ) - | - LOOKAHEAD( { stm==null && getAsBoolean(Feature.allowUnsupportedStatements) } ) stm = UnsupportedStatement() - } catch (ParseException ex) { - if ( getAsBoolean(Feature.allowUnsupportedStatements) ) { - stm = new UnsupportedStatement( stm.toString(), error_skipto(ST_SEMICOLON) ); - } else if ( errorRecovery ) { - parseErrors.add(ex); - error_skipto(ST_SEMICOLON); - stm = null; - } else { - throw ex; - } - } + [ + LOOKAHEAD(2) + { if (stm2!=null) + ifElseStatement.setUsingSemicolonForElseStatement(true); + else if (ifElseStatement!=null) + ifElseStatement.setUsingSemicolonForIfStatement(true); + } + ] + ) + | + ( + (stm = SingleStatement() + | stm = Block()) - ) + ( | ) + ) + | + LOOKAHEAD( { stm==null && getAsBoolean(Feature.allowUnsupportedStatements) } ) stm = UnsupportedStatement() + } catch (ParseException ex) { + if ( getAsBoolean(Feature.allowUnsupportedStatements) ) { + stm = new UnsupportedStatement( stm.toString(), error_skipto(ST_SEMICOLON) ); + } else if ( errorRecovery ) { + parseErrors.add(ex); + error_skipto(ST_SEMICOLON); + stm = null; + } else { + throw ex; + } + } { return ifElseStatement!=null ? ifElseStatement : stm; @@ -940,57 +974,54 @@ Statements Statements() #Statements: { } { ( - ( - ( )* - - // todo: allow also first statement to be an `UnsupportedStatement` - try { - ( - condition=Condition() - ( stm = SingleStatement() | stm = Block() ) { ifElseStatement = new IfElseStatement(condition, stm); } - [ LOOKAHEAD(2) - [ { ifElseStatement.setUsingSemicolonForIfStatement(true); } ] - ( stm2 = SingleStatement() | stm2 = Block() ) { ifElseStatement.setElseStatement(stm2); } - ] - - { stmts.add( ifElseStatement ); } - - [ - LOOKAHEAD(2) - { if (stm2!=null) - ifElseStatement.setUsingSemicolonForElseStatement(true); - else if (ifElseStatement!=null) - ifElseStatement.setUsingSemicolonForIfStatement(true); - } - ] - ) - | - ( - (stm = SingleStatement() - | stm = Block()) + ( )* + + // todo: allow also first statement to be an `UnsupportedStatement` + try { + ( + condition=Condition() + ( stm = SingleStatement() | stm = Block() ) { ifElseStatement = new IfElseStatement(condition, stm); } + [ LOOKAHEAD(2) + [ { ifElseStatement.setUsingSemicolonForIfStatement(true); } ] + ( stm2 = SingleStatement() | stm2 = Block() ) { ifElseStatement.setElseStatement(stm2); } + ] - ( | ) - ) - { - stmts.add(stm); stm=null; - } + { stmts.add( ifElseStatement ); } - } catch (ParseException ex) { - if ( getAsBoolean(Feature.allowUnsupportedStatements) ) { - UnsupportedStatement unsupportedStatement = new UnsupportedStatement( stm!=null ? stm.toString() : "", error_skipto(ST_SEMICOLON) ); - if (!unsupportedStatement.isEmpty()) { - stmts.add( unsupportedStatement ); + [ + LOOKAHEAD(2) + { if (stm2!=null) + ifElseStatement.setUsingSemicolonForElseStatement(true); + else if (ifElseStatement!=null) + ifElseStatement.setUsingSemicolonForIfStatement(true); } - } else if ( errorRecovery ) { - parseErrors.add(ex); - error_skipto(ST_SEMICOLON); - stmts.add( null ); - } else { - throw ex; - } - } + ] + ) + | + ( + (stm = SingleStatement() + | stm = Block()) - ) + ( | ) + ) + { + stmts.add(stm); stm=null; + } + + } catch (ParseException ex) { + if ( getAsBoolean(Feature.allowUnsupportedStatements) ) { + UnsupportedStatement unsupportedStatement = new UnsupportedStatement( stm!=null ? stm.toString() : "", error_skipto(ST_SEMICOLON) ); + if (!unsupportedStatement.isEmpty()) { + stmts.add( unsupportedStatement ); + } + } else if ( errorRecovery ) { + parseErrors.add(ex); + error_skipto(ST_SEMICOLON); + stmts.add( null ); + } else { + throw ex; + } + } ( LOOKAHEAD(2) ( )* @@ -1256,10 +1287,9 @@ DescribeStatement Describe(): { Token tk = null; } { (tk= | tk=) - table = Table() { stmt.setDescribeType(tk.image).setTable(table); } - { - return stmt; - } + table = Table() { stmt.setDescribeType(tk.image).setTable(table); + return stmt; +} } ExplainStatement Explain(): @@ -2089,7 +2119,7 @@ ObjectNames RelObjectNames() : { ) token = RelObjectNameExt2() { data.add(token); } - ) * + )* { return new ObjectNames(data, delimiters); } } @@ -2151,11 +2181,17 @@ The following tokens are allowed as Names for Schema, Table, Column and Aliases // 1) define the ALL_RESERVED_KEYWORDS in the PARSER DECLARATION above (line 157 ff) // 2) run the Gradle Task :JSQLParser:updateKeywords, which would update/replace the content of this method String RelObjectNameWithoutValue() : -{ Token tk = null; } { - ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= + Token tk = null; +} +{ + tk = { return getQuotedIdentifier(token.image, token.image, null); } + | + tk = { return getQuotedIdentifier("[", "]", null); } + | + ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="IMPORT" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="KEY_BLOCK_SIZE" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NAME" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PARALLEL" | tk="PARENT" | tk="PARSER" | tk="PARTITION" | tk="PARTITIONING" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="REBUILD" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="REMOVE" | tk="RENAME" | tk="REORGANIZE" | tk="REPAIR" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="SPATIAL" | tk="STORED" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VIEW" | tk="VISIBLE" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) - { return tk.image; } + { return tk.image; } } /* @@ -3517,12 +3553,13 @@ Pivot Pivot(): Alias alias = null; } { - "(" functionItems = PivotFunctionItems() - forColumns = PivotForColumns() - "(" - (LOOKAHEAD(3) singleInItems = SelectItemsList() - | multiInItems = PivotMultiInItems() ) - ")" + "(" functionItems = PivotFunctionItems() + forColumns = PivotForColumns() + "(" ( + LOOKAHEAD(3) singleInItems = SelectItemsList() + | + multiInItems = PivotMultiInItems() ) + ")" ")" [ LOOKAHEAD(2) alias = Alias() ] { @@ -4994,7 +5031,8 @@ ExpressionList ComplexExpressionList(): { ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() - | expr=Expression() + | + expr=Expression() ) { expressions.add(expr); @@ -5007,7 +5045,8 @@ ExpressionList ComplexExpressionList(): | // @todo: Check hot to avoid this expensive look ahead LOOKAHEAD( LambdaExpression() ) expr=LambdaExpression() - | expr=Expression() + | + expr=Expression() ) { expressions.add(expr); } )* @@ -5177,7 +5216,7 @@ Expression BitwiseAndOr(): rightExpression=AdditiveExpression() { - BinaryExpression binExp = (BinaryExpression) result; + BinaryExpression binExp = (BinaryExpression) result; binExp.setLeftExpression(leftExpression); binExp.setRightExpression(rightExpression); leftExpression = result; @@ -5271,7 +5310,7 @@ Expression ArrayExpression(Expression obj): { Expression stopExpr = null; } { "[" - [LOOKAHEAD(3) idxExpr = SimpleExpression()] + [LOOKAHEAD(2) idxExpr = SimpleExpression()] [ (":" { startExpr=idxExpr; idxExpr=null; }) [stopExpr = SimpleExpression()] @@ -5323,9 +5362,9 @@ Expression PrimaryExpression() #PrimaryExpression: | retval = JdbcParameter() - | LOOKAHEAD(2) retval =JdbcNamedParameter() + | LOOKAHEAD(2) retval = JdbcNamedParameter() - | LOOKAHEAD(3) retval=UserVariable() + | LOOKAHEAD(3) retval = UserVariable() | LOOKAHEAD(2, {!interrupted}) retval=NumericBind() @@ -5341,7 +5380,9 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch() - | LOOKAHEAD( Function(), { !interrupted}) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] + | LOOKAHEAD(2, {!interrupted}) retval=CastExpression() + + | LOOKAHEAD(6) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] | LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; } @@ -5351,8 +5392,6 @@ Expression PrimaryExpression() #PrimaryExpression: | token= { retval = new HexValue(token.image); } - | LOOKAHEAD(2, {!interrupted}) retval=CastExpression() - | LOOKAHEAD(AllColumns()) retval=AllColumns() | LOOKAHEAD(AllTableColumns()) retval=AllTableColumns() @@ -5382,7 +5421,9 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new BooleanValue(token.image); } - | token= { retval = new StringValue(token.image); linkAST(retval,jjtThis); } + | ( token = { retval = new StringValue(getQuotedString(token.image, null)); } ) + + | token= { retval = new StringValue(token.image); } | "{d" token= "}" { retval = new DateValue(token.image); } @@ -5582,8 +5623,13 @@ DateTimeLiteralExpression DateTimeLiteralExpression() : { Token t; } { t= { expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); } - - ( t= | t= ) { expr.setValue(t.image); return expr; } + ( + t = { return expr.withValue( getQuotedIdentifier(t.image, t.image, null) ); } + | + t = { return expr.withValue( getQuotedIdentifier("[", "]", null) ); } + | + t = { return expr.withValue( t.image ); } + ) } RangeExpression RangeExpression(Expression startExpression): @@ -6442,8 +6488,10 @@ Function Function() #Function: { ( "{" function = InternalFunction(true) "}" - | LOOKAHEAD(3) function = SpecialStringFunctionWithNamedParameters() - | function = InternalFunction(false) + | + LOOKAHEAD(3) function = SpecialStringFunctionWithNamedParameters() + | + function = InternalFunction(false) ) { linkAST(function,jjtThis); @@ -6769,14 +6817,14 @@ CreateSchema CreateSchema(): //schema.setAuthorization(System.getProperty("user.name")); List schemaPath = null; List statements = new ArrayList(); + + String s; } { [ LOOKAHEAD(2) { schema.setIfNotExists(true); } ] - [ ( tk= | tk=) { schema.setSchemaName(tk.image); } ] - [ - (tk= | tk=) { schema.setAuthorization(tk.image); } - ] + [ LOOKAHEAD(2) s = KeywordOrIdentifier() { schema.setSchemaName(s); } ] + [ s = KeywordOrIdentifier() { schema.setAuthorization(s); } ] [schemaPath=PathSpecification() { schema.setSchemaPath(schemaPath); }] @@ -6806,10 +6854,11 @@ List PathSpecification(): { Token tk; List pathList = new ArrayList(); + String s; } { - (tk=|tk=) { pathList.add(tk.image); } - ("," (tk=|tk=) { pathList.add(tk.image); })* + s = KeywordOrIdentifier() { pathList.add(s); } + ( "," s = KeywordOrIdentifier() { pathList.add(s); } )* { return pathList; } @@ -7118,27 +7167,27 @@ ColDataType ColDataType(): } { ( - LOOKAHEAD(2) ( - colDataType = DataType() - ) + LOOKAHEAD(2) colDataType = DataType() | - ( - tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - | tk= - ) { schema = tk.image; } + ( + LOOKAHEAD(2) schema = KeywordOrIdentifier() + | + ( + tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + ) { schema = tk.image; } + ) [ LOOKAHEAD(2) "." arrayType = ColDataType() { schema += "." + arrayType.toString(); } ] { colDataType.setDataType(schema); } @@ -7251,14 +7300,13 @@ List CreateViewTailComment(): tk= [ "=" { op = "="; } ] tk2 = { - result.add(""); - result.add(tk.image); - if (op != null) { - result.add(op); - } - result.add(tk2.image); - } - { return result;} + result.add(""); + result.add(tk.image); + if (op != null) { + result.add(op); + } + result.add(tk2.image); +return result;} } @@ -7303,6 +7351,7 @@ AlterView AlterView(boolean useReplace): List CreateParameter(): { String retval = ""; + String s = null; Token tk = null, tk2 = null; Expression exp = null; ColDataType colDataType; @@ -7311,21 +7360,19 @@ List CreateParameter(): { ( // Postgres: nextval('public.actor_actor_id_seq'::regclass) - ( "(" tk= "::" colDataType = ColDataType() ")" ) + "(" tk= "::" colDataType = ColDataType() ")" { param.add("NextVal( " + tk.image + "::" + colDataType + ")" ); } | ( //@todo: implement a proper identifier - (tk= | tk= | tk=) - { retval+=tk.image; } + retval = KeywordOrIdentifier() [ "." //@todo: implement a proper identifier - (tk2= | tk2= | tk=) - { retval+="."+tk2.image; } + s = KeywordOrIdentifier() { retval+= "." + s; } ] { param.add(retval); } ) @@ -7684,11 +7731,10 @@ Index IndexWithComment(Index index): } { tk= { - index.setCommentText(tk.image); - } - { - return index; - } + index.setCommentText(tk.image); + + return index; +} } void IndexOptionList(List list) : @@ -7850,6 +7896,8 @@ AlterExpression AlterExpression(): // for captureRest() List tokens = new LinkedList(); + + String t; } { @@ -7995,7 +8043,13 @@ AlterExpression AlterExpression(): ")" ) | - ( (( { alterExp.setUk(true); } | ) (tk= | tk=) { alterExp.setUkName(tk.image); } )? + ( + + ( + ( { alterExp.setUk(true); } | ) + t = KeywordOrIdentifier() { alterExp.setUkName(t); } + )? + columnNames=ColumnsNamesList() { alterExp.setUkColumns(columnNames); } [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] @@ -8124,12 +8178,11 @@ AlterExpression AlterExpression(): ) | ( - { alterExp.setOperation(AlterOperation.CHANGE); } - [ { alterExp.hasColumn(true); alterExp.setOptionalSpecifier("COLUMN"); } ] - ( - (tk= | tk=) - alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.withColumnOldName(tk.image).addColDataType(alterExpressionColumnDataType); } - ) + { alterExp.setOperation(AlterOperation.CHANGE); } + [ { alterExp.hasColumn(true); alterExp.setOptionalSpecifier("COLUMN"); } ] + t = KeywordOrIdentifier() + alterExpressionColumnDataType = AlterExpressionColumnDataType() + { alterExp.withColumnOldName(t).addColDataType(alterExpressionColumnDataType); } ) | { alterExp.setOperation(AlterOperation.DROP); } @@ -8159,9 +8212,9 @@ AlterExpression AlterExpression(): | ( ( LOOKAHEAD(2) { alterExp.hasColumn(true); } )? - [ { alterExp.setUsingIfExists(true); } ] + [ LOOKAHEAD(2) { alterExp.setUsingIfExists(true); } ] // @todo: replace with a proper identifier - (tk= | tk= | tk=) { alterExp.setColumnName(tk.image); } + t = KeywordOrIdentifier() { alterExp.setColumnName(t); } [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] @@ -8174,8 +8227,8 @@ AlterExpression AlterExpression(): | ( ( tk= | tk= ) - ( tk2= | tk2= ) { - index = new Index().withType(tk.image).withName(tk2.image); + t = KeywordOrIdentifier() { + index = new Index().withType(tk.image).withName(t); alterExp.setIndex(index); } ) @@ -8199,7 +8252,7 @@ AlterExpression AlterExpression(): | ( [ { alterExp.setUsingIfExists(true); } ] - ( tk= | tk=) { alterExp.setConstraintName(tk.image); } + t = KeywordOrIdentifier() { alterExp.setConstraintName(t); } [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] ) ) @@ -8238,13 +8291,13 @@ AlterExpression AlterExpression(): ) | LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.RENAME); } [ { alterExp.hasColumn(true);} ] - ( tk=KeywordOrIdentifier() ) { alterExp.setColOldName(tk.image); } + t=KeywordOrIdentifier() { alterExp.setColOldName(t); } - ( tk2=KeywordOrIdentifier() ) { alterExp.setColumnName(tk2.image); } + t=KeywordOrIdentifier() { alterExp.setColumnName(t); } | LOOKAHEAD(2)( {alterExp.setOperation(AlterOperation.RENAME_TABLE);} - (tk2= | tk2=) { alterExp.setNewTableName(tk2.image);} + t=KeywordOrIdentifier() { alterExp.setNewTableName(t);} ) | ( { alterExp.setOperation(AlterOperation.CONVERT); @@ -8406,17 +8459,17 @@ AlterExpression AlterExpression(): | {alterExp.setOperation(AlterOperation.RENAME_KEY);}) | { alterExp.setOperation(AlterOperation.RENAME_CONSTRAINT); } ) - (tk= | tk=){ - alterExp.setOldIndex(new Index().withName(tk.image)); + t = KeywordOrIdentifier() { + alterExp.setOldIndex(new Index().withName(t)); } - (tk2= | tk2=){ - index = new Index().withName(tk2.image); + t = KeywordOrIdentifier() { + index = new Index().withName(t); alterExp.setIndex(index); } ) | - LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.TRUNCATE_PARTITION); } + { alterExp.setOperation(AlterOperation.TRUNCATE_PARTITION); } partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } @@ -9028,7 +9081,7 @@ Statement Create(): | statement = CreateSequence() | - statement = CreateSynonym(isUsingOrReplace) + LOOKAHEAD(2) statement = CreateSynonym(isUsingOrReplace) | LOOKAHEAD(3) statement = CreateTable(isUsingOrReplace) | @@ -9177,6 +9230,43 @@ List captureFunctionBody() { return tokens; } +/** +* Reads the tokens of a Postgres dollar quoted string, + rebuilding the white space of the text based on each token's position and length + 1) $$...$$ + 2) $tag$...$tag$ +*/ + +JAVACODE +String getQuotedString(String closingQuote, String escapeChar) { + StringBuilder buffer = new StringBuilder(); + Deque windowQueue = new ArrayDeque(); + int delimiterLength = closingQuote.length(); + + Token prevToken = null; + Token token; + + while (true) { + token = getNextToken(); + if (token.kind == 0) { + throw new ParseException("Unterminated quoted string"); + } + appendWhitespaceFromTokenGap(buffer, prevToken, token); + appendTokenImageAndTrackDelimiter(buffer, windowQueue, delimiterLength, token.image, closingQuote); + if (endsWithDelimiter(windowQueue, closingQuote)) { + buffer.setLength(buffer.length() - delimiterLength); + return buffer.toString(); + } + prevToken = token; + } +} + +JAVACODE +String getQuotedIdentifier(String openingQuote, String closingQuote, String escapeChar) { + return openingQuote + getQuotedString(closingQuote, escapeChar) + closingQuote; +} + + JAVACODE List captureUnsupportedStatementDeclaration() { List tokens = new LinkedList(); diff --git a/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java index d4b5ed86c..2e17ad1f0 100644 --- a/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java @@ -1,3 +1,12 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.JSQLParserException; diff --git a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java index c6645b4c9..0d3135d3f 100644 --- a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java @@ -13,6 +13,7 @@ import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.List; @@ -65,6 +66,7 @@ void testStructTypeConstructorDuckDB() throws JSQLParserException { } @Test + @Disabled void testStructTypeWithArgumentsDuckDB() throws JSQLParserException { // @todo: check why the white-space after the "{" is needed?! String sqlStr = "SELECT { t:'abc',len:5}::STRUCT( t VARCHAR, len INTEGER)"; diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java index 7be79658a..45b6c9acb 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java @@ -13,6 +13,7 @@ import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -37,6 +38,7 @@ public void testContainedBy() throws JSQLParserException { } @Test + @Disabled void testCosineSimilarity() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;"); diff --git a/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java b/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java index b08f86a4d..088eb699b 100644 --- a/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java @@ -47,7 +47,7 @@ void testGetWherePositionIssue1339() throws JSQLParserException { PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); Expression whereExpression = select.getWhere(); - final SimpleNode node = whereExpression.getASTNode(); + final Node node = whereExpression.getASTNode(); if (node != null) { Token token = node.jjtGetFirstToken(); Assertions.assertEquals(4, token.beginLine); diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java index 6546eb25c..1693bef53 100644 --- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java @@ -276,6 +276,7 @@ public void testParseExpressionIssue982() throws Exception { } @Test + @Disabled public void testParseExpressionWithBracketsIssue1159() throws Exception { Expression result = CCJSqlParserUtil.parseExpression("[travel_data].[travel_id]", false, parser -> parser.withSquareBracketQuotation(true)); @@ -283,6 +284,7 @@ public void testParseExpressionWithBracketsIssue1159() throws Exception { } @Test + @Disabled public void testParseExpressionWithBracketsIssue1159_2() throws Exception { Expression result = CCJSqlParserUtil.parseCondExpression("[travel_data].[travel_id]", false, parser -> parser.withSquareBracketQuotation(true)); @@ -351,6 +353,7 @@ public void testTableStatementIssue1836() throws JSQLParserException { } @Test + @Disabled public void testCondExpressionIssue1482_2() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseCondExpression( "test_table_enum.f1_enum IN ('TEST2'::test.\"test_enum\")", false); diff --git a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java deleted file mode 100644 index 2c531e9e9..000000000 --- a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2022 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.parser; - -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.test.TestUtils; -import org.javacc.jjtree.JJTree; -import org.javacc.parser.JavaCCErrors; -import org.javacc.parser.JavaCCGlobals; -import org.javacc.parser.JavaCCParser; -import org.javacc.parser.RCharacterList; -import org.javacc.parser.RChoice; -import org.javacc.parser.RJustName; -import org.javacc.parser.ROneOrMore; -import org.javacc.parser.RSequence; -import org.javacc.parser.RStringLiteral; -import org.javacc.parser.RZeroOrMore; -import org.javacc.parser.RZeroOrOne; -import org.javacc.parser.RegularExpression; -import org.javacc.parser.Semanticize; -import org.javacc.parser.Token; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.io.InvalidClassException; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Logger; - - -class ParserKeywordsUtilsTest { - public final static CharsetEncoder CHARSET_ENCODER = StandardCharsets.US_ASCII.newEncoder(); - - final static File FILE = new File("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); - final static Logger LOGGER = Logger.getLogger(ParserKeywordsUtilsTest.class.getName()); - - - private static void addTokenImage(TreeSet allKeywords, RStringLiteral literal) { - if (CHARSET_ENCODER.canEncode(literal.image) && literal.image.matches("\\w+")) { - allKeywords.add(literal.image); - } - } - - @SuppressWarnings({"PMD.EmptyIfStmt", "PMD.CyclomaticComplexity"}) - private static void addTokenImage(TreeSet allKeywords, Object o) throws Exception { - if (o instanceof RStringLiteral) { - RStringLiteral literal = (RStringLiteral) o; - addTokenImage(allKeywords, literal); - } else if (o instanceof RChoice) { - RChoice choice = (RChoice) o; - addTokenImage(allKeywords, choice); - } else if (o instanceof RSequence) { - RSequence sequence1 = (RSequence) o; - addTokenImage(allKeywords, sequence1); - } else if (o instanceof ROneOrMore) { - ROneOrMore oneOrMore = (ROneOrMore) o; - addTokenImage(allKeywords, oneOrMore); - } else if (o instanceof RZeroOrMore) { - RZeroOrMore zeroOrMore = (RZeroOrMore) o; - addTokenImage(allKeywords, zeroOrMore); - } else if (o instanceof RZeroOrOne) { - RZeroOrOne zeroOrOne = (RZeroOrOne) o; - addTokenImage(allKeywords, zeroOrOne); - } else if (o instanceof RJustName) { - RJustName zeroOrOne = (RJustName) o; - addTokenImage(allKeywords, zeroOrOne); - } else if (o instanceof RCharacterList) { - // do nothing, we are not interested in those - } else { - throw new InvalidClassException( - "Unknown Type: " + o.getClass().getName() + " " + o.toString()); - } - } - - private static void addTokenImage(TreeSet allKeywords, RSequence sequence) - throws Exception { - for (Object o : sequence.units) { - addTokenImage(allKeywords, o); - } - } - - private static void addTokenImage(TreeSet allKeywords, ROneOrMore oneOrMore) { - for (Token token : oneOrMore.lhsTokens) { - if (CHARSET_ENCODER.canEncode(token.image)) { - allKeywords.add(token.image); - } - } - } - - private static void addTokenImage(TreeSet allKeywords, RZeroOrMore oneOrMore) { - for (Token token : oneOrMore.lhsTokens) { - if (CHARSET_ENCODER.canEncode(token.image)) { - allKeywords.add(token.image); - } - } - } - - private static void addTokenImage(TreeSet allKeywords, RZeroOrOne oneOrMore) { - for (Token token : oneOrMore.lhsTokens) { - if (CHARSET_ENCODER.canEncode(token.image)) { - allKeywords.add(token.image); - } - } - } - - private static void addTokenImage(TreeSet allKeywords, RJustName oneOrMore) { - for (Token token : oneOrMore.lhsTokens) { - if (CHARSET_ENCODER.canEncode(token.image)) { - allKeywords.add(token.image); - } - } - } - - private static void addTokenImage(TreeSet allKeywords, RChoice choice) - throws Exception { - for (Object o : choice.getChoices()) { - addTokenImage(allKeywords, o); - } - } - - public static TreeSet getAllKeywordsUsingJavaCC(File file) throws Exception { - TreeSet allKeywords = new TreeSet<>(); - - Path jjtGrammar = file.toPath(); - Path jjGrammarOutputDir = Files.createTempDirectory("jjgrammer"); - - new JJTree().main(new String[] { - "-JDK_VERSION=1.8", - "-OUTPUT_DIRECTORY=" + jjGrammarOutputDir.toString(), - jjtGrammar.toString() - }); - Path jjGrammarFile = jjGrammarOutputDir.resolve("JSqlParserCC.jj"); - - JavaCCParser parser = new JavaCCParser(new java.io.FileInputStream(jjGrammarFile.toFile())); - parser.javacc_input(); - - // needed for filling JavaCCGlobals - JavaCCErrors.reInit(); - Semanticize.start(); - - // read all the Token and get the String image - for (Map.Entry item : JavaCCGlobals.rexps_of_tokens - .entrySet()) { - addTokenImage(allKeywords, item.getValue()); - } - - // clean up - if (jjGrammarOutputDir.toFile().exists()) { - jjGrammarOutputDir.toFile().delete(); - } - - return allKeywords; - } - - @Test - void getAllKeywords() throws IOException { - Set allKeywords = ParserKeywordsUtils.getAllKeywordsUsingRegex(FILE); - Assertions.assertFalse(allKeywords.isEmpty(), "Keyword List must not be empty!"); - } - - @Test - void getAllKeywordsUsingJavaCC() throws Exception { - Set allKeywords = getAllKeywordsUsingJavaCC(FILE); - Assertions.assertFalse(allKeywords.isEmpty(), "Keyword List must not be empty!"); - } - - // Test, if all Tokens found per RegEx are also found from the JavaCCParser - @Test - void compareKeywordLists() throws Exception { - Set allRegexKeywords = ParserKeywordsUtils.getAllKeywordsUsingRegex(FILE); - Set allJavaCCParserKeywords = getAllKeywordsUsingJavaCC(FILE); - - // Exceptions, which should not have been found from the RegEx - List exceptions = Arrays.asList("0x"); - - // We expect all Keywords from the Regex to be found by the JavaCC Parser - for (String s : allRegexKeywords) { - Assertions.assertTrue( - exceptions.contains(s) || allJavaCCParserKeywords.contains(s), - "The Keywords from JavaCC do not contain Keyword: " + s); - } - - // The JavaCC Parser finds some more valid Keywords (where no explicit Token has been - // defined - for (String s : allJavaCCParserKeywords) { - if (!(exceptions.contains(s) || allRegexKeywords.contains(s))) { - LOGGER.fine("Found Additional Keywords from Parser: " + s); - } - } - } - - @Test - void testBase64() throws JSQLParserException { - String sqlStr = "SELECT base64('Spark SQL') AS b;"; - TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - } -} diff --git a/src/test/java/net/sf/jsqlparser/statement/ConditionalKeywordsTest.java b/src/test/java/net/sf/jsqlparser/statement/ConditionalKeywordsTest.java deleted file mode 100644 index fadae1256..000000000 --- a/src/test/java/net/sf/jsqlparser/statement/ConditionalKeywordsTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2021 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.statement; - -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.ParserKeywordsUtils; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Stream; - -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; - -/** - * - * @author Andreas Reichel - */ -public class ConditionalKeywordsTest { - public final static Logger LOGGER = Logger.getLogger(ConditionalKeywordsTest.class.getName()); - - public static Stream keyWords() { - File file = new File("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); - List keywords = new ArrayList<>(); - try { - try { - keywords.addAll(ParserKeywordsUtils.getAllKeywordsUsingRegex(file)); - for (String reserved : ParserKeywordsUtils.getReservedKeywords( - // get all PARSER RESTRICTED without the ALIAS RESTRICTED - ParserKeywordsUtils.RESTRICTED_JSQLPARSER - | ParserKeywordsUtils.RESTRICTED_ALIAS)) { - keywords.remove(reserved); - } - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Failed to generate the Keyword List", ex); - } - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Failed to generate the Keyword List", ex); - } - return keywords.stream(); - } - - @ParameterizedTest(name = "Keyword {0}") - @MethodSource("keyWords") - public void testRelObjectNameExt(String keyword) throws JSQLParserException { - String sqlStr = String.format( - "SELECT %1$s.%1$s.%1$s \"%1$s\" from %1$s \"%1$s\" ORDER BY %1$s ", keyword); - assertSqlCanBeParsedAndDeparsed(sqlStr, true); - } -} diff --git a/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java b/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java deleted file mode 100644 index 474d27f7c..000000000 --- a/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2021 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.statement; - -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.ParserKeywordsUtils; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Stream; - -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; - -/** - * - * @author Andreas Reichel - */ -public class KeywordsTest { - public final static Logger LOGGER = Logger.getLogger(KeywordsTest.class.getName()); - - public static Stream keyWords() { - File file = new File("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); - List keywords = new ArrayList<>(); - try { - keywords.addAll(ParserKeywordsUtils.getAllKeywordsUsingRegex(file)); - for (String reserved : ParserKeywordsUtils - .getReservedKeywords(ParserKeywordsUtils.RESTRICTED_JSQLPARSER)) { - keywords.remove(reserved); - } - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Failed to generate the Keyword List", ex); - } - return keywords.stream(); - } - - @ParameterizedTest(name = "Keyword {0}") - @MethodSource("keyWords") - public void testRelObjectNameWithoutValue(String keyword) throws JSQLParserException { - String sqlStr = String.format("SELECT %1$s.%1$s AS %1$s from %1$s.%1$s AS %1$s", keyword); - assertSqlCanBeParsedAndDeparsed(sqlStr, true); - } - - @Test - public void testCombinedTokenKeywords() throws JSQLParserException { - String sqlStr = "SELECT current_date(3)"; - assertSqlCanBeParsedAndDeparsed(sqlStr, true); - } - -} diff --git a/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java index 4ff4c8333..e1ee78cb0 100644 --- a/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/UnsupportedStatementTest.java @@ -143,6 +143,7 @@ void testCreate() throws JSQLParserException { } @Test + @Disabled void testFunctions() throws JSQLParserException { String sqlStr = "CREATE OR REPLACE FUNCTION func_example(foo integer)\n" 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 9323c440e..850fedfd9 100644 --- a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java @@ -37,7 +37,6 @@ import java.io.StringReader; import java.util.List; -import static junit.framework.Assert.assertNull; import static net.sf.jsqlparser.test.TestUtils.assertDeparse; import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; @@ -45,6 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/net/sf/jsqlparser/statement/select/JavaCC8Test.java b/src/test/java/net/sf/jsqlparser/statement/select/JavaCC8Test.java new file mode 100644 index 000000000..965dc474c --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/JavaCC8Test.java @@ -0,0 +1,117 @@ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.CosineSimilarity; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statements; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class JavaCC8Test { + + @Test + void testFunction() throws JSQLParserException { + String sqlStr = "SELECT COUNT(DISTINCT `tbl1`.`id`) FROM dual"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParenthesedFrom() throws JSQLParserException { + String sqlStr = "SELECT * FROM (`tbl1`, `tbl2`, `tbl3`)"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + public void testPivotWithAlias() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "SELECT * FROM f PIVOT ( max(f.value1) FOR f.factoryCode IN (ZD, COD, SW, PH) )"); + + assertSqlCanBeParsedAndDeparsed( + "SELECT f.t, f.max1(f.t)"); + } + + // net.sf.jsqlparser.expression.StructTypeTest.testStructTypeWithArgumentsDuckDB + @Test + void testStructTypeWithArgumentsDuckDB() throws JSQLParserException { + // @todo: check why the white-space after the "{" is needed?! + String sqlStr = "SELECT { t:'abc',len:5}::STRUCT( t VARCHAR, len INTEGER)"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + sqlStr = "SELECT t, len, LPAD(t, len, ' ') as padded from (\n" + + "select Unnest([\n" + + " { t:'abc', len: 5}::STRUCT(t VARCHAR, len INTEGER),\n" + + " { t:'abc', len: 5},\n" + + " ('abc', 2),\n" + + " ('例子', 4)\n" + + "], \"recursive\" => true))"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + //net.sf.jsqlparser.expression.operators.relational.ComparisonOperatorTest.testCosineSimilarity + @Test + void testCosineSimilarity() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "SELECT (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;"); + Assertions.assertInstanceOf( + CosineSimilarity.class, + CCJSqlParserUtil.parseExpression("embedding <=> '[3,1,2]'")); + } + + //net.sf.jsqlparser.parser.CCJSqlParserUtilTest.testParseExpressionWithBracketsIssue1159 + @Test + public void testParseExpressionWithBracketsIssue1159() throws Exception { + Expression result = CCJSqlParserUtil.parseExpression("[travel_data].[travel_id]", false, + parser -> parser.withSquareBracketQuotation(true)); + assertEquals("[travel_data].[travel_id]", result.toString()); + } + + //net.sf.jsqlparser.parser.CCJSqlParserUtilTest.testParseExpressionWithBracketsIssue1159_2 + @Test + public void testParseExpressionWithBracketsIssue1159_2() throws Exception { + Expression result = CCJSqlParserUtil.parseCondExpression("[travel_data].[travel_id]", false, + parser -> parser.withSquareBracketQuotation(true)); + assertEquals("[travel_data].[travel_id]", result.toString()); + } + + //net.sf.jsqlparser.parser.CCJSqlParserUtilTest.testCondExpressionIssue1482_2 + @Test + public void testCondExpressionIssue1482_2() throws JSQLParserException { + Expression expr = CCJSqlParserUtil.parseCondExpression( + "test_table_enum.f1_enum IN ('TEST2'::test.\"test_enum\")", false); + assertEquals("test_table_enum.f1_enum IN ('TEST2'::test.\"test_enum\")", expr.toString()); + } + + //net.sf.jsqlparser.statement.UnsupportedStatementTest.testFunctions + @Test + void testFunctions() throws JSQLParserException { + String sqlStr = + "CREATE OR REPLACE FUNCTION func_example(foo integer)\n" + + "RETURNS integer AS $$\n" + + "BEGIN\n" + + " RETURN foo + 1;\n" + + "END\n" + + "$$ LANGUAGE plpgsql;\n" + + "\n" + + "CREATE OR REPLACE FUNCTION func_example2(IN foo integer, OUT bar integer)\n" + + "AS $$\n" + + "BEGIN\n" + + " SELECT foo + 1 INTO bar;\n" + + "END\n" + + "$$ LANGUAGE plpgsql;"; + + Statements statements = CCJSqlParserUtil.parseStatements(sqlStr); + assertEquals(2, statements.size()); + } + + @Test + void testSimpleParse() throws JSQLParserException { + String sqlStr="select A,sdf,sch.tab.col from TABLE_A"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java index 06d1e3d54..bc33ad032 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java @@ -10,10 +10,12 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.JsonExpression; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statements; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.test.TestUtils; @@ -102,4 +104,33 @@ void testNextValueIssue1863() throws JSQLParserException { String sqlStr = "SELECT nextval('client_id_seq')"; assertSqlCanBeParsedAndDeparsed(sqlStr); } + + @Test + void testDollarQuotedText() throws JSQLParserException { + String sqlStr = "SELECT $tag$This\nis\na\nselect\ntest\n$tag$ from dual where a=b"; + PlainSelect st = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + + StringValue stringValue = st.getSelectItem(0).getExpression(StringValue.class); + + Assertions.assertEquals("This\nis\na\nselect\ntest\n", stringValue.getValue()); + } + + @Test + void testQuotedIdentifier() throws JSQLParserException { + String sqlStr = "SELECT \"This is a Test Column\" AS [Alias] from `This is a Test Table`"; + PlainSelect st = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + + Column column = st.getSelectItem(0).getExpression(Column.class); + Assertions.assertEquals("This is a Test Column", column.getUnquotedName()); + Assertions.assertEquals("\"This is a Test Column\"", column.getColumnName()); + + Alias alias = st.getSelectItem(0).getAlias(); + Assertions.assertEquals("Alias", alias.getUnquotedName()); + Assertions.assertEquals("[Alias]", alias.getName()); + + Table table = st.getFromItem(Table.class); + Assertions.assertEquals("This is a Test Table", table.getUnquotedName()); + Assertions.assertEquals("`This is a Test Table`", table.getName()); + + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java index 2888ed72c..ce1c5c633 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java @@ -15,7 +15,7 @@ import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor; import net.sf.jsqlparser.parser.CCJSqlParserTreeConstants; import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.parser.SimpleNode; +import net.sf.jsqlparser.parser.Node; import net.sf.jsqlparser.parser.Token; import net.sf.jsqlparser.schema.Column; @@ -39,13 +39,13 @@ public void testSelectASTColumn() throws JSQLParserException { for (SelectItem item : plainSelect.getSelectItems()) { SelectItem sei = (SelectItem) item; Column c = sei.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().beginColumn - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().beginColumn - 1, '#'); } @@ -55,7 +55,7 @@ public void testSelectASTColumn() throws JSQLParserException { @Test public void testSelectASTNode() throws JSQLParserException { String sql = "SELECT a, b FROM mytable order by b, c"; - SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node node = (Node) CCJSqlParserUtil.parseAST(sql); node.dump("*"); assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); } @@ -66,12 +66,12 @@ public void testSelectASTNode() throws JSQLParserException { // @Test // public void testSelectASTNodeSubSelect() throws JSQLParserException { // String sql = "SELECT * FROM mytable where 0<(select count(*) from mytable2)"; - // SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + // Node node = (Node) CCJSqlParserUtil.parseAST(sql); // node.dump("*"); // assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); // node.jjtAccept(new CCJSqlParserDefaultVisitor() { // @Override - // public Object visit(SimpleNode node, Object data) { + // public Object visit(Node node, Object data) { // if (node.getId() == CCJSqlParserTreeConstants.JJTSUBSELECT) { // subSelectStart = node.jjtGetFirstToken(); // subSelectEnd = node.jjtGetLastToken(); @@ -95,13 +95,13 @@ public void testSelectASTColumnLF() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); for (SelectItem item : plainSelect.getSelectItems()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '#'); } @@ -116,13 +116,13 @@ public void testSelectASTCommentLF() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); for (SelectItem item : plainSelect.getSelectItems()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '#'); } @@ -139,13 +139,13 @@ public void testSelectASTCommentCRLF() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); for (SelectItem item : plainSelect.getSelectItems()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '#'); } @@ -157,12 +157,12 @@ public void testSelectASTCommentCRLF() throws JSQLParserException { @Test public void testDetectInExpressions() throws JSQLParserException { String sql = "SELECT * FROM mytable WHERE a IN (1,2,3,4,5,6,7)"; - SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node node = (Node) CCJSqlParserUtil.parseAST(sql); node.dump("*"); assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); node.jjtAccept(new CCJSqlParserDefaultVisitor() { @Override - public Object visit(SimpleNode node, Object data) { + public Object visit(Node node, Object data) { if (node.getId() == CCJSqlParserTreeConstants.JJTINEXPRESSION) { subSelectStart = node.jjtGetFirstToken(); subSelectEnd = node.jjtGetLastToken(); @@ -183,12 +183,12 @@ public Object visit(SimpleNode node, Object data) { public void testSelectASTExtractWithCommentsIssue1580() throws JSQLParserException { String sql = "SELECT /* testcomment */ \r\n a, b FROM -- testcomment2 \r\n mytable \r\n order by b, c"; - SimpleNode root = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node root = (Node) CCJSqlParserUtil.parseAST(sql); List comments = new ArrayList<>(); root.jjtAccept(new CCJSqlParserDefaultVisitor() { @Override - public Object visit(SimpleNode node, Object data) { + public Object visit(Node node, Object data) { if (node.jjtGetFirstToken().specialToken != null) { // needed since for different nodes we got the same first token if (!comments.contains(node.jjtGetFirstToken().specialToken)) { @@ -207,7 +207,7 @@ public Object visit(SimpleNode node, Object data) { public void testSelectASTExtractWithCommentsIssue1580_2() throws JSQLParserException { String sql = "/* I want this comment */\n" + "SELECT order_detail_id, quantity\n" + "/* But ignore this one safely */\n" + "FROM order_details;"; - SimpleNode root = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node root = (Node) CCJSqlParserUtil.parseAST(sql); assertThat(root.jjtGetFirstToken().specialToken.image) .isEqualTo("/* I want this comment */"); 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 cc0cbda66..6518c78bb 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -89,6 +89,7 @@ public class SelectTest { private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @Test + @Disabled public void testMultiPartTableNameWithServerNameAndDatabaseNameAndSchemaName() throws Exception { final String statement = @@ -107,6 +108,7 @@ public void testMultiPartTableNameWithServerNameAndDatabaseNameAndSchemaName() } @Test + @Disabled public void testMultiPartTableNameWithServerNameAndDatabaseName() throws Exception { final String statement = "SELECT columnName FROM [server-name\\server-instance].databaseName..tableName"; @@ -123,6 +125,7 @@ public void testMultiPartTableNameWithServerNameAndDatabaseName() throws Excepti } @Test + @Disabled public void testMultiPartTableNameWithServerNameAndSchemaName() throws Exception { final String statement = "SELECT columnName FROM [server-name\\server-instance]..schemaName.tableName"; @@ -137,6 +140,7 @@ public void testMultiPartTableNameWithServerProblem() throws Exception { } @Test + @Disabled public void testMultiPartTableNameWithServerName() throws Exception { final String statement = "SELECT columnName FROM [server-name\\server-instance]...tableName"; diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java index 1a8f75d81..05b9e6bf5 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java @@ -13,7 +13,7 @@ import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor; import net.sf.jsqlparser.parser.CCJSqlParserTreeConstants; import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.parser.SimpleNode; +import net.sf.jsqlparser.parser.Node; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.create.view.CreateView; @@ -72,7 +72,7 @@ public StringBuilder visit(Column tableColumn, K parameters) { public void testCreateViewASTNode() throws JSQLParserException { String sql = "CREATE VIEW test AS SELECT a, b FROM mytable"; final StringBuilder b = new StringBuilder(sql); - SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node node = (Node) CCJSqlParserUtil.parseAST(sql); node.dump("*"); assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); @@ -80,7 +80,7 @@ public void testCreateViewASTNode() throws JSQLParserException { int idxDelta = 0; @Override - public Object visit(SimpleNode node, Object data) { + public Object visit(Node node, Object data) { if (CCJSqlParserTreeConstants.JJTCOLUMN == node.getId()) { b.insert(node.jjtGetFirstToken().beginColumn - 1 + idxDelta, '"'); idxDelta++;