From 57941c28b320a405180ca676b3f9b89edd0f7802 Mon Sep 17 00:00:00 2001 From: tw Date: Sun, 4 May 2025 23:22:16 +0200 Subject: [PATCH 001/123] reset to fixed dependency versions --- pom.xml | 25 ++++++++----------- .../OracleHierarchicalExpressionTest.java | 9 +++++++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index 98d67faa3..4ef519381 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ net.java.dev.javacc javacc - [7.0.13,) + 7.0.13 test @@ -59,13 +59,13 @@ org.assertj assertj-core - [3.25.3,) + 3.27.3 test org.apache.commons commons-lang3 - [3.14.0,) + 3.17.0 test @@ -173,7 +173,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.2.0 + 3.6.0 add-source @@ -192,16 +192,13 @@ maven-compiler-plugin - 3.10.1 + 3.13.0 11 11 true ${project.build.sourceEncoding} true - true - 128m - 2000m @@ -226,7 +223,7 @@ net.java.dev.javacc javacc - [7.0.13,) + [7.0.13,8) @@ -304,7 +301,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.11.2 attach-javadocs @@ -326,7 +323,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 @@ -349,7 +346,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.5.2 false @@ -364,7 +361,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.11 @@ -383,7 +380,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.28.0 + 2.43.0 origin/master 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; From 560e4076f70a97b82ef6289b7a013143a1a2f5ea Mon Sep 17 00:00:00 2001 From: tw Date: Sun, 4 May 2025 23:43:23 +0200 Subject: [PATCH 002/123] reintroduced forked compiling --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4ef519381..7e930064e 100644 --- a/pom.xml +++ b/pom.xml @@ -192,13 +192,15 @@ maven-compiler-plugin - 3.13.0 + 3.14.0 11 11 true ${project.build.sourceEncoding} true + 2000m + true From 849167cf9da0730e89f0527ce13909d274a9eeab Mon Sep 17 00:00:00 2001 From: tw Date: Sun, 4 May 2025 23:52:09 +0200 Subject: [PATCH 003/123] [maven-release-plugin] prepare release jsqlparser-5.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7e930064e..9fe4a57aa 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.2-SNAPSHOT + 5.2 JSQLParser library 2004 @@ -106,7 +106,7 @@ scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git https://github.com/JSQLParser/JSqlParser.git - HEAD + jsqlparser-5.2 From 4bf50ec5d19dc424c463f80ca43c917cbd663374 Mon Sep 17 00:00:00 2001 From: tw Date: Sun, 4 May 2025 23:52:12 +0200 Subject: [PATCH 004/123] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9fe4a57aa..da18b6e55 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.2 + 5.3-SNAPSHOT JSQLParser library 2004 @@ -106,7 +106,7 @@ scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git https://github.com/JSQLParser/JSqlParser.git - jsqlparser-5.2 + HEAD From 7be59ab74a7a3e0b1555575837fb9556df7a172f Mon Sep 17 00:00:00 2001 From: tw Date: Mon, 5 May 2025 00:01:29 +0200 Subject: [PATCH 005/123] [maven-release-plugin] rollback the release of jsqlparser-5.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da18b6e55..7e930064e 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.3-SNAPSHOT + 5.2-SNAPSHOT JSQLParser library 2004 From a3d5f908bdc704f6670f42d51a33f2cfd0fbb68a Mon Sep 17 00:00:00 2001 From: tw Date: Mon, 5 May 2025 00:05:13 +0200 Subject: [PATCH 006/123] added more stackmemory to compiler --- pom.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pom.xml b/pom.xml index 7e930064e..b293789f8 100644 --- a/pom.xml +++ b/pom.xml @@ -200,6 +200,9 @@ ${project.build.sourceEncoding} true 2000m + + -J-Xss4M + true From 838c834e40d98353870cbf4ea72d75760b43f4a1 Mon Sep 17 00:00:00 2001 From: tw Date: Mon, 5 May 2025 00:11:11 +0200 Subject: [PATCH 007/123] [maven-release-plugin] prepare release jsqlparser-5.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b293789f8..d9e5832e0 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.2-SNAPSHOT + 5.2 JSQLParser library 2004 @@ -106,7 +106,7 @@ scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git https://github.com/JSQLParser/JSqlParser.git - HEAD + jsqlparser-5.2 From c5d91d2b52001bc78f462c1edace49ae5760e448 Mon Sep 17 00:00:00 2001 From: tw Date: Mon, 5 May 2025 00:11:12 +0200 Subject: [PATCH 008/123] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d9e5832e0..daee429d2 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.2 + 5.3-SNAPSHOT JSQLParser library 2004 @@ -106,7 +106,7 @@ scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git https://github.com/JSQLParser/JSqlParser.git - jsqlparser-5.2 + HEAD From 9d1442e9a4800e24dbd24d73c5035ee76770eb69 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Mon, 12 May 2025 13:23:28 +0700 Subject: [PATCH 009/123] feat: JavaCC-8 - without syntactic Lookahead - `Node` replaces `SimpleNode` - removed incompatible `KeywordUtils` - updated `SimpleCharStream` Signed-off-by: Andreas Reichel --- build.gradle | 16 +- pom.xml | 31 +- .../expression/DateTimeLiteralExpression.java | 2 +- .../operators/relational/ExpressionList.java | 8 +- .../sf/jsqlparser/parser/ASTNodeAccess.java | 4 +- .../jsqlparser/parser/ASTNodeAccessImpl.java | 22 +- .../jsqlparser/parser/SimpleCharStream.java | 344 +++++++----------- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 9 +- .../parser/ASTNodeAccessImplTest.java | 2 +- .../parser/ParserKeywordsUtilsTest.java | 213 ----------- .../statement/insert/InsertTest.java | 2 +- .../statement/select/PostgresTest.java | 31 ++ .../statement/select/SelectASTTest.java | 34 +- .../util/deparser/CreateViewDeParserTest.java | 6 +- 14 files changed, 236 insertions(+), 488 deletions(-) delete mode 100644 src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java diff --git a/build.gradle b/build.gradle index 1f0924c03..1b8585f60 100644 --- a/build.gradle +++ b/build.gradle @@ -114,10 +114,18 @@ 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.1.0-SNAPSHOT') { changing = true } + testImplementation('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true } + javacc('org.javacc:core:8.1.0-SNAPSHOT') { changing = true } + javacc('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true } +} +configurations.configureEach { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group in ['org.javacc:core', 'org.javacc.generator']) { + // Check for updates every build + resolutionStrategy.cacheChangingModulesFor 30, 'seconds' + } + } } compileJavacc { diff --git a/pom.xml b/pom.xml index 98d67faa3..4834964b8 100644 --- a/pom.xml +++ b/pom.xml @@ -27,10 +27,16 @@ - net.java.dev.javacc - javacc - [7.0.13,) - test + org.javacc + core + 8.1.0-SNAPSHOT + pom + + + org.javacc.generator + java + 8.1.0-SNAPSHOT + 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/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 9ea68e0e4..1a9a349bb 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -97,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); } @@ -1090,7 +1090,7 @@ Statements Statements() #Statements: { JAVACODE List error_skipto(int kind) { ArrayList tokenImages = new ArrayList(); - ParseException e = generateParseException(); + ParseException e = generateParseException("test"); Token t; do { t = getNextToken(); @@ -3037,6 +3037,7 @@ PlainSelect PlainSelect() #PlainSelect: String windowName = null; WindowDefinition winDef; Table intoTempTable = null; + Distinct distinct; } { @@ -3059,11 +3060,11 @@ PlainSelect PlainSelect() #PlainSelect: | ( - { Distinct distinct = new Distinct(); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(); plainSelect.setDistinct(distinct); } [ LOOKAHEAD(2) "ON" "(" distinctOn=SelectItemsList() { plainSelect.getDistinct().setOnSelectItems(distinctOn); } ")" ] ) | - { Distinct distinct = new Distinct(true); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(true); plainSelect.setDistinct(distinct); } | { plainSelect.setMySqlSqlCalcFoundRows(true); } | 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/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/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/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 e12b51ed8..ddc578d26 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/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++; From 7d42ff614bd2cca45a0c5488a430fdc03f722142 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 13 May 2025 17:38:34 +0700 Subject: [PATCH 010/123] feat: Optimise performance - optimise the `LOOKAHEAD`, avoid syntactic lookaheads - disable `FunctionAllColumns()` in `PrimaryExpression` related to #2207 Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 243 +++++++++++------- 1 file changed, 154 insertions(+), 89 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 89d7227e2..2802b0b96 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) @@ -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) @@ -3001,6 +3037,7 @@ PlainSelect PlainSelect() #PlainSelect: String windowName = null; WindowDefinition winDef; Table intoTempTable = null; + Distinct distinct; } { @@ -3023,11 +3060,11 @@ PlainSelect PlainSelect() #PlainSelect: | ( - { Distinct distinct = new Distinct(); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(); plainSelect.setDistinct(distinct); } [ LOOKAHEAD(2) "ON" "(" distinctOn=SelectItemsList() { plainSelect.getDistinct().setOnSelectItems(distinctOn); } ")" ] ) | - { Distinct distinct = new Distinct(true); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(true); plainSelect.setDistinct(distinct); } | { plainSelect.setMySqlSqlCalcFoundRows(true); } | @@ -3069,8 +3106,9 @@ PlainSelect PlainSelect() #PlainSelect: [ LOOKAHEAD(2) preferringClause=PreferringClause() { plainSelect.setPreferringClause(preferringClause); } [LOOKAHEAD(2) ( - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() - | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) + LOOKAHEAD(2) expressionList=ComplexExpressionList() + | + "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) { preferringClause.setPartitionExpressionList(expressionList, partitionByBrackets); @@ -3091,7 +3129,7 @@ PlainSelect PlainSelect() #PlainSelect: ] [ LOOKAHEAD( ) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ] [ LOOKAHEAD(2) { plainSelect.setEmitChanges(true); } ] - [ LOOKAHEAD(LimitBy()) limit = LimitBy() { plainSelect.setLimitBy(limit); } ] + [ LOOKAHEAD(7) limit = LimitBy() { plainSelect.setLimitBy(limit); } ] [ LOOKAHEAD() limit = LimitWithOffset() { plainSelect.setLimit(limit); } ] [ LOOKAHEAD() offset = Offset() { plainSelect.setOffset(offset); } ] [ LOOKAHEAD(, { limit==null }) limit = LimitWithOffset() { plainSelect.setLimit(limit); } ] @@ -3639,11 +3677,11 @@ FromItem FromItem() #FromItem: ( LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) fromItem = Values() | - LOOKAHEAD( TableFunction() ) fromItem=TableFunction() + LOOKAHEAD(16) fromItem=TableFunction() | LOOKAHEAD(3) fromItem=Table() | - LOOKAHEAD( ParenthesedFromItem() ) fromItem = ParenthesedFromItem() + LOOKAHEAD(ParenthesedFromItem()) fromItem = ParenthesedFromItem() | LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) ( fromItem=ParenthesedSelect() @@ -3941,17 +3979,18 @@ Expression PriorTo(): } { ( - LOOKAHEAD(PreferenceTermTerminal(), {!interrupted}) left=PreferenceTermTerminal() - | "(" left=PreferenceTerm() ")" { left = new ParenthesedExpressionList(left); } + LOOKAHEAD(3) left=PreferenceTermTerminal() + | + "(" left=PreferenceTerm() ")" { left = new ParenthesedExpressionList(left); } ) { result = left; } ( - LOOKAHEAD(2) - + LOOKAHEAD(2) ( - LOOKAHEAD(PreferenceTermTerminal(), {!interrupted}) right=PreferenceTermTerminal() - | "(" right=PreferenceTerm() ")" { left = new ParenthesedExpressionList(right); } + LOOKAHEAD(3) right=PreferenceTermTerminal() + | + "(" right=PreferenceTerm() ")" { left = new ParenthesedExpressionList(right); } ) { result = new PriorTo(left, right); @@ -4469,8 +4508,7 @@ Expression AndExpression() : } { ( - LOOKAHEAD(Condition(), {!interrupted}) - left=Condition() + LOOKAHEAD(Condition(), {!interrupted}) left=Condition() | [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] "(" left=XorExpression() ")" {left = new ParenthesedExpressionList(left); if (not) { left = new NotExpression(left, exclamationMarkNot); not = false; } } @@ -4481,8 +4519,7 @@ Expression AndExpression() : { boolean useOperator = false; } ( | {useOperator=true;} ) ( - LOOKAHEAD(Condition(), {!interrupted}) - right=Condition() + LOOKAHEAD(Condition(), {!interrupted}) right=Condition() | [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] "(" right=XorExpression() ")" {right = new ParenthesedExpressionList(right); if (not) { right = new NotExpression(right, exclamationMarkNot); not = false; } } @@ -4508,8 +4545,9 @@ Expression Condition(): { [ LOOKAHEAD(2) ( { not=true; } | "!" { not=true; exclamationMarkNot=true; })] ( - LOOKAHEAD(RegularCondition()) result=RegularCondition() - | result=SQLCondition() + LOOKAHEAD(RegularCondition(), {!interrupted}) result=RegularCondition() + | + result=SQLCondition() ) { return not?new NotExpression(result, exclamationMarkNot):result; } @@ -4610,28 +4648,29 @@ Expression SQLCondition(): { ( result=ExistsExpression() - | LOOKAHEAD(InExpression() , {!interrupted}) result=InExpression() - | LOOKAHEAD(OverlapsCondition(), {!interrupted}) result=OverlapsCondition() + | LOOKAHEAD( OverlapsCondition(), {!interrupted}) result=OverlapsCondition() | left = SimpleExpression() { result = left; } [ LOOKAHEAD(2) ( - LOOKAHEAD(ExcludesExpression()) result=ExcludesExpression(left) + LOOKAHEAD(3, {!interrupted}) result=InExpression(left) + | + LOOKAHEAD(3) result=ExcludesExpression(left) | - LOOKAHEAD(IncludesExpression()) result=IncludesExpression(left) + LOOKAHEAD(3) result=IncludesExpression(left) | LOOKAHEAD(2) result=Between(left) | result = MemberOfExpression(left) | - LOOKAHEAD(IsNullExpression()) result=IsNullExpression(left) + LOOKAHEAD(3) result=IsNullExpression(left) | - LOOKAHEAD(IsBooleanExpression()) result=IsBooleanExpression(left) + LOOKAHEAD(3) result=IsBooleanExpression(left) | - LOOKAHEAD(IsUnknownExpression()) result=IsUnknownExpression(left) + LOOKAHEAD(3) result=IsUnknownExpression(left) | LOOKAHEAD(2) result=LikeExpression(left) | - LOOKAHEAD(IsDistinctExpression()) result=IsDistinctExpression(left) + LOOKAHEAD(3) result=IsDistinctExpression(left) | result=SimilarToExpression(left) ) @@ -4640,17 +4679,15 @@ Expression SQLCondition(): { return result; } } -Expression InExpression() #InExpression : +Expression InExpression(Expression leftExpression) #InExpression : { Token token; int oldOracleJoin = 0; boolean usingNot = false; boolean usingGlobal = false; - Expression leftExpression; Expression rightExpression; } { - leftExpression=SimpleExpression() [ "(" "+" ")" { oldOracleJoin=EqualsTo.ORACLE_JOIN_RIGHT; } ] [ { usingGlobal=true; } ] @@ -4658,10 +4695,8 @@ Expression InExpression() #InExpression : ( LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } - | LOOKAHEAD(3) rightExpression = Function() - | LOOKAHEAD(ParenthesedSelect(), {!interrupted}) rightExpression = ParenthesedSelect() - | LOOKAHEAD(3) rightExpression = ParenthesedExpressionList() - | rightExpression = SimpleExpression() + | + rightExpression = Expression() ) { InExpression inExpression = new InExpression(leftExpression, rightExpression) @@ -4715,7 +4750,7 @@ Expression Between(Expression leftExpression) : ( LOOKAHEAD( 3 ) betweenExpressionStart = ParenthesedSelect() | - LOOKAHEAD( RegularCondition() ) betweenExpressionStart = RegularCondition() + LOOKAHEAD( 11 ) betweenExpressionStart = RegularCondition() | betweenExpressionStart = SimpleExpression() ) @@ -4724,7 +4759,7 @@ Expression Between(Expression leftExpression) : ( LOOKAHEAD( 3 ) betweenExpressionEnd = ParenthesedSelect() | - LOOKAHEAD( RegularCondition() ) betweenExpressionEnd = RegularCondition() + LOOKAHEAD( 11 ) betweenExpressionEnd = RegularCondition() | betweenExpressionEnd = SimpleExpression() ) @@ -4946,8 +4981,7 @@ ExpressionList SimpleExpressionList(): ( LOOKAHEAD(2, {!interrupted} ) "," ( - // @todo: Check hot to avoid this expensive look ahead - LOOKAHEAD( LambdaExpression() ) expr=LambdaExpression() + LOOKAHEAD( 6 ) expr=LambdaExpression() | expr=SimpleExpression() ) @@ -4994,7 +5028,8 @@ ExpressionList ComplexExpressionList(): { ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() - | expr=Expression() + | + expr=Expression() ) { expressions.add(expr); @@ -5005,8 +5040,7 @@ ExpressionList ComplexExpressionList(): ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() | - // @todo: Check hot to avoid this expensive look ahead - LOOKAHEAD( LambdaExpression() ) expr=LambdaExpression() + LOOKAHEAD( 6 ) expr=LambdaExpression() | expr=Expression() ) { expressions.add(expr); } )* @@ -5070,11 +5104,15 @@ Expression ComparisonItem() : } { ( - LOOKAHEAD( AnyComparisonExpression() ) retval=AnyComparisonExpression() - | LOOKAHEAD(3) retval=SimpleExpression() - | LOOKAHEAD(3) retval=ParenthesedExpressionList() - | LOOKAHEAD(3) retval=RowConstructor() - | retval=PrimaryExpression() + LOOKAHEAD( 6 ) retval=AnyComparisonExpression() + | + LOOKAHEAD( 3 ) retval=SimpleExpression() + | + LOOKAHEAD( 3 ) retval=ParenthesedExpressionList() + | + LOOKAHEAD( 3 ) retval=RowConstructor() + | + retval=PrimaryExpression() ) { @@ -5089,14 +5127,13 @@ Expression AnyComparisonExpression() : } { ( - ( - { anyType = AnyType.ANY; } - | { anyType = AnyType.SOME; } - | { anyType = AnyType.ALL; } - ) - - select = ParenthesedSelect() + { anyType = AnyType.ANY; } + | + { anyType = AnyType.SOME; } + | + { anyType = AnyType.ALL; } ) + select = ParenthesedSelect() { return new AnyComparisonExpression(anyType, select); } @@ -5109,17 +5146,8 @@ Expression SimpleExpression(): Token operation = null; } { - - ( - [ LOOKAHEAD(UserVariable() ("=" | ":=") ) - user = UserVariable() - ( operation = "=" | operation = ":=" ) - ] - - ( - retval=ConcatExpression() - ) - ) + [ LOOKAHEAD( 5 ) user = UserVariable() ( operation = "=" | operation = ":=" ) ] + retval=ConcatExpression() { if (user != null) { VariableAssignment assignment = new VariableAssignment(); @@ -5177,7 +5205,7 @@ Expression BitwiseAndOr(): rightExpression=AdditiveExpression() { - BinaryExpression binExp = (BinaryExpression) result; + BinaryExpression binExp = (BinaryExpression) result; binExp.setLeftExpression(leftExpression); binExp.setRightExpression(rightExpression); leftExpression = result; @@ -5319,7 +5347,7 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) retval=CharacterPrimary() - | LOOKAHEAD( ImplicitCast(), {!interrupted}) retval=ImplicitCast() + | LOOKAHEAD(5, {!interrupted}) retval=ImplicitCast() | retval = JdbcParameter() @@ -5329,7 +5357,7 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) retval=NumericBind() - | LOOKAHEAD( ExtractExpression() , {!interrupted}) retval=ExtractExpression() + | LOOKAHEAD(4 , {!interrupted}) retval=ExtractExpression() | LOOKAHEAD(3) retval=MySQLGroupConcat() @@ -5341,7 +5369,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(16) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] | LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; } @@ -5351,13 +5381,13 @@ Expression PrimaryExpression() #PrimaryExpression: | token= { retval = new HexValue(token.image); } - | LOOKAHEAD(2, {!interrupted}) retval=CastExpression() - - | LOOKAHEAD(AllColumns()) retval=AllColumns() + | LOOKAHEAD(3) retval=AllColumns() - | LOOKAHEAD(AllTableColumns()) retval=AllTableColumns() + | LOOKAHEAD(16) retval=AllTableColumns() - | LOOKAHEAD(FunctionAllColumns()) retval=FunctionAllColumns() + // See issue #2207 + // there is a huge! performance deterioration from this production + //| LOOKAHEAD(FunctionAllColumns()) retval=FunctionAllColumns() // support timestamp expressions | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new TimeKeyExpression(token.image); } @@ -5390,9 +5420,9 @@ Expression PrimaryExpression() #PrimaryExpression: | "{ts" token= "}" { retval = new TimestampValue(token.image); } - | LOOKAHEAD( Select() , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() + | LOOKAHEAD( 17 , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() - | LOOKAHEAD( ParenthesedSelect() , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() + | LOOKAHEAD( 17 , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() | ( @@ -5979,7 +6009,7 @@ JsonAggregateFunction JsonAggregateFunction() : { {result.setAnalyticType(AnalyticType.OVER);} "(" [ - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() + (LOOKAHEAD(3) expressionList=ComplexExpressionList() | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) ] [olist=OrderByElements() ] @@ -6086,7 +6116,7 @@ void windowFun(AnalyticExpression retval):{ [ LOOKAHEAD(2) "(" [ - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() + (LOOKAHEAD(3) expressionList=ComplexExpressionList() | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) ] ")" { winDef.setPartitionExpressionList(expressionList, partitionByBrackets); retval.setType(AnalyticType.WITHIN_GROUP_OVER); } @@ -6103,7 +6133,7 @@ WindowDefinition windowDefinition() : { } { "(" [ - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() + (LOOKAHEAD(3) expressionList=ComplexExpressionList() | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) ] [olist=OrderByElements() ] @@ -6214,7 +6244,7 @@ CastExpression ImplicitCast() #ImplicitCast: int scale = -1; } { - colDataType = DataType() + colDataType = DataType() ( tk2 = | @@ -6463,7 +6493,7 @@ Function SpecialStringFunctionWithNamedParameters() : "(" ( - LOOKAHEAD(NamedExpressionListExprFirst(), { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() + LOOKAHEAD(6, { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() | expressionList=ExpressionList() ) @@ -6554,7 +6584,7 @@ Function InternalFunction(boolean escaped): // tricky lookahead since we do need to support the following constructs // schema.f1().f2() - Function with Function Column // schema.f1().f2.f3 - Function with Attribute Column - LOOKAHEAD( Function() ) attributeExpression=Function() { retval.setAttribute(attributeExpression); } + LOOKAHEAD( 6 ) attributeExpression=Function() { retval.setAttribute(attributeExpression); } | attributeColumn=Column() { retval.setAttribute(attributeColumn); } ) @@ -9195,6 +9225,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(); @@ -9263,15 +9330,13 @@ TranscodingFunction TranscodingFunction() #TranscodingFunction : { "(" ( - LOOKAHEAD(ColDataType() ",") ( - colDataType = ColDataType() - "," expression = Expression() - [ "," style = { transcodingName = style.image; } ] + LOOKAHEAD(4) colDataType = ColDataType() + "," expression = Expression() + [ "," style = { transcodingName = style.image; } ] - { - transcodingFunction = new TranscodingFunction(colDataType, expression, transcodingName); - } - ) + { + transcodingFunction = new TranscodingFunction(colDataType, expression, transcodingName); + } | ( expression = Expression() From d35028c557b742fc1953b635756730d0adefada1 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 13 May 2025 17:40:31 +0700 Subject: [PATCH 011/123] style: Disable obsolete pseudo benchmark Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/statement/select/SpeedTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java index 21565c78f..19908e675 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.statement.simpleparsing.CCJSqlParserManagerTest; import net.sf.jsqlparser.test.TestException; import net.sf.jsqlparser.util.TablesNamesFinder; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.BufferedReader; @@ -30,6 +31,9 @@ public class SpeedTest { private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @Test + @Disabled + // replaced by a proper JMH based benchmark + // @todo: remove this eventually public void testSpeed() throws Exception { // all the statements in testfiles/simple_parsing.txt BufferedReader in = new BufferedReader( From fe860ddd18f28f8b26ffaef252abc247341bfab6 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 13 May 2025 17:41:15 +0700 Subject: [PATCH 012/123] feat: adopt proper JMH based benchmark Signed-off-by: Andreas Reichel --- README.md | 14 +- build.gradle | 11 +- src/site/sphinx/_static/jmh_results.txt | 20 + src/site/sphinx/contribution.rst | 17 +- .../benchmark/DynamicParserRunner.java | 31 + .../benchmark/JSQLParserBenchmark.java | 80 + .../benchmark/LatestClasspathRunner.java | 19 + .../jsqlparser/benchmark/SqlParserRunner.java | 12 + .../net/sf/jsqlparser/performance.sql | 2101 +++++++++++++++++ 9 files changed, 2302 insertions(+), 3 deletions(-) create mode 100644 src/site/sphinx/_static/jmh_results.txt create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java create mode 100644 src/test/resources/net/sf/jsqlparser/performance.sql diff --git a/README.md b/README.md index ed1b89d27..9d8db30b8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [JSqlParser 5.1 Website](https://jsqlparser.github.io/JSqlParser) drawing +# [JSqlParser 5.2 Website](https://jsqlparser.github.io/JSqlParser) drawing [![CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) @@ -69,6 +69,18 @@ JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later de Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. +## Performan ce + +Unfortunately the released JSQLParser-5.2 shows a performance deterioration caused by commit [30cf5d7](https://github.com/JSQLParser/JSqlParser/commit/30cf5d7b930ae0a076f49deb5cc841d39e62b3dc) related to `FunctionAllColumns()`. +This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been added to avoid such regressions in the future. Further all `LOOKAHEADS` have been revised one by one, and we have gained back a very good performance of the Parser. + +```text +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op <-- `FunctionAllColumns()` disabled +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op +``` + ## [Supported Grammar and Syntax](https://jsqlparser.github.io/JSqlParser/syntax.html) **JSqlParser** aims to support the SQL standard as well as all major RDBMS. Any missing syntax or features can be added on demand. diff --git a/build.gradle b/build.gradle index 1f0924c03..822796e85 100644 --- a/build.gradle +++ b/build.gradle @@ -117,7 +117,8 @@ dependencies { testImplementation 'net.java.dev.javacc:javacc:+' javacc 'net.java.dev.javacc:javacc:+' - + jmh 'org.openjdk.jmh:jmh-core:1.37' + jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' } compileJavacc { @@ -633,3 +634,11 @@ tasks.register('upload') { check { dependsOn jacocoTestCoverageVerification } + +jmh { + includes = ['.*JSQLParserBenchmark.*'] + warmupIterations = 3 + fork = 3 + iterations = 10 + timeOnIteration = '1s' +} diff --git a/src/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt new file mode 100644 index 000000000..e5d28aa38 --- /dev/null +++ b/src/site/sphinx/_static/jmh_results.txt @@ -0,0 +1,20 @@ +-- Optimised LOOKAHEADS (replacing all syntactic lookahead by numeric lookaheads) +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 264.132 ± 9.636 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 415.744 ± 20.602 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 89.387 ± 1.916 ms/op +JSQLParserBenchmark.parseSQLStatements 5.0 avgt 15 68.810 ± 2.591 ms/op +JSQLParserBenchmark.parseSQLStatements 4.9 avgt 15 60.515 ± 1.650 ms/op +JSQLParserBenchmark.parseSQLStatements 4.8 avgt 15 60.002 ± 1.259 ms/op +JSQLParserBenchmark.parseSQLStatements 4.7 avgt 15 73.291 ± 3.049 ms/op + +-- Optimised LOOKAHEADS (replacing huge numeric lookaheads with syntactic lookaheads again) +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 249.408 ± 11.340 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 ms/op + +-- Disable `FunctionAllColumns()` +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op \ No newline at end of file diff --git a/src/site/sphinx/contribution.rst b/src/site/sphinx/contribution.rst index bfb3b3571..9793e8947 100644 --- a/src/site/sphinx/contribution.rst +++ b/src/site/sphinx/contribution.rst @@ -77,7 +77,22 @@ The JSQLParser is generated by ``JavaCC`` based on the provided Grammar. The Gra mvn verify - 7) Create your `GitHub Pull Request `_ + 7) Verify the performance and avoid any deterioration + + .. code-block:: shell + :caption: Gradle `check` Task + + gradle jmh + + .. code-block:: text + :caption: JMH performance results + + Benchmark (version) Mode Cnt Score Error Units + JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op + JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op + JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op + + 8) Create your `GitHub Pull Request `_ Manage Reserved Keywords ------------------------------ diff --git a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java new file mode 100644 index 000000000..021e04f64 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java @@ -0,0 +1,31 @@ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.lang.reflect.Method; +import java.net.URLClassLoader; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class DynamicParserRunner implements SqlParserRunner { + private final Method parseStatementsMethod; + + public DynamicParserRunner(URLClassLoader loader) throws Exception { + Class utilClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParserUtil"); + Class ccjClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParser"); + Class consumerClass = Class.forName("java.util.function.Consumer"); // interface OK + parseStatementsMethod = utilClass.getMethod( + "parseStatements", + String.class, + ExecutorService.class, + consumerClass); + } + + @Override + public Statements parseStatements(String sql, + ExecutorService executorService, + Consumer consumer) throws Exception { + return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null); + } +} diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java new file mode 100644 index 000000000..d81b1e01b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -0,0 +1,80 @@ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; +import org.openjdk.jmh.annotations.*; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.concurrent.*; +import java.util.function.Consumer; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +public class JSQLParserBenchmark { + + private String sqlContent; + private ExecutorService executorService; + + SqlParserRunner runner; + + // @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" }) + @Param({"latest", "5.2", "5.1"}) + public String version; + + @Setup(Level.Trial) + public void setup() throws Exception { + if ("latest".equals(version)) { + runner = new LatestClasspathRunner(); // direct call, no reflection + } else { + Path jarPath = downloadJsqlparserJar(version); + URLClassLoader loader = new URLClassLoader(new URL[] {jarPath.toUri().toURL()}, null); + runner = new DynamicParserRunner(loader); + } + + // Adjust path as necessary based on where source root is during test execution + Path path = Paths.get("src/test/resources/net/sf/jsqlparser/performance.sql"); + sqlContent = Files.readString(path, StandardCharsets.UTF_8); + executorService = Executors.newSingleThreadExecutor(); + } + + private Path downloadJsqlparserJar(String version) throws IOException { + String jarUrl = String.format( + "https://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/%s/jsqlparser-%s.jar", + version, version); + + Path cacheDir = Paths.get("build/libs/downloaded-jars"); + Files.createDirectories(cacheDir); + Path jarFile = cacheDir.resolve("jsqlparser-" + version + ".jar"); + + if (!Files.exists(jarFile)) { + System.out.println("Downloading " + version); + try (InputStream in = new URL(jarUrl).openStream()) { + Files.copy(in, jarFile); + } + } + + return jarFile; + } + + @Benchmark + public void parseSQLStatements() throws Exception { + final Statements statements = runner.parseStatements( + sqlContent, + executorService, + (Consumer) parser -> { + // No-op consumer (or you can log/validate each parser if desired) + }); + assert statements.size() == 4; + } + + @TearDown(Level.Trial) + public void tearDown() { + executorService.shutdown(); + } +} diff --git a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java new file mode 100644 index 000000000..17bbf8e4b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java @@ -0,0 +1,19 @@ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class LatestClasspathRunner implements SqlParserRunner { + + @Override + public Statements parseStatements(String sql, + ExecutorService executorService, + Consumer consumer) throws Exception { + return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService, + consumer); + } +} + diff --git a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java new file mode 100644 index 000000000..a3ef61afc --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java @@ -0,0 +1,12 @@ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public interface SqlParserRunner { + Statements parseStatements(String sql, ExecutorService executorService, + Consumer consumer) throws Exception; +} diff --git a/src/test/resources/net/sf/jsqlparser/performance.sql b/src/test/resources/net/sf/jsqlparser/performance.sql new file mode 100644 index 000000000..0727f0a14 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/performance.sql @@ -0,0 +1,2101 @@ +-- complex-lateral-select-request.txt +SELECT +O.ORDERID, +O.CUSTNAME, +OL.LINETOTAL, +OC.ORDCHGTOTAL, +OT.TAXTOTAL +FROM +ORDERS O, +LATERAL ( +SELECT +SUM(NETAMT) AS LINETOTAL +FROM +ORDERLINES LINES +WHERE +LINES.ORDERID=O.ORDERID +) AS OL, +LATERAL ( +SELECT +SUM(CHGAMT) AS ORDCHGTOTAL +FROM +ORDERCHARGES CHARGES +WHERE +LINES.ORDERID=O.ORDERID +) AS OC, +LATERAL ( +SELECT +SUM(TAXAMT) AS TAXTOTAL +FROM +ORDERTAXES TAXES +WHERE +TAXES.ORDERID=O.ORDERID +) AS OT +; + +-- large-sql-issue-235.txt +SELECT + 'CR' AS `^CR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -3) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -3) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^P3Q TRR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -2) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -2) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^P2Q TRR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -1) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -1) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^PQ TRR`, + (1 - (SUM((CASE + WHEN ((ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = 0) + AND (`tbl`.`AS` = 'Cancelled')) THEN 1 + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN 1 + ELSE 0 + END)))) AS `^CQ TRR` + FROM + `tbl` + GROUP BY + 'CR' LIMIT 25000 +; + +-- large-sql-issue-566.txt +SELECT "CAMPAIGNID","TARGET_SOURCE","NON_INDV_TYPE","GROUP_SPONSOR","SEGMNTS","COUNTRY_CD","TARGET_STATE","TARGET_CITY","TARGET_ZIP","SIC_CLASS","NAICS_CLASS","GENDER_CD","OCCUPATION","CREDIT_SCORE","MARITAL_STATUS","IMPORT_ID","BIRTH_DT","STATUS" + FROM ( + SELECT + X.CAMPAIGNID, + X.FIELDNAME, + CASE WHEN Y.VALUE IS NULL THEN 'ALL' + ELSE Y.VALUE END AS VALUE + FROM + --CREATES A CARTESIAN JOIN TO COMBINE ALL CHARACTERISTICS WITH CAMPAIGN + (SELECT + CAMPAIGNID, + FIELDNAME + FROM CAMPAIGN + CROSS JOIN (SELECT DISTINCT FIELDNAME + FROM FIELDCRITERIA)) X + LEFT JOIN + --RETURNS ALL AVAILABLE CAMPAIGN CHARACTERISTS + ( + SELECT + CAMPAIGNID, + FIELDNAME, + (CASE FIELDNAME + WHEN U'BUSINESSTYPE' THEN D.DISPLAYVALUE + WHEN U'LEADTARGETSOURCE' THEN E.DISPLAYVALUE + ELSE VALUE END) AS VALUE + FROM FIELDCRITERIA A, STRINGFIELDCRITERIA_VALUE B + LEFT JOIN (SELECT + B.CODE, + B.DISPLAYVALUE, + LOOKUPNAME + FROM LOOKUPLIST A, LOOKUPVALUE B + WHERE A.ID = B.LOOKUPLIST_ID AND LOOKUPNAME = 'NONINDIVIDUALTYPE') D ON B.VALUE = D.CODE + LEFT JOIN (SELECT + B.CODE, + B.DISPLAYVALUE, + LOOKUPNAME + FROM LOOKUPLIST A, LOOKUPVALUE B + WHERE A.ID = B.LOOKUPLIST_ID AND LOOKUPNAME = 'LEADTARGETSOURCE') E ON B.VALUE = E.CODE + , + CAMPAIGN C + WHERE A.ID = B.FIELD_CRITERIA_ID + AND A.CRITERIA_ID = C.ID + ) Y ON X.CAMPAIGNID = Y.CAMPAIGNID AND X.FIELDNAME = Y.FIELDNAME + ) + PIVOT (MAX(VALUE) + FOR FIELDNAME + IN + ('LEADTARGETSOURCE' AS TARGET_SOURCE, 'BUSINESSTYPE' AS NON_INDV_TYPE, 'GROUPSPONSOR' AS GROUP_SPONSOR, 'SEGMENTS' AS SEGMNTS, 'COUNTRYCD' AS COUNTRY_CD, 'STATEPROVCD' AS TARGET_STATE, + 'CITY' AS TARGET_CITY, 'POSTALCODE' AS TARGET_ZIP, 'SICCLASSIFICATION' AS SIC_CLASS, 'NAICSCLASSIFICATION' AS NAICS_CLASS, 'GENDERCD' AS GENDER_CD, 'OCCUPATION' AS OCCUPATION, 'CREDITSCORE' AS CREDIT_SCORE, + 'MARITALSTATUSCD' AS MARITAL_STATUS, 'IMPORTID' AS IMPORT_ID, 'BIRTHDATE' AS BIRTH_DT, 'STATUS' AS STATUS)) +; + +-- large-sql-issue-923.txt +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + CLM.STATUS_C, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + EPPCL.PRODUCT_TYPE, + CLM.SERVICE_START_DATE, + CLM.SERVICE_END_DATE, + CLM.DATE_RECEIVED, + CLM_CS.NAME, + CLM.STATUS_DATE, + CLM_APSTS.ABBR, + CLM_CF.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + GRP.PLAN_GRP_NAME, + SERREN_2.NPI, + SERREN.PROV_NAME, + D_VTN.TAX_ID, + VENCLM.VENDOR_NAME, + (CLM.TOT_BILLED_AMT), + (CLM.TOT_NET_PAYABLE), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME), + POS.CITY, + POS_ST.ABBR, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + POS_TYPE.NAME, + POS.POS_CODE, + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END, + CLM_MAP5.INTERNAL_ID, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLAIM_FORMAT CLM_CF RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_FORMAT_C=CLM_CF.CLAIM_FORMAT_C) + LEFT OUTER JOIN ZC_CLM_STATUS CLM_CS ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN ZC_CLM_AP_STAT CLM_APSTS ON (CLM.AP_STS_C=CLM_APSTS.AP_STS_C) + LEFT OUTER JOIN CLARITY_POS POS ON (CLM.LOC_ID=POS.POS_ID) + LEFT OUTER JOIN ZC_POS_TYPE POS_TYPE ON (POS.POS_TYPE_C=POS_TYPE.POS_TYPE_C) + LEFT OUTER JOIN ZC_STATE POS_ST ON (POS.STATE_C=POS_ST.STATE_C AND POS_ST.INTERNAL_ID >= 0 AND POS_ST.INTERNAL_ID <= 51) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN AP_CLAIM AOC ON (CLM.ORIG_ADJST_CLM_ID=AOC.CLAIM_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP5 ON (AOC.CLAIM_ID=CLM_MAP5.CID AND AOC.CM_LOG_OWNER_ID=CLM_MAP5.CM_LOG_OWNER_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END BETWEEN (CASE + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ) Like 't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) AND (CASE + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ) Like't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) + AND + ( + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:7,Optional) + ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:9,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:13) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + EOB_CODE.ROUTE_FROM_DISC_C, + EOB_CODE.MNEMONIC +FROM + ZC_POS_TYPE CLMPOS RIGHT OUTER JOIN AP_CLAIM_PX CLD ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END BETWEEN (CASE + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ) Like 't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) AND (CASE + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ) Like't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) + AND + ( + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:7,Optional) + ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:9,Optional) + AND + EOB_CODE.CODE_TYPE_C IN ( 2 ) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:13) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME +FROM + CLARITY_EOB_CODE EOB_CODE +WHERE + EOB_CODE.CODE_TYPE_C = 2 +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + EAP.PROC_CODE, + CLM_CS.NAME, + CLM.STATUS_DATE, + CKR.CHECK_STATUS_C, + CLM_APSTS.ABBR, + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + EOB_CODE2.MNEMONIC, + EOB_CODE2.CODE_TYPE_C, + EOB_CODE.CODE_TYPE_C, + EOB_CODE2.EOB_CODE_NAME, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLM_STATUS CLM_CS RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN ZC_CLM_AP_STAT CLM_APSTS ON (CLM.AP_STS_C=CLM_APSTS.AP_STS_C) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN CLARITY_EAP EAP ON (CLD.PROC_ID=EAP.PROC_ID) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN ( + SELECT + PRV_SPEC.PROV_ID PROV_ID, + PRV_SPEC.SPECIALTY_C SPECIALTY_C +FROM + CLARITY_SER_SPEC PRV_SPEC +WHERE LINE=1 +group by PROV_ID,SPECIALTY_C + ) D_PRV_SPEC ON (SERREN.PROV_ID=D_PRV_SPEC.PROV_ID) + LEFT OUTER JOIN ZC_SPECIALTY ZC_SPEC ON (D_PRV_SPEC.SPECIALTY_C=ZC_SPEC.SPECIALTY_C) + LEFT OUTER JOIN CLARITY_SER_ADDR SERRENADDR ON (SERREN.PROV_ID=SERRENADDR.PROV_ID) + LEFT OUTER JOIN ZC_STATE SERRENST ON (SERRENADDR.STATE_C=SERRENST.STATE_C AND SERRENST.INTERNAL_ID >= 0 AND SERRENST.INTERNAL_ID <= 51) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END Is Null + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:7,Optional) + AND + ( + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:9,Optional) + ) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,{'Original Claim'},User:13) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + CLD.LINE, + CLM.ACCT_NUM_WITH_VEN +, + CLM_CF.NAME, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + VENCLM.VENDOR_NAME, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + SERREN.PROV_NAME, + EAP.PROC_CODE, + CLM.TYPE_OF_BILL, + CLM_CS.NAME, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end), + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end), + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end), + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CLM.DATE_RECEIVED, + CLM.SERVICE_END_DATE, + WQ.WORKQUEUE_NAME, + CLM.SERVICE_START_DATE, + CLD.POS_TYPE_C, + CLMPOS.NAME, + POS.POS_NAME, + sum(coalesce(CLD.OVERRIDE_ALLD_AMT,CLD.ALLOWED_AMT,0)), + CLD.NET_PAYABLE, + sum(coalesce(CLD.OVRD_COPAY,CLD.COPAYMENT,0)), + sum(coalesce(CLD.OVRD_COINS,CLD.COINSURANCE,0)), + sum(CLD.BILLED_AMT), + EAFMAP.INTERNAL_ID, + sum(coalesce(CLD.OVRD_DEDUCTIBLE,CLD.DEDUCTIBLE,0)), + SUM(CLD.PRIM_PAT_PORTION), + sum(CLD.PRIM_INS_AMOUNT), + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST, + CLD.BILLED_AMT +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLAIM_FORMAT CLM_CF RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_FORMAT_C=CLM_CF.CLAIM_FORMAT_C) + LEFT OUTER JOIN ZC_CLM_STATUS CLM_CS ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN CLARITY_POS POS ON (CLM.LOC_ID=POS.POS_ID) + LEFT OUTER JOIN EAF_MAP EAFMAP ON (EAFMAP.CID=POS.POS_ID AND POS.CM_LOG_OWNER_ID=EAFMAP.CM_LOG_OWNER_ID) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN CLARITY_EAP EAP ON (CLD.PROC_ID=EAP.PROC_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN ( + SELECT + PRV_SPEC.PROV_ID PROV_ID, + PRV_SPEC.SPECIALTY_C SPECIALTY_C +FROM + CLARITY_SER_SPEC PRV_SPEC +WHERE LINE=1 +group by PROV_ID,SPECIALTY_C + ) D_PRV_SPEC ON (SERREN.PROV_ID=D_PRV_SPEC.PROV_ID) + LEFT OUTER JOIN ZC_SPECIALTY ZC_SPEC ON (D_PRV_SPEC.SPECIALTY_C=ZC_SPEC.SPECIALTY_C) + LEFT OUTER JOIN CLARITY_SER_ADDR SERRENADDR ON (SERREN.PROV_ID=SERRENADDR.PROV_ID) + LEFT OUTER JOIN ZC_STATE SERRENST ON (SERRENADDR.STATE_C=SERRENST.STATE_C AND SERRENST.INTERNAL_ID >= 0 AND SERRENST.INTERNAL_ID <= 51) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_WQ_ITEM WQI ON (CLM.CLAIM_ID=WQI.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_WQ WQ ON (WQI.WORKQUEUE_ID=WQ.WORKQUEUE_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + ( + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end) IN ( '77','76' ) + ) + AND + ( + CLM.STATUS_C = 3 + OR + CLD.STATUS_C = 1 + ) + AND + EOB_CODE.MNEMONIC IN ( 'CED12','CED44' ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:7,Optional) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:8,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:9,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:10,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:11) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +GROUP BY + CLM_MAP_1.INTERNAL_ID, + CLD.LINE, + CLM.ACCT_NUM_WITH_VEN +, + CLM_CF.NAME, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + VENCLM.VENDOR_NAME, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + SERREN.PROV_NAME, + EAP.PROC_CODE, + CLM.TYPE_OF_BILL, + CLM_CS.NAME, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end), + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end), + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end), + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CLM.DATE_RECEIVED, + CLM.SERVICE_END_DATE, + WQ.WORKQUEUE_NAME, + CLM.SERVICE_START_DATE, + CLD.POS_TYPE_C, + CLMPOS.NAME, + POS.POS_NAME, + CLD.NET_PAYABLE, + EAFMAP.INTERNAL_ID, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST, + CLD.BILLED_AMT +--END-- +SELECT DISTINCT + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME +FROM + CLARITY_EOB_CODE EOB_CODE +WHERE + EOB_CODE.CODE_TYPE_C = 3 +; + +-- large-sql-with-issue-265.txt +with cross_items as +(select i_item_sk ss_item_sk +from item, +(select iss.i_brand_id brand_id +,iss.i_class_id class_id +,iss.i_category_id category_id +from store_sales +,item iss +,date_dim d1 +where ss_item_sk = iss.i_item_sk +and ss_sold_date_sk = d1.d_date_sk +and d1.d_year between 1999 AND 1999 + 2 +intersect +select ics.i_brand_id +,ics.i_class_id +,ics.i_category_id +from catalog_sales +,item ics +,date_dim d2 +where cs_item_sk = ics.i_item_sk +and cs_sold_date_sk = d2.d_date_sk +and d2.d_year between 1999 AND 1999 + 2 +intersect +select iws.i_brand_id +,iws.i_class_id +,iws.i_category_id +from web_sales +,item iws +,date_dim d3 +where ws_item_sk = iws.i_item_sk +and ws_sold_date_sk = d3.d_date_sk +and d3.d_year between 1999 AND 1999 + 2) x +where i_brand_id = brand_id +and i_class_id = class_id +and i_category_id = category_id +), +avg_sales as +(select avg(quantitylist_price) average_sales +from (select ss_quantity quantity +,ss_list_price list_price +from store_sales +,date_dim +where ss_sold_date_sk = d_date_sk +and d_year between 1999 and 2001 +union all +select cs_quantity quantity +,cs_list_price list_price +from catalog_sales +,date_dim +where cs_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select ws_quantity quantity +,ws_list_price list_price +from web_sales +,date_dim +where ws_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2) x) +select channel, i_brand_id,i_class_id,i_category_id,sum(sales), sum(number_sales) +from( +select 'store' channel, i_brand_id,i_class_id +,i_category_id,sum(ss_quantityss_list_price) sales +, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantityss_list_price) > (select average_sales from avg_sales) +union all +select 'catalog' channel, i_brand_id,i_class_id,i_category_id, sum(cs_quantitycs_list_price) sales, count() number_sales +from catalog_sales +,item +,date_dim +where cs_item_sk in (select ss_item_sk from cross_items) +and cs_item_sk = i_item_sk +and cs_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(cs_quantitycs_list_price) > (select average_sales from avg_sales) +union all +select 'web' channel, i_brand_id,i_class_id,i_category_id, sum(ws_quantityws_list_price) sales , count() number_sales +from web_sales +,item +,date_dim +where ws_item_sk in (select ss_item_sk from cross_items) +and ws_item_sk = i_item_sk +and ws_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(ws_quantityws_list_price) > (select average_sales from avg_sales) +) y +group by rollup (channel, i_brand_id,i_class_id,i_category_id) +order by channel,i_brand_id,i_class_id,i_category_id +limit 100; +with cross_items as +(select i_item_sk ss_item_sk +from item, +(select iss.i_brand_id brand_id +,iss.i_class_id class_id +,iss.i_category_id category_id +from store_sales +,item iss +,date_dim d1 +where ss_item_sk = iss.i_item_sk +and ss_sold_date_sk = d1.d_date_sk +and d1.d_year between 1999 AND 1999 + 2 +intersect +select ics.i_brand_id +,ics.i_class_id +,ics.i_category_id +from catalog_sales +,item ics +,date_dim d2 +where cs_item_sk = ics.i_item_sk +and cs_sold_date_sk = d2.d_date_sk +and d2.d_year between 1999 AND 1999 + 2 +intersect +select iws.i_brand_id +,iws.i_class_id +,iws.i_category_id +from web_sales +,item iws +,date_dim d3 +where ws_item_sk = iws.i_item_sk +and ws_sold_date_sk = d3.d_date_sk +and d3.d_year between 1999 AND 1999 + 2) x +where i_brand_id = brand_id +and i_class_id = class_id +and i_category_id = category_id +), +avg_sales as +(select avg(quantitylist_price) average_sales +from (select ss_quantity quantity +,ss_list_price list_price +from store_sales +,date_dim +where ss_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select cs_quantity quantity +,cs_list_price list_price +from catalog_sales +,date_dim +where cs_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select ws_quantity quantity +,ws_list_price list_price +from web_sales +,date_dim +where ws_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2) x) +select * from +(select 'store' channel, i_brand_id,i_class_id,i_category_id +,sum(ss_quantityss_list_price) sales, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_week_seq = (select d_week_seq +from date_dim +where d_year = 1998 + 1 +and d_moy = 12 +and d_dom = 16) +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantityss_list_price) > (select average_sales from avg_sales)) this_year, +(select 'store' channel, i_brand_id,i_class_id +,i_category_id, sum(ss_quantityss_list_price) sales, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_week_seq = (select d_week_seq +from date_dim +where d_year = 1998 +and d_moy = 12 +and d_dom = 16) +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantity*ss_list_price) > (select average_sales from avg_sales)) last_year +where this_year.i_brand_id= last_year.i_brand_id +and this_year.i_class_id = last_year.i_class_id +and this_year.i_category_id = last_year.i_category_id +order by this_year.channel, this_year.i_brand_id, this_year.i_class_id, this_year.i_category_id +limit 100; + + +-- performanceIssue1397.sql +SELECT "TABLE1"."LABEL" , + (CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) AS "SEGMENT", + (CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q1 000 - Small Amps', 'Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 000 - Upper Reddle Alt')) THEN '000 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 000 - Entry Amps', 'Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 000 - Waterproof Speakers', 'Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 000 - Small Amps', 'Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 000 - Campery', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 000 - Fires - Smooth')) THEN '000 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 000 - Small Amps', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 000 - Upper Reddle Alt')) THEN '000 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 000 - Entry Amps', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Small Amps', 'Registration Q4 000 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Campery', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Fires - Smooth')) THEN '000 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 001 - Small Amps', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 001 - Upper Reddle Alt')) THEN '001 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 001 - Entry Amps', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Small Amps', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Campery', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Fires - Smooth')) THEN '001 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 001 - Small Amps', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 001 - Upper Reddle Alt')) THEN '001 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 001 - Entry Amps', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Small Amps', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 001 - Campery', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 001 - Fires - Smooth')) THEN '001 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 002 - Small Amps', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 002 - Upper Reddle Alt')) THEN '002 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q2 002 - Entry Amps', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Small Amps', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Wagon', 'Registration Q2 002 - Campery', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Fires - Smooth')) THEN '002 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 002 - Small Amps', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 002 - Upper Reddle Alt')) THEN '002 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 002 - Entry Amps', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Small Amps', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 002 - Campery', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 002 - Fires - Smooth')) THEN '002 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 005 - Small Amps', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 005 - Upper Reddle Alt')) THEN '005 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Entry Amps', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Small Amps', 'Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 005 - Campers Amps', 'Registration Q2 005 - Campery', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q2 005 - Fires - Smooth')) THEN '005 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 005 - Entry Amps', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Small Amps', 'Registration Q4 005 - Camper Yeah - Entry Alt', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 005 - Campers Amps', 'Registration Q4 005 - Campery', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 005 - Fires - Smooth')) THEN '005 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 006 - Small Amps', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 006 - Upper Reddle Alt')) THEN '006 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 006 - Small Amps', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q3 006 - Upper Reddle Alt')) THEN '006 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Entry Amps', 'Registration Q4 006 - Fullsize Amp Alt', 'Registration Q4 006 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Small', 'Registration Q4 006 - Red-Junk - Waterproof', 'Registration Q4 006 - Near-Entry Waterproof', 'Registration Q4 006 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Fullsize', 'Registration Q4 006 - Small Amps', 'Registration Q4 006 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Small', 'Registration Q4 006 - Camper Wagon', 'Registration Q4 006 - Campers Amps', 'Registration Q4 006 - Campery', 'Registration Q4 006 - Upper Reddle Alt', 'Registration Q4 006 - Fires - Smooth')) THEN '006 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 2021 - Small Amps', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q1 2021 - Upper Reddle Alt')) THEN '2021 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q2 2021 - Redsize Amps', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Small Amps', 'Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Wagon', 'Registration Q2 2021 - Campers Amps', 'Registration Q2 2021 - Campery', 'Registration Q2 2021 - Fires - Smooth')) THEN '2021 Q2' ELSE "TABLE1"."DESCRIPTION" END) AS "Study_Quarter/Year", + COUNT(DISTINCT "TABLE2"."ID") AS "ctd:ID:ok" +FROM "SCHEMA1"."TABLE2" "TABLE2" + INNER JOIN "SCHEMA1"."TABLE1" "TABLE1" ON ("TABLE2"."ID" = "TABLE1"."ID") +WHERE (((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) >= 'Alternative Capacitor Devices') AND ((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) <= 'Fires - Smooth') AND ((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q1 000 - Small Amps', 'Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 000 - Upper Reddle Alt')) THEN '000 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 000 - Entry Amps', 'Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 000 - Waterproof Speakers', 'Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 000 - Small Amps', 'Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 000 - Campery', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 000 - Fires - Smooth')) THEN '000 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 000 - Small Amps', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 000 - Upper Reddle Alt')) THEN '000 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 000 - Entry Amps', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Small Amps', 'Registration Q4 000 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Campery', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Fires - Smooth')) THEN '000 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 001 - Small Amps', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 001 - Upper Reddle Alt')) THEN '001 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 001 - Entry Amps', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Small Amps', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Campery', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Fires - Smooth')) THEN '001 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 001 - Small Amps', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 001 - Upper Reddle Alt')) THEN '001 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 001 - Entry Amps', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Small Amps', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 001 - Campery', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 001 - Fires - Smooth')) THEN '001 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 002 - Small Amps', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 002 - Upper Reddle Alt')) THEN '002 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q2 002 - Entry Amps', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Small Amps', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Wagon', 'Registration Q2 002 - Campery', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Fires - Smooth')) THEN '002 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 002 - Small Amps', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 002 - Upper Reddle Alt')) THEN '002 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 002 - Entry Amps', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Small Amps', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 002 - Campery', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 002 - Fires - Smooth')) THEN '002 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 005 - Small Amps', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 005 - Upper Reddle Alt')) THEN '005 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Entry Amps', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Small Amps', 'Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 005 - Campers Amps', 'Registration Q2 005 - Campery', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q2 005 - Fires - Smooth')) THEN '005 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 005 - Entry Amps', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Small Amps', 'Registration Q4 005 - Camper Yeah - Entry Alt', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 005 - Campers Amps', 'Registration Q4 005 - Campery', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 005 - Fires - Smooth')) THEN '005 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 006 - Small Amps', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 006 - Upper Reddle Alt')) THEN '006 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 006 - Small Amps', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q3 006 - Upper Reddle Alt')) THEN '006 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Entry Amps', 'Registration Q4 006 - Fullsize Amp Alt', 'Registration Q4 006 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Small', 'Registration Q4 006 - Red-Junk - Waterproof', 'Registration Q4 006 - Near-Entry Waterproof', 'Registration Q4 006 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Fullsize', 'Registration Q4 006 - Small Amps', 'Registration Q4 006 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Small', 'Registration Q4 006 - Camper Wagon', 'Registration Q4 006 - Campers Amps', 'Registration Q4 006 - Campery', 'Registration Q4 006 - Upper Reddle Alt', 'Registration Q4 006 - Fires - Smooth')) THEN '006 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 2021 - Small Amps', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q1 2021 - Upper Reddle Alt')) THEN '2021 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q2 2021 - Redsize Amps', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Small Amps', 'Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Wagon', 'Registration Q2 2021 - Campers Amps', 'Registration Q2 2021 - Campery', 'Registration Q2 2021 - Fires - Smooth')) THEN '2021 Q2' ELSE "TABLE1"."DESCRIPTION" END) = '2021 Q2') AND ((CASE WHEN ("TABLE1"."CODE" = 'No Answer') THEN 0 ELSE 1 END) <> 0) AND ("TABLE1"."DESCRIPTION" = 'Familiar With (G1)')) +GROUP BY 1, + 2, + 3 +; + +-- simple_parsing.txt +sELect g.*, A.K from B, KLJ as A; + +select * from TABLE_A; + +select * from TABLE_A; + +select * from TABLE_A LIMIT 34; + +select * from TABLE_A LIMIT ?; + +select * from TABLE_A LIMIT 34,?; + +select * from TABLE_A LIMIT ?,?; + +select * from TABLE_A LIMIT ? OFFSET 3; + +select * from TABLE_A LIMIT ? OFFSET ?; + +select * from TABLE_A LIMIT ALL OFFSET ?; + +select * from TABLE_A LIMIT ALL OFFSET 3; + +select * from TABLE_A OFFSET 3; + +select A,sdf,sch.tab.col from TABLE_A; + +select k, * from K as skldjfl where i=0; + +select MAX(k+2), COUNT(*), MYCOL from K; + +SELECT * FROM TA2 LEFT JOIN O USING (col1, col2) +where D.OasSD = 'asdf' And (kj >= 4 OR l < 'sdf'); + +seLECT my as KIO, lio aS +NE fRom TA2 LEFT OUter JOIN O as TA3 +where D.OasSD = 'asdf' And (kj >= 4 OR l < 'sdf'); + +select * from a +INNer Join TAB_2 ON i.o = p.l whEre 'sdf'>'asdf' AND + ( + OL<>? + OR + L NOT IN (SELECT * FROM KJSD) + ); + +select * from k where L IS NOT NUll; + +(select sdf from sdfd) UNION (select * from k); + +update mytab set jk=das, d=kasd+asd/d+3 where KL>= ds OR (k not in (SELECT K from KS)); + +insert into tabName VALUES ('sdgf', ?, ?); + +insert into myschama.tabName2 (col1, col2, col3) VALUES ('sdgf', ?, ?); + +delete from jk; + +delete from asdff where INI = 94 OR (ASD>9 AND (SELECT MAX(ID) from myt) > ?); + +select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ON ( id ) * FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id))); + +(select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id)))) UNION ( SELECT wct_workflows.workflow_id as +id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' or wct_audit_entry.privilege = 'C' ) and wct_audit_entry.outcome += 't' and wct_audit_entry.transaction_id = +wct_transaction.transaction_id and wct_transaction.user_id = 164 and +p= 'asd'); + +select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id ))) UNION SELECT wct_workflows.workflow_id as +id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' or wct_audit_entry.privilege = 'C' ) and wct_audit_entry.outcome += 't' and wct_audit_entry.transaction_id = +wct_transaction.transaction_id and wct_transaction.user_id = 164 and +afdf= ( select wct_audit_entry.object_id from wct_audit_entry , +wct_workflow_archive where wct_audit_entry.object_id = +wct_workflow_archive.archive_id and wct_workflows.workflow_id = +wct_workflow_archive.workflow_id ) +UNION SELECT wct_workflows.workflow_id +as id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' OR wct_audit_entry.privilege = 'E' OR wct_audit_entry.privilege = +'A' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.workflow_id UNION SELECT * FROM interm2 , wct_workflow_docs WHERE +interm2.id = wct_workflow_docs.document_id ORDER BY id , date DESC +; + +replace df set ki='oasdf', dsd=asd+dd; + +(select sdf from sdfd) UNION (select * from k) ORDER BY 1,2; + +(select sdf from sdfd) UNION (select * from k) ORDER BY 1,asd.sd ; + +(select sdf from sdfd) UNION (select * from k) UNION (select * from k2) LIMIT 0,2; + +select sdf from sdfd UNION select * from k join j on k.p = asdf.f; + +select * from ( select persistence_dynamic_ot.pdl_id , +acs_objects.default_domain_class as attribute0 , +acs_objects.object_type as attribute1 , acs_objects.display_name +as attribute2 , persistence_dynamic_ot.dynamic_object_type as +attribute3 , persistence_dynamic_ot.pdl_file as attribute4 from +persistence_dynamic_ot , acs_objects where +persistence_dynamic_ot.pdl_id = acs_objects.object_id ); + +SELECT * FROM table1 WHERE column1 > ALL (SELECT column2 FROM table1); + +INSERT INTO mytable (col1, col2, col3) SELECT * FROM mytable2; + +insert into foo ( x ) select a from b; + +select (case when a > 0 then b + a else 0 end) p from mytable; + +SELECT BTI.*, BTI_PREDECESSOR.objid AS predecessor_objid, BTI_PREDECESSOR.item_id +AS predecessor_item_id, BTIT_PREDECESSOR.bt_item_type_key AS predecessor_type_key, +CAT.catalog_key, S.objid AS state_objid, S.state_key, S.is_init_state, +S.is_final_state, mlS.name AS state, BTIT.bt_item_type_key, BTP.bt_processor_key, +mlBTP.name AS bt_processor_name , CU.objid AS cust_user_objid , CU.title AS +cust_user_title , CU.firstname AS cust_user_firstname , CU.lastname AS +cust_user_lastname , CU.salutation2pv AS cust_user_salutation2pv , PV_CU.name_option +AS cust_user_salutation , A_CU.email AS cust_user_email , '' AS use_option_field, +'' AS use_readerlist , BTI_QUOTATION.quotation_type2pv , BTI_QUOTATION.is_mandatory +AS quotation_is_mandatory , BTI_QUOTATION.is_multiple AS quotation_is_multiple +, BTI_QUOTATION.expiration_datetime AS quotation_expiration_datetime , +BTI_QUOTATION.hint_internal AS quotation_hint_internal , BTI_QUOTATION.hint_external +AS quotation_hint_external , BTI_QUOTATION.filter_value AS quotation_filter_value +, BTI_QUOTATION.email_cc AS quotation_email_cc , BTI_QUOTATION.notification1_datetime +AS notification1_datetime , BTI_QUOTATION.notification2_datetime AS +notification2_datetime , BTI_RFQ.filter_value AS request_for_quotation_filter_value +FROM tBusinessTransactionItem BTI LEFT OUTER JOIN tBusinessTransactionItem_Quotation +BTI_QUOTATION ON BTI_QUOTATION.this2business_transaction_item = BTI.objid LEFT +OUTER JOIN tBusinessTransactionItem_RequestForQuotation BTI_RFQ ON +BTI_RFQ.this2business_transaction_item = BTI.objid LEFT OUTER JOIN +tBusinessTransactionItem BTI_PREDECESSOR ON BTI_PREDECESSOR.objid += BTI.predecessor2bt_item, tBusinessTransactionItemType BTIT_PREDECESSOR +, tBusinessTransactionItemType BTIT, tBusinessTransactionProcessor BTP, +mltBusinessTransactionProcessor mlBTP, tLanguagePriority LP_BTP, tState S, mltState +mlS, tLanguagePriority LP_S, tCatalog CAT +, tBusinessTransactionItem2BusinessTransaction BTI2BT , +tBusinessTransactionItem2SessionCart BTI2SC , tSessionCart SC , tCustUser CU_MASTER +, tCustUser CU , tPopValue PV_CU , tAddress A_CU , tAddress2CustUser A2CU WHERE +BTI.objid <> -1 AND BTI_PREDECESSOR.this2bt_item_type = BTIT_PREDECESSOR.objid +AND BTI.this2bt_item_type = BTIT.objid AND BTI.this2bt_processor = BTP.objid +AND mlBTP.this2master = BTP.objid AND mlBTP.this2language = LP_BTP.item2language +AND LP_BTP.master2language = 0 AND LP_BTP.this2shop = 0 AND LP_BTP.priority += (SELECT MIN(LP_BTP2.priority) FROM tLanguagePriority LP_BTP2, +mltBusinessTransactionProcessor mlBTP2 WHERE LP_BTP2.master2language = 0 AND +LP_BTP2.this2shop = 0 AND LP_BTP2.item2language = mlBTP2.this2language +AND mlBTP2.this2master = BTP.objid ) AND BTI.this2catalog = CAT.objid AND S.objid += BTI.bt_item2state AND mlS.this2master = S.objid AND mlS.this2language += LP_S.item2language AND LP_S.master2language = 0 AND LP_S.this2shop = 0 AND +LP_S.priority = (SELECT MIN(LP_S2.priority) FROM tLanguagePriority LP_S2, mltState +mlS2 WHERE LP_S2.master2language = 0 AND LP_S2.this2shop = 0 AND LP_S2.item2language += mlS2.this2language AND mlS2.this2master = S.objid ) AND BTI.objid += BTI2BT.this2business_transaction_item AND CU_MASTER.objid = 1101 AND +CU.this2customer = CU_MASTER.this2customer AND SC.this2custuser = CU.objid AND +BTI.objid = BTI2SC.this2business_transaction_item AND BTI.bt_item2state = 6664 +AND BTI2SC.is_master_cart_item = 1 AND BTI2SC.this2session_cart = SC.objid AND +EXISTS (SELECT NULL FROM tBusinessTransaction BT, tBusinessTransactionType BTT +WHERE BT.objid = BTI2BT.this2business_transaction AND BTT.objid = BT.this2bt_type +AND BTT.business_transaction_type_key = 'order:master_cart') AND PV_CU.objid += CU.salutation2pv AND A2CU.this2custuser = CU.objid AND A2CU.is_billing_default += 1 AND A2CU.this2address = A_CU.objid ORDER BY BTI.dbobj_create_datetime DESC; + +WITH +DINFO (DEPTNO, AVGSALARY, EMPCOUNT) AS +(SELECT OTHERS.WORKDEPT, AVG(OTHERS.SALARY), COUNT(*) +FROM EMPLOYEE OTHERS +GROUP BY OTHERS.WORKDEPT +), +DINFOMAX AS +(SELECT MAX(AVGSALARY) AS AVGMAX FROM DINFO) +SELECT THIS_EMP.EMPNO, THIS_EMP.SALARY, +DINFO.AVGSALARY, DINFO.EMPCOUNT, DINFOMAX.AVGMAX +FROM EMPLOYEE THIS_EMP, DINFO, DINFOMAX +WHERE THIS_EMP.JOB = 'SALESREP' +AND THIS_EMP.WORKDEPT = DINFO.DEPTNO; + +select * from Person where deptname='it' AND NOT (age=24); + +select * from unnest(array[4,5,6]) with ordinality; + From 517fe72c55cdddeca2745d1456a34d42ad152596 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 13 May 2025 17:43:36 +0700 Subject: [PATCH 013/123] chore: minor clean-ups around the performance optimisations Signed-off-by: Andreas Reichel --- .../expression/DateTimeLiteralExpression.java | 2 +- .../statement/insert/InsertTest.java | 2 +- .../statement/select/PostgresTest.java | 36 +++++++++++++++++++ .../statement/select/SelectASTTest.java | 2 +- .../statement/select/SelectTest.java | 4 +++ .../select/oracle-tests/condition06.sql | 3 +- 6 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java index 3510fe6d3..ccb15db4b 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/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/PostgresTest.java b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java index 06d1e3d54..9ded16786 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java @@ -10,14 +10,17 @@ 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; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.List; @@ -102,4 +105,37 @@ void testNextValueIssue1863() throws JSQLParserException { String sqlStr = "SELECT nextval('client_id_seq')"; assertSqlCanBeParsedAndDeparsed(sqlStr); } + + @Test + @Disabled + // wip + 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 + @Disabled + // wip + 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..e12b51ed8 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java @@ -175,7 +175,7 @@ public Object visit(SimpleNode node, Object data) { assertNotNull(subSelectStart); assertNotNull(subSelectEnd); - assertEquals(30, subSelectStart.beginColumn); + assertEquals(32, subSelectStart.beginColumn); assertEquals(49, subSelectEnd.endColumn); } 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..bd75daf4d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6174,6 +6174,8 @@ public void testSelectWithSkylineKeywords() throws JSQLParserException { } @Test + @Disabled + // see issue #2207 public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException { String sql = "SELECT (pg_stat_file('postgresql.conf')).*"; Statement statement = CCJSqlParserUtil.parse(sql); @@ -6192,6 +6194,8 @@ public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException } @Test + @Disabled + // see issue #2207 public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() throws JSQLParserException { String sql = "SELECT ( ( ( pg_stat_file('postgresql.conf') ) )) . *"; diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql index 1406c1f8d..1142b951d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql @@ -22,4 +22,5 @@ and t1.sid(+)=t2.sid and ( ( t1.scode like 'mmm' and t2.scode like 'xax' ) ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "is" "IS" recorded first on 13 May 2025, 16:46:15 \ No newline at end of file From f372ff818952d056a86e04c246e4b4c72542ddc8 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 13 May 2025 18:09:45 +0700 Subject: [PATCH 014/123] build: fix Maven build r/ JMH Signed-off-by: Andreas Reichel --- README.md | 2 +- pom.xml | 23 +++++++++++++++++++ .../benchmark/DynamicParserRunner.java | 9 ++++++++ .../benchmark/JSQLParserBenchmark.java | 9 ++++++++ .../benchmark/LatestClasspathRunner.java | 9 ++++++++ .../jsqlparser/benchmark/SqlParserRunner.java | 9 ++++++++ .../net/sf/jsqlparser/performance.sql | 9 ++++++++ 7 files changed, 69 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d8db30b8..a37c98419 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later de Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. -## Performan ce +## Performance Unfortunately the released JSQLParser-5.2 shows a performance deterioration caused by commit [30cf5d7](https://github.com/JSQLParser/JSqlParser/commit/30cf5d7b930ae0a076f49deb5cc841d39e62b3dc) related to `FunctionAllColumns()`. This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been added to avoid such regressions in the future. Further all `LOOKAHEADS` have been revised one by one, and we have gained back a very good performance of the Parser. diff --git a/pom.xml b/pom.xml index daee429d2..ceefe4abf 100644 --- a/pom.xml +++ b/pom.xml @@ -82,6 +82,22 @@ 1.3 test + + + + org.openjdk.jmh + jmh-core + 1.37 + + + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + provided + + @@ -204,6 +220,13 @@ -J-Xss4M true + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + + diff --git a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java index 021e04f64..f87acd119 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.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.benchmark; import net.sf.jsqlparser.parser.CCJSqlParser; diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index d81b1e01b..b046ff865 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.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.benchmark; import net.sf.jsqlparser.parser.CCJSqlParser; diff --git a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java index 17bbf8e4b..5f70cf878 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.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.benchmark; import net.sf.jsqlparser.parser.CCJSqlParser; diff --git a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java index a3ef61afc..00496ad68 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.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.benchmark; import net.sf.jsqlparser.parser.CCJSqlParser; diff --git a/src/test/resources/net/sf/jsqlparser/performance.sql b/src/test/resources/net/sf/jsqlparser/performance.sql index 0727f0a14..d83065643 100644 --- a/src/test/resources/net/sf/jsqlparser/performance.sql +++ b/src/test/resources/net/sf/jsqlparser/performance.sql @@ -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% +--- -- complex-lateral-select-request.txt SELECT O.ORDERID, From bad818e0b872c6a0a3aa96ed82c3d3fec5823048 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 14 May 2025 14:53:10 +0700 Subject: [PATCH 015/123] fix: the Quotes Token manipulation - off now by one char at start Signed-off-by: Andreas Reichel --- .../jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 1a9a349bb..845d41ffa 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -738,22 +738,23 @@ TOKEN: // which contains the , then we will need to // 1) break the at close it with a "'" // 2) continue tokenizing after that with a new or any other Token - if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\'") ) { - matchedToken.image = image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; + if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) + && matchedToken.image.contains("\\'") ) { + matchedToken.image = "'" + image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; for (int i=0;i") ) { matchedToken.kind = i; } } - input_stream.backup(image.length() - matchedToken.image.length() ); + input_stream.backup(image.length() + 1 - matchedToken.image.length()); } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\''") ) { - matchedToken.image = image.substring( 0, image.lastIndexOf("\\'") + 3); + matchedToken.image = "'" + image.substring( 0, image.lastIndexOf("\\'") + 3); for (int i=0;i") ) { matchedToken.kind = i; } } - input_stream.backup(image.length() - matchedToken.image.length() ); + input_stream.backup(image.length() + 1 - matchedToken.image.length() ); } } | < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > From f2c87a3a4cf58f274fb6fd3e6bf80b03f3782284 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 14 May 2025 14:54:08 +0700 Subject: [PATCH 016/123] chore: disable a production with a large performance regression Signed-off-by: Andreas Reichel --- src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 2 +- .../java/net/sf/jsqlparser/statement/select/SelectTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 845d41ffa..91d7f3316 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5388,7 +5388,7 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(16) retval=AllTableColumns() - | LOOKAHEAD(250) retval=FunctionAllColumns() + // | LOOKAHEAD(250) retval=FunctionAllColumns() // support timestamp expressions | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new TimeKeyExpression(token.image); } 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..9039ea969 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6174,6 +6174,7 @@ public void testSelectWithSkylineKeywords() throws JSQLParserException { } @Test + @Disabled public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException { String sql = "SELECT (pg_stat_file('postgresql.conf')).*"; Statement statement = CCJSqlParserUtil.parse(sql); @@ -6192,6 +6193,7 @@ public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException } @Test + @Disabled public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() throws JSQLParserException { String sql = "SELECT ( ( ( pg_stat_file('postgresql.conf') ) )) . *"; From 21c983fc1f4f3f29b3de17f40f400fd65baef1c4 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 14 May 2025 14:54:37 +0700 Subject: [PATCH 017/123] feat: add proper JMH benchmarks Signed-off-by: Andreas Reichel --- build.gradle | 8 + src/site/sphinx/_static/jmh_results.txt | 20 + .../benchmark/DynamicParserRunner.java | 40 + .../benchmark/JSQLParserBenchmark.java | 89 + .../benchmark/LatestClasspathRunner.java | 28 + .../jsqlparser/benchmark/SqlParserRunner.java | 21 + .../statement/select/SpeedTest.java | 2 + .../net/sf/jsqlparser/performance.sql | 2110 +++++++++++++++++ 8 files changed, 2318 insertions(+) create mode 100644 src/site/sphinx/_static/jmh_results.txt create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java create mode 100644 src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java create mode 100644 src/test/resources/net/sf/jsqlparser/performance.sql diff --git a/build.gradle b/build.gradle index 1b8585f60..5d505ce2f 100644 --- a/build.gradle +++ b/build.gradle @@ -641,3 +641,11 @@ tasks.register('upload') { check { dependsOn jacocoTestCoverageVerification } + +jmh { + includes = ['.*JSQLParserBenchmark.*'] + warmupIterations = 3 + fork = 3 + iterations = 10 + timeOnIteration = '1s' +} diff --git a/src/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt new file mode 100644 index 000000000..e5d28aa38 --- /dev/null +++ b/src/site/sphinx/_static/jmh_results.txt @@ -0,0 +1,20 @@ +-- Optimised LOOKAHEADS (replacing all syntactic lookahead by numeric lookaheads) +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 264.132 ± 9.636 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 415.744 ± 20.602 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 89.387 ± 1.916 ms/op +JSQLParserBenchmark.parseSQLStatements 5.0 avgt 15 68.810 ± 2.591 ms/op +JSQLParserBenchmark.parseSQLStatements 4.9 avgt 15 60.515 ± 1.650 ms/op +JSQLParserBenchmark.parseSQLStatements 4.8 avgt 15 60.002 ± 1.259 ms/op +JSQLParserBenchmark.parseSQLStatements 4.7 avgt 15 73.291 ± 3.049 ms/op + +-- Optimised LOOKAHEADS (replacing huge numeric lookaheads with syntactic lookaheads again) +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 249.408 ± 11.340 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 ms/op + +-- Disable `FunctionAllColumns()` +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op \ No newline at end of file diff --git a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java new file mode 100644 index 000000000..f87acd119 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java @@ -0,0 +1,40 @@ +/*- + * #%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.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.lang.reflect.Method; +import java.net.URLClassLoader; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class DynamicParserRunner implements SqlParserRunner { + private final Method parseStatementsMethod; + + public DynamicParserRunner(URLClassLoader loader) throws Exception { + Class utilClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParserUtil"); + Class ccjClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParser"); + Class consumerClass = Class.forName("java.util.function.Consumer"); // interface OK + parseStatementsMethod = utilClass.getMethod( + "parseStatements", + String.class, + ExecutorService.class, + consumerClass); + } + + @Override + public Statements parseStatements(String sql, + ExecutorService executorService, + Consumer consumer) throws Exception { + return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null); + } +} diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java new file mode 100644 index 000000000..b046ff865 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -0,0 +1,89 @@ +/*- + * #%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.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; +import org.openjdk.jmh.annotations.*; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.concurrent.*; +import java.util.function.Consumer; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +public class JSQLParserBenchmark { + + private String sqlContent; + private ExecutorService executorService; + + SqlParserRunner runner; + + // @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" }) + @Param({"latest", "5.2", "5.1"}) + public String version; + + @Setup(Level.Trial) + public void setup() throws Exception { + if ("latest".equals(version)) { + runner = new LatestClasspathRunner(); // direct call, no reflection + } else { + Path jarPath = downloadJsqlparserJar(version); + URLClassLoader loader = new URLClassLoader(new URL[] {jarPath.toUri().toURL()}, null); + runner = new DynamicParserRunner(loader); + } + + // Adjust path as necessary based on where source root is during test execution + Path path = Paths.get("src/test/resources/net/sf/jsqlparser/performance.sql"); + sqlContent = Files.readString(path, StandardCharsets.UTF_8); + executorService = Executors.newSingleThreadExecutor(); + } + + private Path downloadJsqlparserJar(String version) throws IOException { + String jarUrl = String.format( + "https://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/%s/jsqlparser-%s.jar", + version, version); + + Path cacheDir = Paths.get("build/libs/downloaded-jars"); + Files.createDirectories(cacheDir); + Path jarFile = cacheDir.resolve("jsqlparser-" + version + ".jar"); + + if (!Files.exists(jarFile)) { + System.out.println("Downloading " + version); + try (InputStream in = new URL(jarUrl).openStream()) { + Files.copy(in, jarFile); + } + } + + return jarFile; + } + + @Benchmark + public void parseSQLStatements() throws Exception { + final Statements statements = runner.parseStatements( + sqlContent, + executorService, + (Consumer) parser -> { + // No-op consumer (or you can log/validate each parser if desired) + }); + assert statements.size() == 4; + } + + @TearDown(Level.Trial) + public void tearDown() { + executorService.shutdown(); + } +} diff --git a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java new file mode 100644 index 000000000..5f70cf878 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java @@ -0,0 +1,28 @@ +/*- + * #%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.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class LatestClasspathRunner implements SqlParserRunner { + + @Override + public Statements parseStatements(String sql, + ExecutorService executorService, + Consumer consumer) throws Exception { + return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService, + consumer); + } +} + diff --git a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java new file mode 100644 index 000000000..00496ad68 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java @@ -0,0 +1,21 @@ +/*- + * #%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.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public interface SqlParserRunner { + Statements parseStatements(String sql, ExecutorService executorService, + Consumer consumer) throws Exception; +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java index 21565c78f..9210e9d5c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.statement.simpleparsing.CCJSqlParserManagerTest; import net.sf.jsqlparser.test.TestException; import net.sf.jsqlparser.util.TablesNamesFinder; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.BufferedReader; @@ -30,6 +31,7 @@ public class SpeedTest { private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @Test + @Disabled public void testSpeed() throws Exception { // all the statements in testfiles/simple_parsing.txt BufferedReader in = new BufferedReader( diff --git a/src/test/resources/net/sf/jsqlparser/performance.sql b/src/test/resources/net/sf/jsqlparser/performance.sql new file mode 100644 index 000000000..d83065643 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/performance.sql @@ -0,0 +1,2110 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2025 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +-- complex-lateral-select-request.txt +SELECT +O.ORDERID, +O.CUSTNAME, +OL.LINETOTAL, +OC.ORDCHGTOTAL, +OT.TAXTOTAL +FROM +ORDERS O, +LATERAL ( +SELECT +SUM(NETAMT) AS LINETOTAL +FROM +ORDERLINES LINES +WHERE +LINES.ORDERID=O.ORDERID +) AS OL, +LATERAL ( +SELECT +SUM(CHGAMT) AS ORDCHGTOTAL +FROM +ORDERCHARGES CHARGES +WHERE +LINES.ORDERID=O.ORDERID +) AS OC, +LATERAL ( +SELECT +SUM(TAXAMT) AS TAXTOTAL +FROM +ORDERTAXES TAXES +WHERE +TAXES.ORDERID=O.ORDERID +) AS OT +; + +-- large-sql-issue-235.txt +SELECT + 'CR' AS `^CR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -3) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -3) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^P3Q TRR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -2) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -2) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^P2Q TRR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -1) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -1) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^PQ TRR`, + (1 - (SUM((CASE + WHEN ((ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = 0) + AND (`tbl`.`AS` = 'Cancelled')) THEN 1 + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN 1 + ELSE 0 + END)))) AS `^CQ TRR` + FROM + `tbl` + GROUP BY + 'CR' LIMIT 25000 +; + +-- large-sql-issue-566.txt +SELECT "CAMPAIGNID","TARGET_SOURCE","NON_INDV_TYPE","GROUP_SPONSOR","SEGMNTS","COUNTRY_CD","TARGET_STATE","TARGET_CITY","TARGET_ZIP","SIC_CLASS","NAICS_CLASS","GENDER_CD","OCCUPATION","CREDIT_SCORE","MARITAL_STATUS","IMPORT_ID","BIRTH_DT","STATUS" + FROM ( + SELECT + X.CAMPAIGNID, + X.FIELDNAME, + CASE WHEN Y.VALUE IS NULL THEN 'ALL' + ELSE Y.VALUE END AS VALUE + FROM + --CREATES A CARTESIAN JOIN TO COMBINE ALL CHARACTERISTICS WITH CAMPAIGN + (SELECT + CAMPAIGNID, + FIELDNAME + FROM CAMPAIGN + CROSS JOIN (SELECT DISTINCT FIELDNAME + FROM FIELDCRITERIA)) X + LEFT JOIN + --RETURNS ALL AVAILABLE CAMPAIGN CHARACTERISTS + ( + SELECT + CAMPAIGNID, + FIELDNAME, + (CASE FIELDNAME + WHEN U'BUSINESSTYPE' THEN D.DISPLAYVALUE + WHEN U'LEADTARGETSOURCE' THEN E.DISPLAYVALUE + ELSE VALUE END) AS VALUE + FROM FIELDCRITERIA A, STRINGFIELDCRITERIA_VALUE B + LEFT JOIN (SELECT + B.CODE, + B.DISPLAYVALUE, + LOOKUPNAME + FROM LOOKUPLIST A, LOOKUPVALUE B + WHERE A.ID = B.LOOKUPLIST_ID AND LOOKUPNAME = 'NONINDIVIDUALTYPE') D ON B.VALUE = D.CODE + LEFT JOIN (SELECT + B.CODE, + B.DISPLAYVALUE, + LOOKUPNAME + FROM LOOKUPLIST A, LOOKUPVALUE B + WHERE A.ID = B.LOOKUPLIST_ID AND LOOKUPNAME = 'LEADTARGETSOURCE') E ON B.VALUE = E.CODE + , + CAMPAIGN C + WHERE A.ID = B.FIELD_CRITERIA_ID + AND A.CRITERIA_ID = C.ID + ) Y ON X.CAMPAIGNID = Y.CAMPAIGNID AND X.FIELDNAME = Y.FIELDNAME + ) + PIVOT (MAX(VALUE) + FOR FIELDNAME + IN + ('LEADTARGETSOURCE' AS TARGET_SOURCE, 'BUSINESSTYPE' AS NON_INDV_TYPE, 'GROUPSPONSOR' AS GROUP_SPONSOR, 'SEGMENTS' AS SEGMNTS, 'COUNTRYCD' AS COUNTRY_CD, 'STATEPROVCD' AS TARGET_STATE, + 'CITY' AS TARGET_CITY, 'POSTALCODE' AS TARGET_ZIP, 'SICCLASSIFICATION' AS SIC_CLASS, 'NAICSCLASSIFICATION' AS NAICS_CLASS, 'GENDERCD' AS GENDER_CD, 'OCCUPATION' AS OCCUPATION, 'CREDITSCORE' AS CREDIT_SCORE, + 'MARITALSTATUSCD' AS MARITAL_STATUS, 'IMPORTID' AS IMPORT_ID, 'BIRTHDATE' AS BIRTH_DT, 'STATUS' AS STATUS)) +; + +-- large-sql-issue-923.txt +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + CLM.STATUS_C, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + EPPCL.PRODUCT_TYPE, + CLM.SERVICE_START_DATE, + CLM.SERVICE_END_DATE, + CLM.DATE_RECEIVED, + CLM_CS.NAME, + CLM.STATUS_DATE, + CLM_APSTS.ABBR, + CLM_CF.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + GRP.PLAN_GRP_NAME, + SERREN_2.NPI, + SERREN.PROV_NAME, + D_VTN.TAX_ID, + VENCLM.VENDOR_NAME, + (CLM.TOT_BILLED_AMT), + (CLM.TOT_NET_PAYABLE), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME), + POS.CITY, + POS_ST.ABBR, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + POS_TYPE.NAME, + POS.POS_CODE, + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END, + CLM_MAP5.INTERNAL_ID, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLAIM_FORMAT CLM_CF RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_FORMAT_C=CLM_CF.CLAIM_FORMAT_C) + LEFT OUTER JOIN ZC_CLM_STATUS CLM_CS ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN ZC_CLM_AP_STAT CLM_APSTS ON (CLM.AP_STS_C=CLM_APSTS.AP_STS_C) + LEFT OUTER JOIN CLARITY_POS POS ON (CLM.LOC_ID=POS.POS_ID) + LEFT OUTER JOIN ZC_POS_TYPE POS_TYPE ON (POS.POS_TYPE_C=POS_TYPE.POS_TYPE_C) + LEFT OUTER JOIN ZC_STATE POS_ST ON (POS.STATE_C=POS_ST.STATE_C AND POS_ST.INTERNAL_ID >= 0 AND POS_ST.INTERNAL_ID <= 51) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN AP_CLAIM AOC ON (CLM.ORIG_ADJST_CLM_ID=AOC.CLAIM_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP5 ON (AOC.CLAIM_ID=CLM_MAP5.CID AND AOC.CM_LOG_OWNER_ID=CLM_MAP5.CM_LOG_OWNER_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END BETWEEN (CASE + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ) Like 't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) AND (CASE + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ) Like't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) + AND + ( + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:7,Optional) + ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:9,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:13) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + EOB_CODE.ROUTE_FROM_DISC_C, + EOB_CODE.MNEMONIC +FROM + ZC_POS_TYPE CLMPOS RIGHT OUTER JOIN AP_CLAIM_PX CLD ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END BETWEEN (CASE + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ) Like 't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) AND (CASE + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ) Like't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) + AND + ( + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:7,Optional) + ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:9,Optional) + AND + EOB_CODE.CODE_TYPE_C IN ( 2 ) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:13) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME +FROM + CLARITY_EOB_CODE EOB_CODE +WHERE + EOB_CODE.CODE_TYPE_C = 2 +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + EAP.PROC_CODE, + CLM_CS.NAME, + CLM.STATUS_DATE, + CKR.CHECK_STATUS_C, + CLM_APSTS.ABBR, + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + EOB_CODE2.MNEMONIC, + EOB_CODE2.CODE_TYPE_C, + EOB_CODE.CODE_TYPE_C, + EOB_CODE2.EOB_CODE_NAME, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLM_STATUS CLM_CS RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN ZC_CLM_AP_STAT CLM_APSTS ON (CLM.AP_STS_C=CLM_APSTS.AP_STS_C) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN CLARITY_EAP EAP ON (CLD.PROC_ID=EAP.PROC_ID) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN ( + SELECT + PRV_SPEC.PROV_ID PROV_ID, + PRV_SPEC.SPECIALTY_C SPECIALTY_C +FROM + CLARITY_SER_SPEC PRV_SPEC +WHERE LINE=1 +group by PROV_ID,SPECIALTY_C + ) D_PRV_SPEC ON (SERREN.PROV_ID=D_PRV_SPEC.PROV_ID) + LEFT OUTER JOIN ZC_SPECIALTY ZC_SPEC ON (D_PRV_SPEC.SPECIALTY_C=ZC_SPEC.SPECIALTY_C) + LEFT OUTER JOIN CLARITY_SER_ADDR SERRENADDR ON (SERREN.PROV_ID=SERRENADDR.PROV_ID) + LEFT OUTER JOIN ZC_STATE SERRENST ON (SERRENADDR.STATE_C=SERRENST.STATE_C AND SERRENST.INTERNAL_ID >= 0 AND SERRENST.INTERNAL_ID <= 51) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END Is Null + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:7,Optional) + AND + ( + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:9,Optional) + ) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,{'Original Claim'},User:13) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + CLD.LINE, + CLM.ACCT_NUM_WITH_VEN +, + CLM_CF.NAME, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + VENCLM.VENDOR_NAME, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + SERREN.PROV_NAME, + EAP.PROC_CODE, + CLM.TYPE_OF_BILL, + CLM_CS.NAME, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end), + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end), + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end), + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CLM.DATE_RECEIVED, + CLM.SERVICE_END_DATE, + WQ.WORKQUEUE_NAME, + CLM.SERVICE_START_DATE, + CLD.POS_TYPE_C, + CLMPOS.NAME, + POS.POS_NAME, + sum(coalesce(CLD.OVERRIDE_ALLD_AMT,CLD.ALLOWED_AMT,0)), + CLD.NET_PAYABLE, + sum(coalesce(CLD.OVRD_COPAY,CLD.COPAYMENT,0)), + sum(coalesce(CLD.OVRD_COINS,CLD.COINSURANCE,0)), + sum(CLD.BILLED_AMT), + EAFMAP.INTERNAL_ID, + sum(coalesce(CLD.OVRD_DEDUCTIBLE,CLD.DEDUCTIBLE,0)), + SUM(CLD.PRIM_PAT_PORTION), + sum(CLD.PRIM_INS_AMOUNT), + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST, + CLD.BILLED_AMT +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLAIM_FORMAT CLM_CF RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_FORMAT_C=CLM_CF.CLAIM_FORMAT_C) + LEFT OUTER JOIN ZC_CLM_STATUS CLM_CS ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN CLARITY_POS POS ON (CLM.LOC_ID=POS.POS_ID) + LEFT OUTER JOIN EAF_MAP EAFMAP ON (EAFMAP.CID=POS.POS_ID AND POS.CM_LOG_OWNER_ID=EAFMAP.CM_LOG_OWNER_ID) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN CLARITY_EAP EAP ON (CLD.PROC_ID=EAP.PROC_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN ( + SELECT + PRV_SPEC.PROV_ID PROV_ID, + PRV_SPEC.SPECIALTY_C SPECIALTY_C +FROM + CLARITY_SER_SPEC PRV_SPEC +WHERE LINE=1 +group by PROV_ID,SPECIALTY_C + ) D_PRV_SPEC ON (SERREN.PROV_ID=D_PRV_SPEC.PROV_ID) + LEFT OUTER JOIN ZC_SPECIALTY ZC_SPEC ON (D_PRV_SPEC.SPECIALTY_C=ZC_SPEC.SPECIALTY_C) + LEFT OUTER JOIN CLARITY_SER_ADDR SERRENADDR ON (SERREN.PROV_ID=SERRENADDR.PROV_ID) + LEFT OUTER JOIN ZC_STATE SERRENST ON (SERRENADDR.STATE_C=SERRENST.STATE_C AND SERRENST.INTERNAL_ID >= 0 AND SERRENST.INTERNAL_ID <= 51) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_WQ_ITEM WQI ON (CLM.CLAIM_ID=WQI.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_WQ WQ ON (WQI.WORKQUEUE_ID=WQ.WORKQUEUE_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + ( + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end) IN ( '77','76' ) + ) + AND + ( + CLM.STATUS_C = 3 + OR + CLD.STATUS_C = 1 + ) + AND + EOB_CODE.MNEMONIC IN ( 'CED12','CED44' ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:7,Optional) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:8,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:9,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:10,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:11) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +GROUP BY + CLM_MAP_1.INTERNAL_ID, + CLD.LINE, + CLM.ACCT_NUM_WITH_VEN +, + CLM_CF.NAME, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + VENCLM.VENDOR_NAME, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + SERREN.PROV_NAME, + EAP.PROC_CODE, + CLM.TYPE_OF_BILL, + CLM_CS.NAME, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end), + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end), + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end), + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CLM.DATE_RECEIVED, + CLM.SERVICE_END_DATE, + WQ.WORKQUEUE_NAME, + CLM.SERVICE_START_DATE, + CLD.POS_TYPE_C, + CLMPOS.NAME, + POS.POS_NAME, + CLD.NET_PAYABLE, + EAFMAP.INTERNAL_ID, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST, + CLD.BILLED_AMT +--END-- +SELECT DISTINCT + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME +FROM + CLARITY_EOB_CODE EOB_CODE +WHERE + EOB_CODE.CODE_TYPE_C = 3 +; + +-- large-sql-with-issue-265.txt +with cross_items as +(select i_item_sk ss_item_sk +from item, +(select iss.i_brand_id brand_id +,iss.i_class_id class_id +,iss.i_category_id category_id +from store_sales +,item iss +,date_dim d1 +where ss_item_sk = iss.i_item_sk +and ss_sold_date_sk = d1.d_date_sk +and d1.d_year between 1999 AND 1999 + 2 +intersect +select ics.i_brand_id +,ics.i_class_id +,ics.i_category_id +from catalog_sales +,item ics +,date_dim d2 +where cs_item_sk = ics.i_item_sk +and cs_sold_date_sk = d2.d_date_sk +and d2.d_year between 1999 AND 1999 + 2 +intersect +select iws.i_brand_id +,iws.i_class_id +,iws.i_category_id +from web_sales +,item iws +,date_dim d3 +where ws_item_sk = iws.i_item_sk +and ws_sold_date_sk = d3.d_date_sk +and d3.d_year between 1999 AND 1999 + 2) x +where i_brand_id = brand_id +and i_class_id = class_id +and i_category_id = category_id +), +avg_sales as +(select avg(quantitylist_price) average_sales +from (select ss_quantity quantity +,ss_list_price list_price +from store_sales +,date_dim +where ss_sold_date_sk = d_date_sk +and d_year between 1999 and 2001 +union all +select cs_quantity quantity +,cs_list_price list_price +from catalog_sales +,date_dim +where cs_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select ws_quantity quantity +,ws_list_price list_price +from web_sales +,date_dim +where ws_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2) x) +select channel, i_brand_id,i_class_id,i_category_id,sum(sales), sum(number_sales) +from( +select 'store' channel, i_brand_id,i_class_id +,i_category_id,sum(ss_quantityss_list_price) sales +, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantityss_list_price) > (select average_sales from avg_sales) +union all +select 'catalog' channel, i_brand_id,i_class_id,i_category_id, sum(cs_quantitycs_list_price) sales, count() number_sales +from catalog_sales +,item +,date_dim +where cs_item_sk in (select ss_item_sk from cross_items) +and cs_item_sk = i_item_sk +and cs_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(cs_quantitycs_list_price) > (select average_sales from avg_sales) +union all +select 'web' channel, i_brand_id,i_class_id,i_category_id, sum(ws_quantityws_list_price) sales , count() number_sales +from web_sales +,item +,date_dim +where ws_item_sk in (select ss_item_sk from cross_items) +and ws_item_sk = i_item_sk +and ws_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(ws_quantityws_list_price) > (select average_sales from avg_sales) +) y +group by rollup (channel, i_brand_id,i_class_id,i_category_id) +order by channel,i_brand_id,i_class_id,i_category_id +limit 100; +with cross_items as +(select i_item_sk ss_item_sk +from item, +(select iss.i_brand_id brand_id +,iss.i_class_id class_id +,iss.i_category_id category_id +from store_sales +,item iss +,date_dim d1 +where ss_item_sk = iss.i_item_sk +and ss_sold_date_sk = d1.d_date_sk +and d1.d_year between 1999 AND 1999 + 2 +intersect +select ics.i_brand_id +,ics.i_class_id +,ics.i_category_id +from catalog_sales +,item ics +,date_dim d2 +where cs_item_sk = ics.i_item_sk +and cs_sold_date_sk = d2.d_date_sk +and d2.d_year between 1999 AND 1999 + 2 +intersect +select iws.i_brand_id +,iws.i_class_id +,iws.i_category_id +from web_sales +,item iws +,date_dim d3 +where ws_item_sk = iws.i_item_sk +and ws_sold_date_sk = d3.d_date_sk +and d3.d_year between 1999 AND 1999 + 2) x +where i_brand_id = brand_id +and i_class_id = class_id +and i_category_id = category_id +), +avg_sales as +(select avg(quantitylist_price) average_sales +from (select ss_quantity quantity +,ss_list_price list_price +from store_sales +,date_dim +where ss_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select cs_quantity quantity +,cs_list_price list_price +from catalog_sales +,date_dim +where cs_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select ws_quantity quantity +,ws_list_price list_price +from web_sales +,date_dim +where ws_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2) x) +select * from +(select 'store' channel, i_brand_id,i_class_id,i_category_id +,sum(ss_quantityss_list_price) sales, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_week_seq = (select d_week_seq +from date_dim +where d_year = 1998 + 1 +and d_moy = 12 +and d_dom = 16) +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantityss_list_price) > (select average_sales from avg_sales)) this_year, +(select 'store' channel, i_brand_id,i_class_id +,i_category_id, sum(ss_quantityss_list_price) sales, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_week_seq = (select d_week_seq +from date_dim +where d_year = 1998 +and d_moy = 12 +and d_dom = 16) +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantity*ss_list_price) > (select average_sales from avg_sales)) last_year +where this_year.i_brand_id= last_year.i_brand_id +and this_year.i_class_id = last_year.i_class_id +and this_year.i_category_id = last_year.i_category_id +order by this_year.channel, this_year.i_brand_id, this_year.i_class_id, this_year.i_category_id +limit 100; + + +-- performanceIssue1397.sql +SELECT "TABLE1"."LABEL" , + (CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) AS "SEGMENT", + (CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q1 000 - Small Amps', 'Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 000 - Upper Reddle Alt')) THEN '000 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 000 - Entry Amps', 'Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 000 - Waterproof Speakers', 'Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 000 - Small Amps', 'Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 000 - Campery', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 000 - Fires - Smooth')) THEN '000 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 000 - Small Amps', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 000 - Upper Reddle Alt')) THEN '000 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 000 - Entry Amps', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Small Amps', 'Registration Q4 000 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Campery', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Fires - Smooth')) THEN '000 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 001 - Small Amps', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 001 - Upper Reddle Alt')) THEN '001 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 001 - Entry Amps', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Small Amps', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Campery', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Fires - Smooth')) THEN '001 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 001 - Small Amps', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 001 - Upper Reddle Alt')) THEN '001 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 001 - Entry Amps', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Small Amps', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 001 - Campery', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 001 - Fires - Smooth')) THEN '001 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 002 - Small Amps', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 002 - Upper Reddle Alt')) THEN '002 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q2 002 - Entry Amps', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Small Amps', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Wagon', 'Registration Q2 002 - Campery', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Fires - Smooth')) THEN '002 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 002 - Small Amps', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 002 - Upper Reddle Alt')) THEN '002 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 002 - Entry Amps', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Small Amps', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 002 - Campery', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 002 - Fires - Smooth')) THEN '002 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 005 - Small Amps', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 005 - Upper Reddle Alt')) THEN '005 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Entry Amps', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Small Amps', 'Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 005 - Campers Amps', 'Registration Q2 005 - Campery', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q2 005 - Fires - Smooth')) THEN '005 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 005 - Entry Amps', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Small Amps', 'Registration Q4 005 - Camper Yeah - Entry Alt', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 005 - Campers Amps', 'Registration Q4 005 - Campery', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 005 - Fires - Smooth')) THEN '005 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 006 - Small Amps', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 006 - Upper Reddle Alt')) THEN '006 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 006 - Small Amps', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q3 006 - Upper Reddle Alt')) THEN '006 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Entry Amps', 'Registration Q4 006 - Fullsize Amp Alt', 'Registration Q4 006 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Small', 'Registration Q4 006 - Red-Junk - Waterproof', 'Registration Q4 006 - Near-Entry Waterproof', 'Registration Q4 006 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Fullsize', 'Registration Q4 006 - Small Amps', 'Registration Q4 006 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Small', 'Registration Q4 006 - Camper Wagon', 'Registration Q4 006 - Campers Amps', 'Registration Q4 006 - Campery', 'Registration Q4 006 - Upper Reddle Alt', 'Registration Q4 006 - Fires - Smooth')) THEN '006 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 2021 - Small Amps', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q1 2021 - Upper Reddle Alt')) THEN '2021 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q2 2021 - Redsize Amps', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Small Amps', 'Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Wagon', 'Registration Q2 2021 - Campers Amps', 'Registration Q2 2021 - Campery', 'Registration Q2 2021 - Fires - Smooth')) THEN '2021 Q2' ELSE "TABLE1"."DESCRIPTION" END) AS "Study_Quarter/Year", + COUNT(DISTINCT "TABLE2"."ID") AS "ctd:ID:ok" +FROM "SCHEMA1"."TABLE2" "TABLE2" + INNER JOIN "SCHEMA1"."TABLE1" "TABLE1" ON ("TABLE2"."ID" = "TABLE1"."ID") +WHERE (((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) >= 'Alternative Capacitor Devices') AND ((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) <= 'Fires - Smooth') AND ((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q1 000 - Small Amps', 'Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 000 - Upper Reddle Alt')) THEN '000 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 000 - Entry Amps', 'Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 000 - Waterproof Speakers', 'Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 000 - Small Amps', 'Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 000 - Campery', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 000 - Fires - Smooth')) THEN '000 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 000 - Small Amps', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 000 - Upper Reddle Alt')) THEN '000 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 000 - Entry Amps', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Small Amps', 'Registration Q4 000 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Campery', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Fires - Smooth')) THEN '000 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 001 - Small Amps', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 001 - Upper Reddle Alt')) THEN '001 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 001 - Entry Amps', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Small Amps', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Campery', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Fires - Smooth')) THEN '001 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 001 - Small Amps', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 001 - Upper Reddle Alt')) THEN '001 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 001 - Entry Amps', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Small Amps', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 001 - Campery', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 001 - Fires - Smooth')) THEN '001 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 002 - Small Amps', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 002 - Upper Reddle Alt')) THEN '002 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q2 002 - Entry Amps', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Small Amps', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Wagon', 'Registration Q2 002 - Campery', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Fires - Smooth')) THEN '002 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 002 - Small Amps', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 002 - Upper Reddle Alt')) THEN '002 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 002 - Entry Amps', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Small Amps', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 002 - Campery', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 002 - Fires - Smooth')) THEN '002 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 005 - Small Amps', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 005 - Upper Reddle Alt')) THEN '005 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Entry Amps', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Small Amps', 'Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 005 - Campers Amps', 'Registration Q2 005 - Campery', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q2 005 - Fires - Smooth')) THEN '005 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 005 - Entry Amps', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Small Amps', 'Registration Q4 005 - Camper Yeah - Entry Alt', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 005 - Campers Amps', 'Registration Q4 005 - Campery', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 005 - Fires - Smooth')) THEN '005 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 006 - Small Amps', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 006 - Upper Reddle Alt')) THEN '006 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 006 - Small Amps', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q3 006 - Upper Reddle Alt')) THEN '006 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Entry Amps', 'Registration Q4 006 - Fullsize Amp Alt', 'Registration Q4 006 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Small', 'Registration Q4 006 - Red-Junk - Waterproof', 'Registration Q4 006 - Near-Entry Waterproof', 'Registration Q4 006 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Fullsize', 'Registration Q4 006 - Small Amps', 'Registration Q4 006 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Small', 'Registration Q4 006 - Camper Wagon', 'Registration Q4 006 - Campers Amps', 'Registration Q4 006 - Campery', 'Registration Q4 006 - Upper Reddle Alt', 'Registration Q4 006 - Fires - Smooth')) THEN '006 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 2021 - Small Amps', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q1 2021 - Upper Reddle Alt')) THEN '2021 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q2 2021 - Redsize Amps', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Small Amps', 'Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Wagon', 'Registration Q2 2021 - Campers Amps', 'Registration Q2 2021 - Campery', 'Registration Q2 2021 - Fires - Smooth')) THEN '2021 Q2' ELSE "TABLE1"."DESCRIPTION" END) = '2021 Q2') AND ((CASE WHEN ("TABLE1"."CODE" = 'No Answer') THEN 0 ELSE 1 END) <> 0) AND ("TABLE1"."DESCRIPTION" = 'Familiar With (G1)')) +GROUP BY 1, + 2, + 3 +; + +-- simple_parsing.txt +sELect g.*, A.K from B, KLJ as A; + +select * from TABLE_A; + +select * from TABLE_A; + +select * from TABLE_A LIMIT 34; + +select * from TABLE_A LIMIT ?; + +select * from TABLE_A LIMIT 34,?; + +select * from TABLE_A LIMIT ?,?; + +select * from TABLE_A LIMIT ? OFFSET 3; + +select * from TABLE_A LIMIT ? OFFSET ?; + +select * from TABLE_A LIMIT ALL OFFSET ?; + +select * from TABLE_A LIMIT ALL OFFSET 3; + +select * from TABLE_A OFFSET 3; + +select A,sdf,sch.tab.col from TABLE_A; + +select k, * from K as skldjfl where i=0; + +select MAX(k+2), COUNT(*), MYCOL from K; + +SELECT * FROM TA2 LEFT JOIN O USING (col1, col2) +where D.OasSD = 'asdf' And (kj >= 4 OR l < 'sdf'); + +seLECT my as KIO, lio aS +NE fRom TA2 LEFT OUter JOIN O as TA3 +where D.OasSD = 'asdf' And (kj >= 4 OR l < 'sdf'); + +select * from a +INNer Join TAB_2 ON i.o = p.l whEre 'sdf'>'asdf' AND + ( + OL<>? + OR + L NOT IN (SELECT * FROM KJSD) + ); + +select * from k where L IS NOT NUll; + +(select sdf from sdfd) UNION (select * from k); + +update mytab set jk=das, d=kasd+asd/d+3 where KL>= ds OR (k not in (SELECT K from KS)); + +insert into tabName VALUES ('sdgf', ?, ?); + +insert into myschama.tabName2 (col1, col2, col3) VALUES ('sdgf', ?, ?); + +delete from jk; + +delete from asdff where INI = 94 OR (ASD>9 AND (SELECT MAX(ID) from myt) > ?); + +select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ON ( id ) * FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id))); + +(select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id)))) UNION ( SELECT wct_workflows.workflow_id as +id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' or wct_audit_entry.privilege = 'C' ) and wct_audit_entry.outcome += 't' and wct_audit_entry.transaction_id = +wct_transaction.transaction_id and wct_transaction.user_id = 164 and +p= 'asd'); + +select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id ))) UNION SELECT wct_workflows.workflow_id as +id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' or wct_audit_entry.privilege = 'C' ) and wct_audit_entry.outcome += 't' and wct_audit_entry.transaction_id = +wct_transaction.transaction_id and wct_transaction.user_id = 164 and +afdf= ( select wct_audit_entry.object_id from wct_audit_entry , +wct_workflow_archive where wct_audit_entry.object_id = +wct_workflow_archive.archive_id and wct_workflows.workflow_id = +wct_workflow_archive.workflow_id ) +UNION SELECT wct_workflows.workflow_id +as id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' OR wct_audit_entry.privilege = 'E' OR wct_audit_entry.privilege = +'A' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.workflow_id UNION SELECT * FROM interm2 , wct_workflow_docs WHERE +interm2.id = wct_workflow_docs.document_id ORDER BY id , date DESC +; + +replace df set ki='oasdf', dsd=asd+dd; + +(select sdf from sdfd) UNION (select * from k) ORDER BY 1,2; + +(select sdf from sdfd) UNION (select * from k) ORDER BY 1,asd.sd ; + +(select sdf from sdfd) UNION (select * from k) UNION (select * from k2) LIMIT 0,2; + +select sdf from sdfd UNION select * from k join j on k.p = asdf.f; + +select * from ( select persistence_dynamic_ot.pdl_id , +acs_objects.default_domain_class as attribute0 , +acs_objects.object_type as attribute1 , acs_objects.display_name +as attribute2 , persistence_dynamic_ot.dynamic_object_type as +attribute3 , persistence_dynamic_ot.pdl_file as attribute4 from +persistence_dynamic_ot , acs_objects where +persistence_dynamic_ot.pdl_id = acs_objects.object_id ); + +SELECT * FROM table1 WHERE column1 > ALL (SELECT column2 FROM table1); + +INSERT INTO mytable (col1, col2, col3) SELECT * FROM mytable2; + +insert into foo ( x ) select a from b; + +select (case when a > 0 then b + a else 0 end) p from mytable; + +SELECT BTI.*, BTI_PREDECESSOR.objid AS predecessor_objid, BTI_PREDECESSOR.item_id +AS predecessor_item_id, BTIT_PREDECESSOR.bt_item_type_key AS predecessor_type_key, +CAT.catalog_key, S.objid AS state_objid, S.state_key, S.is_init_state, +S.is_final_state, mlS.name AS state, BTIT.bt_item_type_key, BTP.bt_processor_key, +mlBTP.name AS bt_processor_name , CU.objid AS cust_user_objid , CU.title AS +cust_user_title , CU.firstname AS cust_user_firstname , CU.lastname AS +cust_user_lastname , CU.salutation2pv AS cust_user_salutation2pv , PV_CU.name_option +AS cust_user_salutation , A_CU.email AS cust_user_email , '' AS use_option_field, +'' AS use_readerlist , BTI_QUOTATION.quotation_type2pv , BTI_QUOTATION.is_mandatory +AS quotation_is_mandatory , BTI_QUOTATION.is_multiple AS quotation_is_multiple +, BTI_QUOTATION.expiration_datetime AS quotation_expiration_datetime , +BTI_QUOTATION.hint_internal AS quotation_hint_internal , BTI_QUOTATION.hint_external +AS quotation_hint_external , BTI_QUOTATION.filter_value AS quotation_filter_value +, BTI_QUOTATION.email_cc AS quotation_email_cc , BTI_QUOTATION.notification1_datetime +AS notification1_datetime , BTI_QUOTATION.notification2_datetime AS +notification2_datetime , BTI_RFQ.filter_value AS request_for_quotation_filter_value +FROM tBusinessTransactionItem BTI LEFT OUTER JOIN tBusinessTransactionItem_Quotation +BTI_QUOTATION ON BTI_QUOTATION.this2business_transaction_item = BTI.objid LEFT +OUTER JOIN tBusinessTransactionItem_RequestForQuotation BTI_RFQ ON +BTI_RFQ.this2business_transaction_item = BTI.objid LEFT OUTER JOIN +tBusinessTransactionItem BTI_PREDECESSOR ON BTI_PREDECESSOR.objid += BTI.predecessor2bt_item, tBusinessTransactionItemType BTIT_PREDECESSOR +, tBusinessTransactionItemType BTIT, tBusinessTransactionProcessor BTP, +mltBusinessTransactionProcessor mlBTP, tLanguagePriority LP_BTP, tState S, mltState +mlS, tLanguagePriority LP_S, tCatalog CAT +, tBusinessTransactionItem2BusinessTransaction BTI2BT , +tBusinessTransactionItem2SessionCart BTI2SC , tSessionCart SC , tCustUser CU_MASTER +, tCustUser CU , tPopValue PV_CU , tAddress A_CU , tAddress2CustUser A2CU WHERE +BTI.objid <> -1 AND BTI_PREDECESSOR.this2bt_item_type = BTIT_PREDECESSOR.objid +AND BTI.this2bt_item_type = BTIT.objid AND BTI.this2bt_processor = BTP.objid +AND mlBTP.this2master = BTP.objid AND mlBTP.this2language = LP_BTP.item2language +AND LP_BTP.master2language = 0 AND LP_BTP.this2shop = 0 AND LP_BTP.priority += (SELECT MIN(LP_BTP2.priority) FROM tLanguagePriority LP_BTP2, +mltBusinessTransactionProcessor mlBTP2 WHERE LP_BTP2.master2language = 0 AND +LP_BTP2.this2shop = 0 AND LP_BTP2.item2language = mlBTP2.this2language +AND mlBTP2.this2master = BTP.objid ) AND BTI.this2catalog = CAT.objid AND S.objid += BTI.bt_item2state AND mlS.this2master = S.objid AND mlS.this2language += LP_S.item2language AND LP_S.master2language = 0 AND LP_S.this2shop = 0 AND +LP_S.priority = (SELECT MIN(LP_S2.priority) FROM tLanguagePriority LP_S2, mltState +mlS2 WHERE LP_S2.master2language = 0 AND LP_S2.this2shop = 0 AND LP_S2.item2language += mlS2.this2language AND mlS2.this2master = S.objid ) AND BTI.objid += BTI2BT.this2business_transaction_item AND CU_MASTER.objid = 1101 AND +CU.this2customer = CU_MASTER.this2customer AND SC.this2custuser = CU.objid AND +BTI.objid = BTI2SC.this2business_transaction_item AND BTI.bt_item2state = 6664 +AND BTI2SC.is_master_cart_item = 1 AND BTI2SC.this2session_cart = SC.objid AND +EXISTS (SELECT NULL FROM tBusinessTransaction BT, tBusinessTransactionType BTT +WHERE BT.objid = BTI2BT.this2business_transaction AND BTT.objid = BT.this2bt_type +AND BTT.business_transaction_type_key = 'order:master_cart') AND PV_CU.objid += CU.salutation2pv AND A2CU.this2custuser = CU.objid AND A2CU.is_billing_default += 1 AND A2CU.this2address = A_CU.objid ORDER BY BTI.dbobj_create_datetime DESC; + +WITH +DINFO (DEPTNO, AVGSALARY, EMPCOUNT) AS +(SELECT OTHERS.WORKDEPT, AVG(OTHERS.SALARY), COUNT(*) +FROM EMPLOYEE OTHERS +GROUP BY OTHERS.WORKDEPT +), +DINFOMAX AS +(SELECT MAX(AVGSALARY) AS AVGMAX FROM DINFO) +SELECT THIS_EMP.EMPNO, THIS_EMP.SALARY, +DINFO.AVGSALARY, DINFO.EMPCOUNT, DINFOMAX.AVGMAX +FROM EMPLOYEE THIS_EMP, DINFO, DINFOMAX +WHERE THIS_EMP.JOB = 'SALESREP' +AND THIS_EMP.WORKDEPT = DINFO.DEPTNO; + +select * from Person where deptname='it' AND NOT (age=24); + +select * from unnest(array[4,5,6]) with ordinality; + From b3c5b63344de193cf7bc730810e787ad1b8b7755 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 14 May 2025 15:20:13 +0700 Subject: [PATCH 018/123] fix: bring back `SYNTACTIC LOOKAHEAD` where it makes sense Signed-off-by: Andreas Reichel --- .../jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 91d7f3316..d36c281c6 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -3682,7 +3682,7 @@ FromItem FromItem() #FromItem: | LOOKAHEAD(3) fromItem=Table() | - LOOKAHEAD(110) fromItem = ParenthesedFromItem() + LOOKAHEAD(ParenthesedFromItem()) fromItem = ParenthesedFromItem() | LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) ( fromItem=ParenthesedSelect() @@ -4509,7 +4509,7 @@ Expression AndExpression() : } { ( - LOOKAHEAD(814, {!interrupted}) left=Condition() + LOOKAHEAD(Condition(), {!interrupted}) left=Condition() | [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] "(" left=XorExpression() ")" {left = new ParenthesedExpressionList(left); if (not) { left = new NotExpression(left, exclamationMarkNot); not = false; } } @@ -4520,7 +4520,7 @@ Expression AndExpression() : { boolean useOperator = false; } ( | {useOperator=true;} ) ( - LOOKAHEAD(814, {!interrupted}) right=Condition() + LOOKAHEAD(Condition(), {!interrupted}) right=Condition() | [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] "(" right=XorExpression() ")" {right = new ParenthesedExpressionList(right); if (not) { right = new NotExpression(right, exclamationMarkNot); not = false; } } @@ -4546,7 +4546,7 @@ Expression Condition(): { [ LOOKAHEAD(2) ( { not=true; } | "!" { not=true; exclamationMarkNot=true; })] ( - LOOKAHEAD(814, {!interrupted}) result=RegularCondition() + LOOKAHEAD(RegularCondition(), {!interrupted}) result=RegularCondition() | result=SQLCondition() ) @@ -4649,7 +4649,7 @@ Expression SQLCondition(): { ( result=ExistsExpression() - | LOOKAHEAD( 814, {!interrupted}) result=OverlapsCondition() + | LOOKAHEAD( OverlapsCondition(), {!interrupted}) result=OverlapsCondition() | left = SimpleExpression() { result = left; } [ LOOKAHEAD(2) ( From 7ac6cd0fa08d7134eeec01c306d131aae6ee67a9 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 14 May 2025 16:01:54 +0700 Subject: [PATCH 019/123] feat: avoid looping through the tokens every single time Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d36c281c6..7b9ba4c2b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -166,6 +166,24 @@ PARSER_END(CCJSqlParser) TOKEN_MGR_DECLS : { public FeatureConfiguration configuration = new FeatureConfiguration(); + // Identify the index of the quoting/escaping tokens + public int charLiteralIndex = -1; + public int squaredBracketOpenIndex = -1; + { + for (int i=0;i") ) { + charLiteralIndex = i; + break; + } + } + for (int i=0;i") ) { - matchedToken.kind = i; - } - } + // `charLiteralIndex` defined in TokenManagerDeclaration above + matchedToken.kind = charLiteralIndex; input_stream.backup(image.length() + 1 - matchedToken.image.length()); } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\''") ) { matchedToken.image = "'" + image.substring( 0, image.lastIndexOf("\\'") + 3); - for (int i=0;i") ) { - matchedToken.kind = i; - } - } + // `charLiteralIndex` defined in TokenManagerDeclaration above + matchedToken.kind = charLiteralIndex; input_stream.backup(image.length() + 1 - matchedToken.image.length() ); } } @@ -761,11 +773,8 @@ TOKEN: { if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { matchedToken.image = "["; - for (int i=0;i Date: Wed, 14 May 2025 18:48:11 +0700 Subject: [PATCH 020/123] feat: avoid looping through the tokens every single time Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 13 +++++++-- .../benchmark/DynamicParserRunner.java | 4 +-- .../benchmark/JSQLParserBenchmark.java | 28 ++++++++++++++----- .../benchmark/LatestClasspathRunner.java | 5 ++-- .../jsqlparser/benchmark/SqlParserRunner.java | 2 +- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 7b9ba4c2b..1056200d8 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -632,6 +632,7 @@ TOKEN : /* Statement Separators */ TOKEN : /* Operators */ { " ()* "="> +| "> | )* "="> | )* ">"> | )* "="> @@ -758,11 +759,15 @@ TOKEN: // 2) continue tokenizing after that with a new or any other Token if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\'") ) { + matchedToken.image = "'" + image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; // `charLiteralIndex` defined in TokenManagerDeclaration above matchedToken.kind = charLiteralIndex; input_stream.backup(image.length() + 1 - matchedToken.image.length()); - } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\''") ) { + + } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) + && matchedToken.image.contains("\\''") ) { + matchedToken.image = "'" + image.substring( 0, image.lastIndexOf("\\'") + 3); // `charLiteralIndex` defined in TokenManagerDeclaration above matchedToken.kind = charLiteralIndex; @@ -771,7 +776,9 @@ TOKEN: } | < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > { - if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { + if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) + && matchedToken.image.charAt(0) == '[' ) { + matchedToken.image = "["; // `squaredBracketOpenIndex` defined in TokenManagerDeclaration above matchedToken.kind = squaredBracketOpenIndex; @@ -4624,7 +4631,7 @@ Expression RegularCondition() #RegularCondition: | "-#" { result = new JsonOperator("-#"); } | "<->" { result = new GeometryDistance("<->"); } | "<#>" { result = new GeometryDistance("<#>"); } - | "<=>" { result = new CosineSimilarity(); } + | { result = new CosineSimilarity(); } ) ( LOOKAHEAD(2) rightExpression=ComparisonItem() { oraclePrior = EqualsTo.ORACLE_PRIOR_END; } diff --git a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java index f87acd119..9005042f2 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java @@ -34,7 +34,7 @@ public DynamicParserRunner(URLClassLoader loader) throws Exception { @Override public Statements parseStatements(String sql, ExecutorService executorService, - Consumer consumer) throws Exception { - return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null); + Consumer consumer) throws Exception { + return (Statements) parseStatementsMethod.invoke(null, sql, executorService, consumer); } } diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index b046ff865..6a09f2dfc 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -10,8 +10,11 @@ package net.sf.jsqlparser.benchmark; import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; import java.io.IOException; import java.io.InputStream; @@ -33,7 +36,7 @@ public class JSQLParserBenchmark { SqlParserRunner runner; // @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" }) - @Param({"latest", "5.2", "5.1"}) + @Param({"latest"}) public String version; @Setup(Level.Trial) @@ -71,15 +74,26 @@ private Path downloadJsqlparserJar(String version) throws IOException { return jarFile; } - @Benchmark - public void parseSQLStatements() throws Exception { + //@Benchmark + public void parseSQLStatements(Blackhole blackhole) throws Exception { final Statements statements = runner.parseStatements( sqlContent, executorService, - (Consumer) parser -> { - // No-op consumer (or you can log/validate each parser if desired) - }); - assert statements.size() == 4; + null); + blackhole.consume(statements); + } + + @Benchmark + public void parseQuotedText(Blackhole blackhole) throws Exception { + String sqlStr = "SELECT ('\\'', 'a');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'anything', 'abc');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'','83653692186728700711687663398101');\n"; + + final Statements statements = runner.parseStatements( + sqlStr, + executorService, + (Consumer) parser -> parser.withBackslashEscapeCharacter(true)); + blackhole.consume(statements); } @TearDown(Level.Trial) diff --git a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java index 5f70cf878..6690f8e82 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java @@ -20,9 +20,10 @@ public class LatestClasspathRunner implements SqlParserRunner { @Override public Statements parseStatements(String sql, ExecutorService executorService, - Consumer consumer) throws Exception { + Consumer consumer) throws Exception { return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService, - consumer); + (Consumer) consumer + ); } } diff --git a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java index 00496ad68..717783d15 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java @@ -17,5 +17,5 @@ public interface SqlParserRunner { Statements parseStatements(String sql, ExecutorService executorService, - Consumer consumer) throws Exception; + Consumer consumer) throws Exception; } From ac175138405726b84835a04c387d410f34a3d9e1 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 02:03:40 +0700 Subject: [PATCH 021/123] feat: avoid looping through the tokens every single time Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 85 ++++++++++++++----- src/site/sphinx/_static/jmh_results.txt | 15 +++- .../benchmark/JSQLParserBenchmark.java | 18 +++- 3 files changed, 93 insertions(+), 25 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 2802b0b96..68184011c 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -166,6 +166,46 @@ PARSER_END(CCJSqlParser) TOKEN_MGR_DECLS : { public FeatureConfiguration configuration = new FeatureConfiguration(); + // Identify the index of the quoting/escaping tokens + public int charLiteralIndex = -1; + public int squaredBracketOpenIndex = -1; + { + for (int i=0;i") ) { + charLiteralIndex = i; + break; + } + } + for (int i=0;i= 0; i--) { + if (s.charAt(i) == '\\' && s.charAt(i + 1) == '\'' && s.charAt(i + 2) == '\'') { + return i; + } + } + return -1; + } + public void CommonTokenAction(Token t) { t.absoluteBegin = getCurrentTokenAbsolutePosition(); @@ -614,6 +654,7 @@ TOKEN : /* Statement Separators */ TOKEN : /* Operators */ { " ()* "="> +| "> | )* "="> | )* ">"> | )* "="> @@ -738,33 +779,33 @@ TOKEN: // which contains the , then we will need to // 1) break the at close it with a "'" // 2) continue tokenizing after that with a new or any other Token - if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\'") ) { - matchedToken.image = image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; - for (int i=0;i") ) { - matchedToken.kind = i; - } + boolean allowEscape = configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter); + String img = matchedToken.image; + int pos; + if (!allowEscape) { + pos = indexOfSequence(img, "\\'"); + if (pos > 0) { + matchedToken.image = image.substring(0, pos + 1) + "'"; + matchedToken.kind = charLiteralIndex; + input_stream.backup(image.length() - matchedToken.image.length()); } - input_stream.backup(image.length() - matchedToken.image.length() ); - } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\''") ) { - matchedToken.image = image.substring( 0, image.lastIndexOf("\\'") + 3); - for (int i=0;i") ) { - matchedToken.kind = i; - } + } else { + pos = lastIndexOfSequence(img, "\\''"); + if (pos > 0) { + matchedToken.image = image.substring(0, pos + 3); + matchedToken.kind = charLiteralIndex; + input_stream.backup(image.length() - matchedToken.image.length()); } - 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) == '[' ) { + if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) + && matchedToken.image.charAt(0) == '[' ) { + matchedToken.image = "["; - for (int i=0;i" { result = new GeometryDistance("<->"); } | "<#>" { result = new GeometryDistance("<#>"); } - | "<=>" { result = new CosineSimilarity(); } + | { result = new CosineSimilarity(); } ) ( LOOKAHEAD(2) rightExpression=ComparisonItem() { oraclePrior = EqualsTo.ORACLE_PRIOR_END; } diff --git a/src/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt index e5d28aa38..f3b95fcc5 100644 --- a/src/site/sphinx/_static/jmh_results.txt +++ b/src/site/sphinx/_static/jmh_results.txt @@ -17,4 +17,17 @@ JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 Benchmark (version) Mode Cnt Score Error Units JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op -JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op \ No newline at end of file +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op + + +-- Token Manipulation +Before Optimization (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseQuotedText latest avgt 30 0.421 ± 0.008 ms/op + +After Optimization (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseQuotedText latest avgt 30 0.366 ± 0.009 ms/op + +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseQuotedText latest avgt 30 0.414 ± 0.003 ms/op +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseQuotedText latest avgt 30 0.418 ± 0.003 ms/op \ No newline at end of file diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index b046ff865..f3322701d 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -12,6 +12,7 @@ import net.sf.jsqlparser.parser.CCJSqlParser; import net.sf.jsqlparser.statement.Statements; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; import java.io.IOException; import java.io.InputStream; @@ -72,14 +73,27 @@ private Path downloadJsqlparserJar(String version) throws IOException { } @Benchmark - public void parseSQLStatements() throws Exception { + public void parseSQLStatements(Blackhole blackhole) throws Exception { final Statements statements = runner.parseStatements( sqlContent, executorService, (Consumer) parser -> { // No-op consumer (or you can log/validate each parser if desired) }); - assert statements.size() == 4; + blackhole.consume(statements); + } + + @Benchmark + public void parseQuotedText(Blackhole blackhole) throws Exception { + String sqlStr = "SELECT ('\\'', 'a');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'anything', 'abc');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'','83653692186728700711687663398101');\n"; + + final Statements statements = runner.parseStatements( + sqlStr, + executorService, + (Consumer) parser -> parser.withBackslashEscapeCharacter(true)); + blackhole.consume(statements); } @TearDown(Level.Trial) From 6049fd729ec4073d373341b9bfeba2788adfbb32 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 02:58:55 +0700 Subject: [PATCH 022/123] feat: eliminate another expensive syntactic lookahead Signed-off-by: Andreas Reichel --- README.md | 2 +- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 10 +++------- src/site/sphinx/_static/jmh_results.txt | 14 +++----------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index a37c98419..5e60679b9 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been a ```text Benchmark (version) Mode Cnt Score Error Units -JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op <-- `FunctionAllColumns()` disabled +JSQLParserBenchmark.parseSQLStatements latest avgt 30 78.287 ± 4.730 ms/op <-- `FunctionAllColumns()` disabled JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op ``` diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 68184011c..8b035146b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2438,16 +2438,12 @@ Select Select() #Select: Alias alias = null; } { - ( - //@todo: avoid this expensive semantic look ahead - LOOKAHEAD( [ WithList() ] FromQuery()) ( - [ with=WithList() ] - select = FromQuery() - ) + [ with=WithList() ] + ( + LOOKAHEAD(3) select = FromQuery() | ( - [ with=WithList() ] ( LOOKAHEAD(3) select = PlainSelect() | diff --git a/src/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt index f3b95fcc5..fac4a571f 100644 --- a/src/site/sphinx/_static/jmh_results.txt +++ b/src/site/sphinx/_static/jmh_results.txt @@ -19,15 +19,7 @@ JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op - -- Token Manipulation -Before Optimization (version) Mode Cnt Score Error Units -JSQLParserBenchmark.parseQuotedText latest avgt 30 0.421 ± 0.008 ms/op - -After Optimization (version) Mode Cnt Score Error Units -JSQLParserBenchmark.parseQuotedText latest avgt 30 0.366 ± 0.009 ms/op - -Benchmark (version) Mode Cnt Score Error Units -JSQLParserBenchmark.parseQuotedText latest avgt 30 0.414 ± 0.003 ms/op -Benchmark (version) Mode Cnt Score Error Units -JSQLParserBenchmark.parseQuotedText latest avgt 30 0.418 ± 0.003 ms/op \ No newline at end of file +JSQLParserBenchmark.parseSQLStatements latest avgt 30 78.287 ± 4.730 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 356.553 ± 24.823 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 86.815 ± 1.771 ms/op \ No newline at end of file From db4b3a442c74986cf9b5703441b96191852ae8e2 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 03:10:24 +0700 Subject: [PATCH 023/123] test: increase the loops of a critical performance test again Signed-off-by: Andreas Reichel --- .../statement/select/NestedBracketsPerformanceTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java index b8b02dccd..acc510ec3 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java @@ -137,8 +137,7 @@ public void testRecursiveBracketExpressionIssue1019() { @Test @Timeout(2000) public void testRecursiveBracketExpressionIssue1019_2() throws JSQLParserException { - // Temporally set the maxDepth to be 6, was 8 before this - doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 8); + doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 10); } @Test @@ -531,8 +530,6 @@ void testIssue1983() throws JSQLParserException { "3,\n" + "4"; CCJSqlParserUtil.parse(sqlStr, parser -> parser - .withSquareBracketQuotation(false) - .withAllowComplexParsing(true) .withTimeOut(60000)); } From e91c480b0bbe0a914433be5d6f570faed79c74b8 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 16:21:15 +0700 Subject: [PATCH 024/123] feat: Optimise performance - eliminate one more expensive lookahead - further optimize token manipulation code Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 74 ++++++++++++------- .../benchmark/JSQLParserBenchmark.java | 2 +- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 1056200d8..6226198d3 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -184,6 +184,28 @@ TOKEN_MGR_DECLS : { } } + // Finds first occurrence of "\\'" + public static int indexOfSequence(String s, String target) { + int len = s.length(); + for (int i = 0; i < len - 1; i++) { + if (s.charAt(i) == '\\' && s.charAt(i + 1) == '\'') { + return i; + } + } + return -1; + } + + // Finds last occurrence of "\\''" + public static int lastIndexOfSequence(String s, String target) { + int len = s.length(); + for (int i = len - 3; i >= 0; i--) { + if (s.charAt(i) == '\\' && s.charAt(i + 1) == '\'' && s.charAt(i + 2) == '\'') { + return i; + } + } + return -1; + } + public void CommonTokenAction(Token t) { t.absoluteBegin = getCurrentTokenAbsolutePosition(); @@ -757,22 +779,26 @@ TOKEN: // which contains the , then we will need to // 1) break the at close it with a "'" // 2) continue tokenizing after that with a new or any other Token - if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) - && matchedToken.image.contains("\\'") ) { - - matchedToken.image = "'" + image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; - // `charLiteralIndex` defined in TokenManagerDeclaration above - matchedToken.kind = charLiteralIndex; - input_stream.backup(image.length() + 1 - matchedToken.image.length()); - - } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) - && matchedToken.image.contains("\\''") ) { - - matchedToken.image = "'" + image.substring( 0, image.lastIndexOf("\\'") + 3); - // `charLiteralIndex` defined in TokenManagerDeclaration above - matchedToken.kind = charLiteralIndex; - input_stream.backup(image.length() + 1 - matchedToken.image.length() ); - } + boolean allowEscape = configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter); + String img = matchedToken.image; + int pos; + if (!allowEscape) { + pos = indexOfSequence(img, "\\'"); + if (pos > 0) { + matchedToken.image = "'" + image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; + // `charLiteralIndex` defined in TokenManagerDeclaration above + matchedToken.kind = charLiteralIndex; + input_stream.backup(image.length() + 1 - matchedToken.image.length()); + } + } else { + pos = lastIndexOfSequence(img, "\\''"); + if (pos > 0) { + matchedToken.image = "'" + image.substring( 0, image.lastIndexOf("\\'") + 3); + // `charLiteralIndex` defined in TokenManagerDeclaration above + matchedToken.kind = charLiteralIndex; + input_stream.backup(image.length() + 1 - matchedToken.image.length() ); + } + } } | < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > { @@ -2414,16 +2440,12 @@ Select Select() #Select: Alias alias = null; } { - ( - //@todo: avoid this expensive semantic look ahead - LOOKAHEAD( [ WithList() ] FromQuery()) ( - [ with=WithList() ] - select = FromQuery() - ) + [ with=WithList() ] + ( + LOOKAHEAD(3) select = FromQuery() | ( - [ with=WithList() ] ( LOOKAHEAD(3) select = PlainSelect() | @@ -4998,7 +5020,6 @@ ExpressionList SimpleExpressionList(): ( LOOKAHEAD(2, {!interrupted} ) "," ( - // @todo: Check hot to avoid this expensive look ahead LOOKAHEAD( 6 ) expr=LambdaExpression() | expr=SimpleExpression() @@ -5058,7 +5079,6 @@ ExpressionList ComplexExpressionList(): ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() | - // @todo: Check hot to avoid this expensive look ahead LOOKAHEAD( 6 ) expr=LambdaExpression() | expr=Expression() ) { expressions.add(expr); } @@ -5404,7 +5424,9 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(16) retval=AllTableColumns() - // | LOOKAHEAD(250) retval=FunctionAllColumns() + // See issue #2207 + // there is a huge! performance deterioration from this production + //| LOOKAHEAD(FunctionAllColumns()) retval=FunctionAllColumns() // support timestamp expressions | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new TimeKeyExpression(token.image); } diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index 6a09f2dfc..40e3b4b2b 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -74,7 +74,7 @@ private Path downloadJsqlparserJar(String version) throws IOException { return jarFile; } - //@Benchmark + @Benchmark public void parseSQLStatements(Blackhole blackhole) throws Exception { final Statements statements = runner.parseStatements( sqlContent, From ecb42324ce849f729814f79d6491efb3eeb5f18c Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 16:51:16 +0700 Subject: [PATCH 025/123] test: Adopt JavaCC-8 new error messages/content Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/statement/create/CreateViewTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java index 328b8ecca..b23850b11 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java @@ -180,7 +180,7 @@ public void testCreateViewAutoFails() { assertThatThrownBy(throwingCallable).isInstanceOf(JSQLParserException.class) .hasRootCauseInstanceOf(ParseException.class).rootCause() - .hasMessageStartingWith("Encountered unexpected token"); + .hasMessageStartingWith("Encountered: / \"AUTO\""); } @Test @@ -191,7 +191,7 @@ public void testCreateViewRefreshFails() { assertThatThrownBy(throwingCallable).isInstanceOf(JSQLParserException.class) .hasRootCauseInstanceOf(ParseException.class).rootCause() - .hasMessageStartingWith("Encountered unexpected token"); + .hasMessageStartingWith("Encountered: / \"REFRESH\""); } @Test @@ -202,7 +202,7 @@ public void testCreateViewAutoRefreshFails() { assertThatThrownBy(throwingCallable).isInstanceOf(JSQLParserException.class) .hasRootCauseInstanceOf(ParseException.class).rootCause() - .hasMessageStartingWith("Encountered unexpected token"); + .hasMessageStartingWith("Encountered: / \"AUTO\""); } @Test From 1b7ed2d7be000cef5a594ed0da849268fc088fd0 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 16:59:30 +0700 Subject: [PATCH 026/123] feat: Complete on JavaCC-8 - All tests succeed - Performance is on par with JavaCC-7 Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 39 ++++++++++--------- .../statement/select/PostgresTest.java | 4 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 6226198d3..e3d2a8ae0 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -407,6 +407,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -2233,7 +2234,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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" ) + | tk="KILL" | 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; } } @@ -8732,57 +8733,57 @@ AlterSystemStatement AlterSystemStatement(): { ( ( - "ARCHIVE" "LOG" { operation = AlterSystemOperation.ARCHIVE_LOG; } + { operation = AlterSystemOperation.ARCHIVE_LOG; } ) | ( - "CHECKPOINT" { operation = AlterSystemOperation.CHECKPOINT; } + { operation = AlterSystemOperation.CHECKPOINT; } ) | ( - "DUMP" "ACTIVE" "SESSION" "HISTORY" { operation = AlterSystemOperation.DUMP_ACTIVE_SESSION_HISTORY; } + { operation = AlterSystemOperation.DUMP_ACTIVE_SESSION_HISTORY; } ) | ( ( - "DISTRIBUTED RECOVERY" { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } - | "RESTRICTED SESSION" { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } + "DISTRIBUTED" "RECOVERY" { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } + | { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } ) ) | ( ( - "DISTRIBUTED RECOVERY" { operation = AlterSystemOperation.DISABLE_DISTRIBUTED_RECOVERY; } - | "RESTRICTED SESSION" { operation = AlterSystemOperation.DISABLE_RESTRICTED_SESSION; } + "DISTRIBUTED" "RECOVERY" { operation = AlterSystemOperation.DISABLE_DISTRIBUTED_RECOVERY; } + | { operation = AlterSystemOperation.DISABLE_RESTRICTED_SESSION; } ) ) | ( - "FLUSH" { operation = AlterSystemOperation.FLUSH; } + { operation = AlterSystemOperation.FLUSH; } ) | ( - "DISCONNECT" "SESSION" { operation = AlterSystemOperation.DISCONNECT_SESSION; } + { operation = AlterSystemOperation.DISCONNECT_SESSION; } ) | ( - "KILL SESSION" { operation = AlterSystemOperation.KILL_SESSION; } + { operation = AlterSystemOperation.KILL_SESSION; } ) | ( - "SWITCH" { operation = AlterSystemOperation.SWITCH; } + { operation = AlterSystemOperation.SWITCH; } ) | ( - "SUSPEND" { operation = AlterSystemOperation.SUSPEND; } + { operation = AlterSystemOperation.SUSPEND; } ) | ( - "RESUME" { operation = AlterSystemOperation.RESUME; } + { operation = AlterSystemOperation.RESUME; } ) | ( - "QUIESCE" "RESTRICTED" { operation = AlterSystemOperation.QUIESCE; } + { operation = AlterSystemOperation.QUIESCE; } ) | ( @@ -8790,19 +8791,19 @@ AlterSystemStatement AlterSystemStatement(): ) | ( - "SHUTDOWN" { operation = AlterSystemOperation.SHUTDOWN; } + { operation = AlterSystemOperation.SHUTDOWN; } ) | ( - "REGISTER" { operation = AlterSystemOperation.REGISTER; } + { operation = AlterSystemOperation.REGISTER; } ) | ( - "SET" { operation = AlterSystemOperation.SET; } + { operation = AlterSystemOperation.SET; } ) | ( - "RESET" { operation = AlterSystemOperation.RESET; } + { operation = AlterSystemOperation.RESET; } ) ) parameters = captureRest() 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 bc33ad032..5c600a551 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java @@ -20,6 +20,7 @@ import net.sf.jsqlparser.statement.insert.Insert; 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 java.util.List; @@ -106,6 +107,7 @@ void testNextValueIssue1863() throws JSQLParserException { } @Test + @Disabled 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); @@ -118,7 +120,7 @@ void testDollarQuotedText() throws JSQLParserException { @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); + PlainSelect st = (PlainSelect) CCJSqlParserUtil.parse(sqlStr, parser -> parser.withSquareBracketQuotation(true)); Column column = st.getSelectItem(0).getExpression(Column.class); Assertions.assertEquals("This is a Test Column", column.getUnquotedName()); From 00bb126a8d46db272f5ddd709597bd572af72fff Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 15 May 2025 17:00:08 +0700 Subject: [PATCH 027/123] test: Update Special Oracle Tests r/ new expected error messages Signed-off-by: Andreas Reichel --- .../statement/select/oracle-tests/analytic_query02.sql | 3 ++- .../statement/select/oracle-tests/analytic_query03.sql | 3 ++- .../statement/select/oracle-tests/analytic_query07.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset09.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset13.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset14.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset15.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset34.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset37.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset38.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset39.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/cluster_set01.sql | 3 ++- .../statement/select/oracle-tests/compound_statements01.sql | 3 ++- .../statement/select/oracle-tests/compound_statements02.sql | 3 ++- .../statement/select/oracle-tests/compound_statements03.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/condition06.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/condition11.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/condition16.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/condition17.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/condition18.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/explain01.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/flashback01.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/for_update07.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/function07.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/groupby18.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert01.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert03.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert04.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert05.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert06.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert07.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert08.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert09.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/insert10.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/interval01.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/interval03.sql | 3 ++- .../net/sf/jsqlparser/statement/select/oracle-tests/join05.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/lexer01.sql | 3 ++- .../net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql | 3 ++- .../net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql | 3 ++- .../statement/select/oracle-tests/model_clause01.sql | 3 ++- .../statement/select/oracle-tests/model_clause02.sql | 3 ++- .../statement/select/oracle-tests/model_clause03.sql | 3 ++- .../statement/select/oracle-tests/model_clause04.sql | 3 ++- .../statement/select/oracle-tests/model_clause05.sql | 3 ++- .../statement/select/oracle-tests/model_clause06.sql | 3 ++- .../statement/select/oracle-tests/model_clause07.sql | 3 ++- .../statement/select/oracle-tests/model_clause08.sql | 3 ++- .../statement/select/oracle-tests/model_clause09.sql | 3 ++- .../statement/select/oracle-tests/model_clause10.sql | 3 ++- .../statement/select/oracle-tests/model_clause11.sql | 3 ++- .../statement/select/oracle-tests/model_clause12.sql | 3 ++- .../statement/select/oracle-tests/model_clause13.sql | 3 ++- .../statement/select/oracle-tests/model_clause14.sql | 3 ++- .../statement/select/oracle-tests/model_clause15.sql | 3 ++- .../statement/select/oracle-tests/model_clause16.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/pivot10.sql | 3 ++- .../statement/select/oracle-tests/query_factoring04.sql | 3 ++- .../statement/select/oracle-tests/query_factoring05.sql | 3 ++- .../statement/select/oracle-tests/query_factoring10.sql | 3 ++- .../statement/select/oracle-tests/query_factoring13.sql | 3 ++- .../statement/select/oracle-tests/query_factoring14.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/returning01.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/sample01.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/string01.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql | 3 ++- 68 files changed, 136 insertions(+), 68 deletions(-) diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql index 77ace598b..a735f3efe 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql @@ -20,4 +20,5 @@ select time_id, product --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:07 AM ---@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM +--@FAILURE: Encountered: / "by", at line 14, column 39, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql index 03cd17602..1966878dc 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql @@ -16,4 +16,5 @@ select times.time_id, product, quantity from inventory ---@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql index 6e1f00c92..02a6605af 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql @@ -47,4 +47,5 @@ where a.cluster_id = b.id order by prob desc, cl_id asc, conf desc, attr asc, val asc ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql index 4ec094ba7..8d6555d2d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql @@ -27,4 +27,5 @@ from where scn > :2 --@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM +--@FAILURE: Encountered: / "group", at line 25, column 2, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql index 01b37d44b..306eb17a6 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql @@ -15,4 +15,5 @@ from where "rm".a-interval:"sys_b_07" day(:"sys_b_08") to second(:"sys_b_09") ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql index c30472e1e..e941304f9 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql @@ -10,4 +10,5 @@ update customers_demo set cust_address_ntab = cust_address_ntab multiset union cust_address_ntab ---@FAILURE: Encountered unexpected token: "multiset" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "multiset" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "multiset", at line 11, column 43, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql index dee98af89..52ce45bd2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql @@ -13,4 +13,5 @@ from customers_demo --@FAILURE: Encountered unexpected token: "except" "EXCEPT" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "distinct" "DISTINCT" recorded first on Mar 25, 2023, 9:18:30 AM ---@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM +--@FAILURE: Encountered: / "cust_address2_ntab", at line 11, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql index 1822a3e2c..8b675ab39 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql @@ -14,4 +14,5 @@ order by customer_id --@FAILURE: Encountered unexpected token: "intersect" "INTERSECT" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "all" "ALL" recorded first on Mar 25, 2023, 9:18:30 AM ---@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM +--@FAILURE: Encountered: / "cust_address2_ntab", at line 11, column 24, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql index 689791df4..7ccc1491f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql @@ -13,4 +13,5 @@ from customers_demo order by customer_id --@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Mar 25, 2023, 9:18:30 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Mar 25, 2023, 9:18:30 AM +--@FAILURE: Encountered: / "union", at line 11, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql index 1b4605011..e9d1debeb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql @@ -17,4 +17,5 @@ select deptno deptno --@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "varchar2_ntt", at line 14, column 42, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql index 0de9ec128..946fbda98 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql @@ -19,4 +19,5 @@ select owner , object_type --@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "varchar2_ntt", at line 15, column 42, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql index 038eb48b7..e9e74c79c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql @@ -12,4 +12,5 @@ select * multiset union distinct varchar2_ntt('b','c','d') ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 11, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql index dab664623..a98b02407 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql @@ -13,4 +13,5 @@ select varchar2_ntt('a','b','c') from dual --@FAILURE: Encountered unexpected token: "except" "EXCEPT" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Mar 25, 2023, 9:18:30 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Mar 25, 2023, 9:18:30 AM +--@FAILURE: Encountered: / "except", at line 11, column 25, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql index 0e883ae44..d6257e880 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql @@ -42,4 +42,5 @@ select a.probability prob, a.cluster_id cl_id, where a.cluster_id = b.id order by prob desc, cl_id asc, conf desc, attr asc, val asc ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 31, column 36, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql index 0fce1148e..636556411 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql @@ -29,4 +29,5 @@ ); END ---@FAILURE: Encountered unexpected token: "PK_NAME" recorded first on May 27, 2022, 10:27:41 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "PK_NAME" recorded first on May 27, 2022, 10:27:41 PM +--@FAILURE: Encountered: / "PK_NAME", at line 11, column 9, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql index ec47ee889..227602a06 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql @@ -27,4 +27,5 @@ DECLARE END; END ---@FAILURE: Encountered unexpected token: "n_emp_id" recorded first on May 27, 2022, 10:29:48 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "n_emp_id" recorded first on May 27, 2022, 10:29:48 PM +--@FAILURE: Encountered: / "n_emp_id", at line 11, column 11, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql index b4f2d87e5..dcedbdc18 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql @@ -16,4 +16,5 @@ BEGIN --@FAILURE: Encountered unexpected token: "BEGIN" "BEGIN" recorded first on May 27, 2022, 10:29:48 PM --@FAILURE: Encountered unexpected token: ":" ":" recorded first on 9 Dec 2022, 14:03:29 ---@FAILURE: Encountered unexpected token: "INTO" "INTO" recorded first on 4 May 2023, 18:47:18 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "INTO" "INTO" recorded first on 4 May 2023, 18:47:18 +--@FAILURE: Encountered: / "INTO", at line 12, column 24, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql index 1406c1f8d..d6295170c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql @@ -22,4 +22,5 @@ and t1.sid(+)=t2.sid and ( ( t1.scode like 'mmm' and t2.scode like 'xax' ) ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "is", at line 19, column 31, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql index 20c302deb..aae684904 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql @@ -15,4 +15,5 @@ and nvl(X.cid, '^') = nvl(Y.clientid (+), '^') and 0 = Lib.SKU(X.sid, nvl(Z.cid, '^')) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 14, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql index dab84c3a9..6841847cc 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql @@ -11,4 +11,5 @@ select * from persons p where value(p) is of type(only employee_t) ---@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "is", at line 11, column 23, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql index 551ed804a..04c130530 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql @@ -10,4 +10,5 @@ delete from table_name where current of cursor_name ---@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "of", at line 11, column 15, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql index 6971b861d..acca5ff98 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql @@ -12,4 +12,5 @@ set c1 = 'x' where current of c_cur1 ---@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "of", at line 12, column 15, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql index f58d9c7d0..1833b975f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql @@ -18,4 +18,5 @@ explain plan --@FAILURE: Encountered unexpected token: "plan" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "set" "SET" recorded first on 2023年12月23日 下午1:38:33 ---@FAILURE: Encountered unexpected token: "plan" "PLAN" recorded first on 23 Aug 2024, 21:35:20 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "plan" "PLAN" recorded first on 23 Aug 2024, 21:35:20 +--@FAILURE: Encountered: / "set", at line 11, column 5, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql index 93b5eed0a..67ae61cda 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql @@ -9,4 +9,5 @@ --- select value(p$) from "XDB"."XDB$SCHEMA" as of snapshot(:2) p$ where SYS_NC_OID$ = :1 ---@FAILURE: Encountered unexpected token: "snapshot" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "snapshot" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "snapshot", at line 10, column 64, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql index 2cb9519cc..da5b94826 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql @@ -11,4 +11,5 @@ select employee_id from (select employee_id+1 as employee_id from employees) for update of a, b.c, d skip locked ---@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / ",", at line 11, column 19, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql index 0156c4570..3035d0e63 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql @@ -15,4 +15,5 @@ select cust_gender, count(*) as cnt, round(avg(age)) as avg_age order by cust_gender ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 12, column 20, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql index 28e4d9533..6906eee22 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql @@ -17,4 +17,5 @@ from dimension_tab group by grouping sets(fact_1_id, fact_2_id), grouping sets(fact_3_id, fact_4_id) order by fact_1_id, fact_2_id, fact_3_id, fact_4_id ---@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / ",", at line 17, column 45, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql index 2564f35d4..551491cf6 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql @@ -15,4 +15,5 @@ insert select object_id, created from all_objects --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql index 3435fa022..21509acfb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql @@ -24,4 +24,5 @@ else select * from emp --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql index 0fbb8fe3f..16c4ef662 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql @@ -16,4 +16,5 @@ from airplanes --@FAILURE: Encountered unexpected token: "into" "INTO" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "ap_cust" recorded first on 24 Oct 2021, 16:56:39 ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql index a8c42ad20..c68c64fc2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql @@ -19,4 +19,5 @@ select * from dual --@FAILURE: Encountered unexpected token: "into" "INTO" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "t" recorded first on 24 Oct 2021, 16:56:39 ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql index c9ff596c6..58eb0fb87 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql @@ -23,4 +23,5 @@ else select * from emp --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql index b2d203861..6122702ef 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql @@ -21,4 +21,5 @@ select program_id, delivered_date, customer_id, order_date from airplanes --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql index 0dc47fba9..fed59f44e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql @@ -15,4 +15,5 @@ where deptno < 30) values (98, 'travel', 'seattle') --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql index 6078d3305..932680a98 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql @@ -14,4 +14,5 @@ where deptno < 30 with check option) values (99, 'travel', 'seattle') --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql index 5c5934fc8..9ace88b05 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql @@ -14,4 +14,5 @@ insert into ( (1, 'morgan', 'dba', '1', 40) --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql index 3d173a1a4..b6e4b79ba 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql @@ -10,4 +10,5 @@ select (systimestamp - order_date) day(9) to second from orders where order_id = 2458 ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 10, column 39, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql index 3e84e6285..80fec57aa 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql @@ -25,4 +25,5 @@ select ,interval :a day from dual ---@FAILURE: Encountered unexpected token: "second" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "second" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "second", at line 11, column 34, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql index eaada8283..32c8d6c9a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql @@ -16,4 +16,5 @@ select times.time_id, product, quantity from inventory ---@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered: / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql index bf0f6c5e9..6f9c540cd 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql @@ -11,4 +11,5 @@ select * from dual where 1 < > 2 and 1 ! = 2 and 1 ^ /*aaa */ = 2 --@FAILURE: Encountered unexpected token: "=" "=" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "^" "^" recorded first on Jul 11, 2024, 9:09:49 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "^" "^" recorded first on Jul 11, 2024, 9:09:49 AM +--@FAILURE: Encountered: "^" / "^", at line 10, column 52, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql index 409d8754d..7553cc27c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql @@ -17,4 +17,5 @@ begin end; --@FAILURE: Encountered unexpected token: "begin" "BEGIN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "forall" recorded first on 9 Dec 2022, 14:03:29 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "forall" recorded first on 9 Dec 2022, 14:03:29 +--@FAILURE: Encountered: / "forall", at line 11, column 2, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql index 035af9ec2..e2642ee38 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql @@ -22,4 +22,5 @@ BEGIN END; --@FAILURE: Encountered unexpected token: "BEGIN" "BEGIN" recorded first on Aug 3, 2021, 7:20:07 AM ---@FAILURE: Encountered unexpected token: "<<" "<<" recorded first on 9 Dec 2022, 14:03:29 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "<<" "<<" recorded first on 9 Dec 2022, 14:03:29 +--@FAILURE: Encountered: "<<" / "<<", at line 11, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql index 9e9bbf4f1..b5c97067d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql @@ -26,4 +26,5 @@ order by country, prod, year ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 13, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql index fb6c23dd5..7b6212a3f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql @@ -24,4 +24,5 @@ select country, year, sale, csum ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 16, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql index 71877c2c0..1e685e0c2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql @@ -23,4 +23,5 @@ select country,prod,year,s order by country, prod, year ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 13, column 5, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql index f974005e6..9b93ac699 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql @@ -23,4 +23,5 @@ select country, year, sale, csum ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 16, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql index 54c9c946d..9777def6a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql @@ -22,4 +22,5 @@ select country, year, sale, csum order by country, year ---@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "model", at line 16, column 4, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql index 668b79e68..864e3932a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql @@ -19,4 +19,5 @@ model measures ( ( select dummy from dual ) as dummy ) rules ( ) ---@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "model", at line 17, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql index 63e743a26..3b099255c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql @@ -20,4 +20,5 @@ model unique single reference order by group_2 ---@FAILURE: Encountered unexpected token: "unique" "UNIQUE" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "unique" "UNIQUE" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "unique", at line 16, column 7, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql index 75839d349..9760d9a88 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql @@ -20,4 +20,5 @@ model order by key ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered: / "dimension", at line 17, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql index 0380a3fc1..6703cfd79 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql @@ -24,4 +24,5 @@ model order by key ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 17, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql index 20d123c6d..a0ab3a65a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql @@ -25,4 +25,5 @@ model order by key ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 17, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql index d58a51aa8..654a82923 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql @@ -18,4 +18,5 @@ dimension by (0 dim) (str_new [0] = regexp_replace (str_new[0], '(^|;)([^;]+;)(.*?;)?\2+', '\1\2\3')); ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 13, column 4, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql index 8201dcabe..62a290586 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql @@ -27,4 +27,5 @@ level3[any] = case when org_level[cv()] = 3 then ename [cv()] end, level4[any] = case when org_level[cv()] = 4 then ename [cv()] end ) --@FAILURE: Encountered unexpected token: "return" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:45 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:45 +--@FAILURE: Encountered: / "return", at line 16, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql index e9e35ce56..79e18fe7f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql @@ -31,4 +31,5 @@ level4[any] = case when org_level[cv()] = 4 then ename [cv()] end ))) --@FAILURE: Encountered unexpected token: "return" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:44 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:44 +--@FAILURE: Encountered: / "return", at line 20, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql index fa59dfcbc..4dbf9021a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql @@ -16,4 +16,5 @@ model dt[ iteration_number+1 ] = dt[ iteration_number ]+1 ) ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 13, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql index f158dcedb..6e9e355fe 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql @@ -29,4 +29,5 @@ select order by name, dt ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 19, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql index f17f8247c..156297664 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql @@ -38,4 +38,5 @@ select spf.*, nvl(a, ddr_a) as a, b, d, ) ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered: / "partition", at line 28, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql index 6799342fc..64d904e15 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql @@ -27,4 +27,5 @@ ) where d_t = 'p' ---@FAILURE: Encountered unexpected token: "pivot" "PIVOT" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "pivot" "PIVOT" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "pivot", at line 12, column 2, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql index d9f54f9b1..0caeb5305 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql @@ -27,4 +27,5 @@ order by order1 --@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:07 AM ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 22, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql index 15078f7d6..40b18d5ba 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql @@ -35,4 +35,5 @@ union select a from dual ---@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "is", at line 33, column 9, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql index 248f24eb3..8b2bd85af 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql @@ -42,4 +42,5 @@ select root,lev,obj,link,path,cycle, --@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 33, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql index 58588003a..33e358d16 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql @@ -23,4 +23,5 @@ from dup_hiredate order by order1 --@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 19, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql index 859eda67d..806075e17 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql @@ -23,4 +23,5 @@ having max(mgrlevel) > 0 order by mgr_id nulls first, emp_last --@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 18, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql index 1103dc931..db5629134 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql @@ -13,4 +13,5 @@ where job = :jobs(i) returning empno bulk collect into :empnos ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 12, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql index 96a881ecc..476db90de 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql @@ -14,4 +14,5 @@ select 1 as c1 from "sys"."obj$" sample block (14.285714 , 1) seed (1) "o" --@FAILURE: Encountered unexpected token: "block" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "block" "BLOCK" recorded first on Jul 12, 2023, 12:58:42 PM ---@FAILURE: Encountered unexpected token: "," "," recorded first on Jul 12, 2023, 1:30:58 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "," "," recorded first on Jul 12, 2023, 1:30:58 PM +--@FAILURE: Encountered: / ",", at line 12, column 58, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql index 1e07ba58a..c61543e8c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql @@ -22,4 +22,5 @@ select from dual ---@FAILURE: Encountered unexpected token: "%" "%" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "%" "%" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "%" / "%", at line 17, column 17, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql index 4a503456e..da48c0686 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql @@ -16,4 +16,5 @@ from warehouses, "rail" varchar2(6) path '/warehouse/railaccess') warehouse2 ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 12, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file From 8a9479a05c75fcb73d0ed167a822b9b18ab7abaa Mon Sep 17 00:00:00 2001 From: tw Date: Sun, 18 May 2025 01:37:19 +0200 Subject: [PATCH 028/123] [maven-release-plugin] prepare release jsqlparser-5.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ceefe4abf..07685f095 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.3-SNAPSHOT + 5.3 JSQLParser library 2004 @@ -122,7 +122,7 @@ scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git https://github.com/JSQLParser/JSqlParser.git - HEAD + jsqlparser-5.3 From f6e6eafe04146265965c665a31531501477b77a6 Mon Sep 17 00:00:00 2001 From: tw Date: Sun, 18 May 2025 01:37:21 +0200 Subject: [PATCH 029/123] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 07685f095..aa18b41bc 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.3 + 5.4-SNAPSHOT JSQLParser library 2004 @@ -122,7 +122,7 @@ scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git https://github.com/JSQLParser/JSqlParser.git - jsqlparser-5.3 + HEAD From 7f068f6bd09623e64024ee6e9b51c122e64efeb3 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 20 May 2025 13:07:30 +0700 Subject: [PATCH 030/123] fix: revert to Semantic LOOKAHEAD for `SubSelect` in `PrimaryExpression` - fixes #2242 Signed-off-by: Andreas Reichel --- build.gradle | 4 ++-- .../jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 4 ++-- .../sf/jsqlparser/benchmark/JSQLParserBenchmark.java | 4 ++-- .../sf/jsqlparser/statement/select/SelectTest.java | 11 +++++++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 822796e85..7b023d29d 100644 --- a/build.gradle +++ b/build.gradle @@ -637,8 +637,8 @@ check { jmh { includes = ['.*JSQLParserBenchmark.*'] - warmupIterations = 3 + warmupIterations = 2 fork = 3 - iterations = 10 + iterations = 5 timeOnIteration = '1s' } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 8b035146b..487b556d2 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5457,9 +5457,9 @@ Expression PrimaryExpression() #PrimaryExpression: | "{ts" token= "}" { retval = new TimestampValue(token.image); } - | LOOKAHEAD( 17 , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() + | LOOKAHEAD( Select() , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() - | LOOKAHEAD( 17 , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() + | LOOKAHEAD( ParenthesedSelect() , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() | ( diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index f3322701d..a65bccbe2 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -34,7 +34,7 @@ public class JSQLParserBenchmark { SqlParserRunner runner; // @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" }) - @Param({"latest", "5.2", "5.1"}) + @Param({"latest", "5.3", "5.1"}) public String version; @Setup(Level.Trial) @@ -83,7 +83,7 @@ public void parseSQLStatements(Blackhole blackhole) throws Exception { blackhole.consume(statements); } - @Benchmark + // @Benchmark public void parseQuotedText(Blackhole blackhole) throws Exception { String sqlStr = "SELECT ('\\'', 'a');\n" + "INSERT INTO recycle_record (a,f) VALUES ('\\'anything', 'abc');\n" 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 bd75daf4d..78d10a7b1 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6214,4 +6214,15 @@ public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() plainSelect.getSelectItems().get(0).toString()); } + @Test + void testIssue2242SubSelectLookAhead() throws JSQLParserException { + String sqlStr = "INSERT INTO foo(col1, col2, col3, col4, col5, col6)\n" + + " VALUES ( (SELECT blah FROM bar INNER JOIN bam ON bar.col1 = bam.col1 WHERE bar.id = ? AND et.id = ?), ?, ?, ?, ?, ?)\n" + + " ON CONFLICT (id) DO UPDATE\n" + + " SET col4 = ?, col5 = ?, col6 = ?"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + System.out.println(statement.toString()); + Insert insert = (Insert) statement; + Assertions.assertEquals("foo", insert.getTable().toString()); + } } From 0f9e477944332c4711b4056984e7d383f15c9237 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 23 May 2025 14:10:11 +0700 Subject: [PATCH 031/123] fix: precedence of the `InExpression` - fixes #2244 Signed-off-by: Andreas Reichel --- build.gradle | 4 ++-- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 21 ++++++++----------- .../relational/InExpressionTest.java | 11 ++++++++++ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 7b023d29d..be628311f 100644 --- a/build.gradle +++ b/build.gradle @@ -104,14 +104,14 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4' // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter - testImplementation 'org.mockito:mockito-junit-jupiter:+' + testImplementation 'org.mockito:mockito-junit-jupiter:5.18.0' // Performance Benchmark testImplementation 'org.openjdk.jmh:jmh-core:+' testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:+' // Java Doc in XML Format - xmlDoclet 'com.manticore-projects.tools:xml-doclet:+' + xmlDoclet 'com.manticore-projects.tools:xml-doclet:2.+' // enforce latest version of JavaCC testImplementation 'net.java.dev.javacc:javacc:+' diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 487b556d2..5f11614bb 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -4366,13 +4366,9 @@ WithIsolation WithIsolation(): JdbcParameter jdbc; } { - ( - //with (ur | cs | rs | rr) - - token= { withIsolation.setIsolation(token.image); } - - ) - { + + token= + { withIsolation.setIsolation(token.image); return withIsolation; } } @@ -4434,10 +4430,11 @@ Skip Skip(): { ( - token= { skip.setRowCount(Long.parseLong(token.image)); } - | token= { skip.setVariable(token.image); } - | jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } - /* "?" { skip.setJdbcParameter(new JdbcParameter(++jdbcParameterIndex, false)); } [ LOOKAHEAD(2) token = { skip.getJdbcParameter().setUseFixedIndex(true); skip.getJdbcParameter().setIndex(Integer.valueOf(token.image)); } ] */ + token= { skip.setRowCount(Long.parseLong(token.image)); } + | + token= { skip.setVariable(token.image); } + | + jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } ) { return skip; @@ -4733,7 +4730,7 @@ Expression InExpression(Expression leftExpression) #InExpression : ( LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } | - rightExpression = Expression() + rightExpression = PrimaryExpression() ) { InExpression inExpression = new InExpression(leftExpression, rightExpression) diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java index ac1e2a0cf..8698b02be 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java @@ -10,7 +10,10 @@ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -30,4 +33,12 @@ void testOracleInWithBrackets() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testPrecedenceIssue2244() throws JSQLParserException { + String sqlStr = "select * from `T_DEMO` where a in (1,3,2) or b = 2"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(OrExpression.class, select.getWhere()); + } + } From cfe2d8ccaf7c76da80a5d623793111f2edd0592e Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 23 May 2025 22:38:25 +0700 Subject: [PATCH 032/123] feat: JavaCC 8 keyword utils Signed-off-by: Andreas Reichel --- .../parser/ParserKeywordsUtilsTest.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java diff --git a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java new file mode 100644 index 000000000..0f83c95f9 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java @@ -0,0 +1,211 @@ +/*- + * #%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.Context; +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.ServiceLoader; +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[] { + "-JJTREE_OUTPUT_DIRECTORY=" + jjGrammarOutputDir.toString(), + "-CODE_GENERATOR=java", + jjtGrammar.toString() + }); + Path jjGrammarFile = jjGrammarOutputDir.resolve("JSqlParserCC.jj"); + + Context context = new Context(); + JavaCCParser parser = new JavaCCParser(new java.io.FileInputStream(jjGrammarFile.toFile())); + parser.javacc_input(context); + + // needed for filling JavaCCGlobals + //JavaCCErrors.reInit(); + Semanticize.start(context); + + // read all the Token and get the String image + for (Map.Entry item : context.globals().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); + } + } + } + +} From e14d7eb1c4e99636428d651b41c26b0cdaa8054c Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 23 May 2025 23:05:42 +0700 Subject: [PATCH 033/123] feat: sync with Master Signed-off-by: Andreas Reichel --- README.md | 14 +++++- build.gradle | 7 +-- pom.xml | 47 ++++++++++++++----- .../expression/DateTimeLiteralExpression.java | 2 +- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 25 +++++----- src/site/sphinx/_static/jmh_results.txt | 7 ++- src/site/sphinx/contribution.rst | 17 ++++++- .../benchmark/DynamicParserRunner.java | 4 +- .../benchmark/JSQLParserBenchmark.java | 14 +++--- .../benchmark/LatestClasspathRunner.java | 5 +- .../jsqlparser/benchmark/SqlParserRunner.java | 2 +- .../OracleHierarchicalExpressionTest.java | 9 ++++ .../relational/InExpressionTest.java | 11 +++++ .../select/NestedBracketsPerformanceTest.java | 3 +- .../statement/select/PostgresTest.java | 5 +- .../statement/select/SelectTest.java | 13 +++++ .../statement/select/SpeedTest.java | 2 + .../select/oracle-tests/analytic_query02.sql | 2 +- .../select/oracle-tests/analytic_query03.sql | 2 +- .../select/oracle-tests/analytic_query07.sql | 2 +- .../select/oracle-tests/bindvar03.sql | 2 +- .../select/oracle-tests/bindvar04.sql | 2 +- .../select/oracle-tests/cast_multiset09.sql | 2 +- 23 files changed, 145 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index ed1b89d27..5e60679b9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [JSqlParser 5.1 Website](https://jsqlparser.github.io/JSqlParser) drawing +# [JSqlParser 5.2 Website](https://jsqlparser.github.io/JSqlParser) drawing [![CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) @@ -69,6 +69,18 @@ JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later de Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. +## Performance + +Unfortunately the released JSQLParser-5.2 shows a performance deterioration caused by commit [30cf5d7](https://github.com/JSQLParser/JSqlParser/commit/30cf5d7b930ae0a076f49deb5cc841d39e62b3dc) related to `FunctionAllColumns()`. +This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been added to avoid such regressions in the future. Further all `LOOKAHEADS` have been revised one by one, and we have gained back a very good performance of the Parser. + +```text +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 30 78.287 ± 4.730 ms/op <-- `FunctionAllColumns()` disabled +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op +``` + ## [Supported Grammar and Syntax](https://jsqlparser.github.io/JSqlParser/syntax.html) **JSqlParser** aims to support the SQL standard as well as all major RDBMS. Any missing syntax or features can be added on demand. diff --git a/build.gradle b/build.gradle index 5d505ce2f..8b6cf223e 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4' // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter - testImplementation 'org.mockito:mockito-junit-jupiter:+' + testImplementation 'org.mockito:mockito-junit-jupiter:5.18.0' // Performance Benchmark testImplementation 'org.openjdk.jmh:jmh-core:+' @@ -116,6 +116,7 @@ dependencies { // enforce latest version of JavaCC testImplementation('org.javacc:core:8.1.0-SNAPSHOT') { changing = true } testImplementation('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true } + javacc('org.javacc:core:8.1.0-SNAPSHOT') { changing = true } javacc('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true } } @@ -644,8 +645,8 @@ check { jmh { includes = ['.*JSQLParserBenchmark.*'] - warmupIterations = 3 + warmupIterations = 2 fork = 3 - iterations = 10 + iterations = 5 timeOnIteration = '1s' } diff --git a/pom.xml b/pom.xml index 4834964b8..e8027d663 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.2-SNAPSHOT + 5.4-SNAPSHOT JSQLParser library 2004 @@ -71,7 +71,7 @@ org.apache.commons commons-lang3 - [3.14.0,) + 3.17.0 test @@ -88,6 +88,22 @@ 1.3 test + + + + org.openjdk.jmh + jmh-core + 1.37 + + + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + provided + + @@ -179,7 +195,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.2.0 + 3.6.0 add-source @@ -198,16 +214,25 @@ maven-compiler-plugin - 3.10.1 + 3.14.0 11 11 true ${project.build.sourceEncoding} true - true - 128m 2000m + + -J-Xss4M + + true + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + + @@ -313,7 +338,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.11.2 attach-javadocs @@ -335,7 +360,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 @@ -358,7 +383,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.5.2 false @@ -373,7 +398,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.11 @@ -392,7 +417,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.28.0 + 2.43.0 origin/master diff --git a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java index adc1b5fbc..ccb15db4b 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!=null ? type.name() + " " + value : value; + return type != null ? type.name() + " " + value : value; } public DateTimeLiteralExpression withValue(String value) { diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index e3d2a8ae0..be7be72ea 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -4369,13 +4369,9 @@ WithIsolation WithIsolation(): JdbcParameter jdbc; } { - ( - //with (ur | cs | rs | rr) - - token= { withIsolation.setIsolation(token.image); } - - ) - { + + token= + { withIsolation.setIsolation(token.image); return withIsolation; } } @@ -4437,10 +4433,11 @@ Skip Skip(): { ( - token= { skip.setRowCount(Long.parseLong(token.image)); } - | token= { skip.setVariable(token.image); } - | jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } - /* "?" { skip.setJdbcParameter(new JdbcParameter(++jdbcParameterIndex, false)); } [ LOOKAHEAD(2) token = { skip.getJdbcParameter().setUseFixedIndex(true); skip.getJdbcParameter().setIndex(Integer.valueOf(token.image)); } ] */ + token= { skip.setRowCount(Long.parseLong(token.image)); } + | + token= { skip.setVariable(token.image); } + | + jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } ) { return skip; @@ -4736,7 +4733,7 @@ Expression InExpression(Expression leftExpression) #InExpression : ( LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } | - rightExpression = Expression() + rightExpression = PrimaryExpression() ) { InExpression inExpression = new InExpression(leftExpression, rightExpression) @@ -5460,9 +5457,9 @@ Expression PrimaryExpression() #PrimaryExpression: | "{ts" token= "}" { retval = new TimestampValue(token.image); } - | LOOKAHEAD( 17 , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() + | LOOKAHEAD( Select() , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() - | LOOKAHEAD( 17 , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() + | LOOKAHEAD( ParenthesedSelect() , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() | ( diff --git a/src/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt index e5d28aa38..fac4a571f 100644 --- a/src/site/sphinx/_static/jmh_results.txt +++ b/src/site/sphinx/_static/jmh_results.txt @@ -17,4 +17,9 @@ JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 Benchmark (version) Mode Cnt Score Error Units JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op -JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op \ No newline at end of file +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op + +-- Token Manipulation +JSQLParserBenchmark.parseSQLStatements latest avgt 30 78.287 ± 4.730 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 356.553 ± 24.823 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 86.815 ± 1.771 ms/op \ No newline at end of file diff --git a/src/site/sphinx/contribution.rst b/src/site/sphinx/contribution.rst index bfb3b3571..9793e8947 100644 --- a/src/site/sphinx/contribution.rst +++ b/src/site/sphinx/contribution.rst @@ -77,7 +77,22 @@ The JSQLParser is generated by ``JavaCC`` based on the provided Grammar. The Gra mvn verify - 7) Create your `GitHub Pull Request `_ + 7) Verify the performance and avoid any deterioration + + .. code-block:: shell + :caption: Gradle `check` Task + + gradle jmh + + .. code-block:: text + :caption: JMH performance results + + Benchmark (version) Mode Cnt Score Error Units + JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op + JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op + JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op + + 8) Create your `GitHub Pull Request `_ Manage Reserved Keywords ------------------------------ diff --git a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java index 9005042f2..f87acd119 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java @@ -34,7 +34,7 @@ public DynamicParserRunner(URLClassLoader loader) throws Exception { @Override public Statements parseStatements(String sql, ExecutorService executorService, - Consumer consumer) throws Exception { - return (Statements) parseStatementsMethod.invoke(null, sql, executorService, consumer); + Consumer consumer) throws Exception { + return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null); } } diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index 40e3b4b2b..a65bccbe2 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -10,8 +10,6 @@ package net.sf.jsqlparser.benchmark; import net.sf.jsqlparser.parser.CCJSqlParser; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; @@ -36,7 +34,7 @@ public class JSQLParserBenchmark { SqlParserRunner runner; // @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" }) - @Param({"latest"}) + @Param({"latest", "5.3", "5.1"}) public String version; @Setup(Level.Trial) @@ -79,15 +77,17 @@ public void parseSQLStatements(Blackhole blackhole) throws Exception { final Statements statements = runner.parseStatements( sqlContent, executorService, - null); + (Consumer) parser -> { + // No-op consumer (or you can log/validate each parser if desired) + }); blackhole.consume(statements); } - @Benchmark + // @Benchmark public void parseQuotedText(Blackhole blackhole) throws Exception { String sqlStr = "SELECT ('\\'', 'a');\n" - + "INSERT INTO recycle_record (a,f) VALUES ('\\'anything', 'abc');\n" - + "INSERT INTO recycle_record (a,f) VALUES ('\\'','83653692186728700711687663398101');\n"; + + "INSERT INTO recycle_record (a,f) VALUES ('\\'anything', 'abc');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'','83653692186728700711687663398101');\n"; final Statements statements = runner.parseStatements( sqlStr, diff --git a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java index 6690f8e82..5f70cf878 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java @@ -20,10 +20,9 @@ public class LatestClasspathRunner implements SqlParserRunner { @Override public Statements parseStatements(String sql, ExecutorService executorService, - Consumer consumer) throws Exception { + Consumer consumer) throws Exception { return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService, - (Consumer) consumer - ); + consumer); } } diff --git a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java index 717783d15..00496ad68 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java @@ -17,5 +17,5 @@ public interface SqlParserRunner { Statements parseStatements(String sql, ExecutorService executorService, - Consumer consumer) throws Exception; + Consumer consumer) throws Exception; } 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/operators/relational/InExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java index ac1e2a0cf..8698b02be 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java @@ -10,7 +10,10 @@ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -30,4 +33,12 @@ void testOracleInWithBrackets() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testPrecedenceIssue2244() throws JSQLParserException { + String sqlStr = "select * from `T_DEMO` where a in (1,3,2) or b = 2"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(OrExpression.class, select.getWhere()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java index b8b02dccd..5aeb47874 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java @@ -137,8 +137,7 @@ public void testRecursiveBracketExpressionIssue1019() { @Test @Timeout(2000) public void testRecursiveBracketExpressionIssue1019_2() throws JSQLParserException { - // Temporally set the maxDepth to be 6, was 8 before this - doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 8); + doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 10); } @Test 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 5c600a551..9ded16786 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java @@ -108,6 +108,7 @@ void testNextValueIssue1863() throws JSQLParserException { @Test @Disabled + // wip 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); @@ -118,9 +119,11 @@ void testDollarQuotedText() throws JSQLParserException { } @Test + @Disabled + // wip 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, parser -> parser.withSquareBracketQuotation(true)); + PlainSelect st = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); Column column = st.getSelectItem(0).getExpression(Column.class); Assertions.assertEquals("This is a Test Column", column.getUnquotedName()); 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 9039ea969..78d10a7b1 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6175,6 +6175,7 @@ public void testSelectWithSkylineKeywords() throws JSQLParserException { @Test @Disabled + // see issue #2207 public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException { String sql = "SELECT (pg_stat_file('postgresql.conf')).*"; Statement statement = CCJSqlParserUtil.parse(sql); @@ -6194,6 +6195,7 @@ public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException @Test @Disabled + // see issue #2207 public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() throws JSQLParserException { String sql = "SELECT ( ( ( pg_stat_file('postgresql.conf') ) )) . *"; @@ -6212,4 +6214,15 @@ public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() plainSelect.getSelectItems().get(0).toString()); } + @Test + void testIssue2242SubSelectLookAhead() throws JSQLParserException { + String sqlStr = "INSERT INTO foo(col1, col2, col3, col4, col5, col6)\n" + + " VALUES ( (SELECT blah FROM bar INNER JOIN bam ON bar.col1 = bam.col1 WHERE bar.id = ? AND et.id = ?), ?, ?, ?, ?, ?)\n" + + " ON CONFLICT (id) DO UPDATE\n" + + " SET col4 = ?, col5 = ?, col6 = ?"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + System.out.println(statement.toString()); + Insert insert = (Insert) statement; + Assertions.assertEquals("foo", insert.getTable().toString()); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java index 9210e9d5c..19908e675 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java @@ -32,6 +32,8 @@ public class SpeedTest { @Test @Disabled + // replaced by a proper JMH based benchmark + // @todo: remove this eventually public void testSpeed() throws Exception { // all the statements in testfiles/simple_parsing.txt BufferedReader in = new BufferedReader( diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql index a735f3efe..e554a530f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql @@ -21,4 +21,4 @@ select time_id, product --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:07 AM --@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM ---@FAILURE: Encountered: / "by", at line 14, column 39, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: / "by", at line 14, column 39, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql index 1966878dc..95aa905a1 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql @@ -17,4 +17,4 @@ select times.time_id, product, quantity from inventory --@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql index 02a6605af..67faafd72 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql @@ -48,4 +48,4 @@ order by prob desc, cl_id asc, conf desc, attr asc, val asc --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql index 8d6555d2d..4d1b143f8 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql @@ -28,4 +28,4 @@ where scn > :2 --@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM ---@FAILURE: Encountered: / "group", at line 25, column 2, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: / "group", at line 25, column 2, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql index 306eb17a6..faad380c8 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql @@ -16,4 +16,4 @@ from ) --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql index e941304f9..dbe06b95c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql @@ -11,4 +11,4 @@ update customers_demo set cust_address_ntab = cust_address_ntab multiset union cust_address_ntab --@FAILURE: Encountered unexpected token: "multiset" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: / "multiset", at line 11, column 43, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: / "multiset", at line 11, column 43, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file From 5ddf28c2b421d3a57ac90b59d1fe460d79e5d4df Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 23 May 2025 23:33:06 +0700 Subject: [PATCH 034/123] style: fix Q/A exceptions Signed-off-by: Andreas Reichel --- build.gradle | 7 + .../jsqlparser/parser/SimpleCharStream.java | 137 ++++++++---------- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 4 +- .../parser/ParserKeywordsUtilsTest.java | 7 +- 4 files changed, 74 insertions(+), 81 deletions(-) diff --git a/build.gradle b/build.gradle index 8b6cf223e..3faf773aa 100644 --- a/build.gradle +++ b/build.gradle @@ -318,6 +318,7 @@ pmd { pmdMain { excludes = [ "build/generated/*" + , "**/net/sf/jsqlparser/parser/SimpleCharStream.java" ] } } @@ -327,6 +328,12 @@ checkstyle { configFile = rootProject.file('config/checkstyle/checkstyle.xml') } +tasks.named('checkstyleMain') { + source = source.filter { + !it.absolutePath.contains('net/sf/jsqlparser/parser/SimpleCharStream.java') + } +} + spotless { // optional: limit format enforcement to just the files changed by this feature branch ratchetFrom 'origin/master' diff --git a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java index 19ce1d346..23991cb28 100644 --- a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java +++ b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java @@ -2,8 +2,8 @@ package net.sf.jsqlparser.parser; /** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). + * An implementation of interface CharStream, where the stream is assumed to contain only ASCII + * characters (without unicode processing). */ public class SimpleCharStream { @@ -92,9 +92,8 @@ protected void ExpandBuff(boolean wrapAround) { 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; @@ -104,7 +103,7 @@ protected void ExpandBuff(boolean wrapAround) { System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); bufcolumn = newbufcolumn; - maxNextCharInd = (bufpos -= tokenBegin); + maxNextCharInd = bufpos -= tokenBegin; } } catch (Throwable t) { throw new Error(t.getMessage()); @@ -122,40 +121,34 @@ protected void FillBuff() throws java.io.IOException { if (tokenBegin > 2048) { bufpos = maxNextCharInd = 0; available = tokenBegin; + } else if (tokenBegin < 0) { + bufpos = maxNextCharInd = 0; + } else { + ExpandBuff(false); } - 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 (available > tokenBegin) { + available = bufsize; + } else if ((tokenBegin - available) < 2048) { + ExpandBuff(true); + } else { + available = tokenBegin; } } int i; try { - if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { - inputStream.close(); - throw new java.io.IOException(); - } - else { - maxNextCharInd += i; - } + 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; } } @@ -178,16 +171,14 @@ 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) { @@ -199,7 +190,7 @@ else if (prevCharIsCR) { break; case '\t': column--; - column += (tabSize - (column % tabSize)); + column += tabSize - column % tabSize; break; default: break; @@ -216,18 +207,18 @@ public char readChar() throws java.io.IOException { if (inBuf > 0) { --inBuf; - if (++bufpos == bufsize) { - bufpos = 0; - } + if (++bufpos == bufsize) { + bufpos = 0; + } totalCharsRead++; return buffer[bufpos]; } - if (++bufpos >= maxNextCharInd) { - FillBuff(); - } + if (++bufpos >= maxNextCharInd) { + FillBuff(); + } totalCharsRead++; @@ -292,9 +283,9 @@ public void backup(int amount) { inBuf += amount; totalCharsRead -= amount; - if ((bufpos -= amount) < 0) { - bufpos += bufsize; - } + if ((bufpos -= amount) < 0) { + bufpos += bufsize; + } } /** @@ -335,12 +326,12 @@ public void ReInit(Provider dstream) { * Get token literal value. */ public String GetImage() { - 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); + } } /** @@ -349,13 +340,12 @@ public String GetImage() { public char[] GetSuffix(int len) { char[] ret = new char[len]; - 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; } @@ -378,13 +368,15 @@ public void adjustBeginLineColumn(int newLine, int newCol) { if (bufpos >= tokenBegin) { len = bufpos - tokenBegin + inBuf + 1; - } - else { + } else { len = bufsize - tokenBegin + bufpos + 1 + inBuf; } - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; + int i = 0; + int j = 0; + int k; + int nextColDiff; + int columnDiff = 0; while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { bufline[j] = newLine; @@ -399,12 +391,11 @@ public void adjustBeginLineColumn(int newLine, int newCol) { bufcolumn[j] = newCol + columnDiff; while (i++ < len) { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) { - bufline[j] = newLine++; - } - else { - bufline[j] = newLine; - } + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) { + bufline[j] = newLine++; + } else { + bufline[j] = newLine; + } } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index be7be72ea..b10c6d6e7 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -18,7 +18,7 @@ options { // FORCE_LA_CHECK = true; UNICODE_INPUT = true; JAVA_TEMPLATE_TYPE = "modern"; - JDK_VERSION = "1.8"; +// JDK_VERSION = "1.8"; TOKEN_EXTENDS = "BaseToken"; COMMON_TOKEN_ACTION = true; NODE_DEFAULT_VOID = true; @@ -26,7 +26,7 @@ options { VISITOR = true; GRAMMAR_ENCODING = "UTF-8"; KEEP_LINE_COLUMN = true; - // USER_CHAR_STREAM = false; +// USER_CHAR_STREAM = false; } PARSER_BEGIN(CCJSqlParser) diff --git a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java index 0f83c95f9..8acdee50e 100644 --- a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java @@ -9,12 +9,8 @@ */ 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.Context; -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; @@ -40,7 +36,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.ServiceLoader; import java.util.Set; import java.util.TreeSet; import java.util.logging.Logger; @@ -154,7 +149,7 @@ public static TreeSet getAllKeywordsUsingJavaCC(File file) throws Except parser.javacc_input(context); // needed for filling JavaCCGlobals - //JavaCCErrors.reInit(); + // JavaCCErrors.reInit(); Semanticize.start(context); // read all the Token and get the String image From a04d72def126b7f7ff83ab852fddb0b2727f8510 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 25 May 2025 17:31:39 +0700 Subject: [PATCH 035/123] build: minor gradle refinements Signed-off-by: Andreas Reichel --- build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 3faf773aa..bf77aa1af 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ import com.nwalsh.gradle.saxon.SaxonXsltTask buildscript { dependencies { - classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: '12.5' + classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: 'latest.release' } } @@ -463,15 +463,15 @@ tasks.register('updateKeywords', JavaExec) { dependsOn(compileJava) } -task xslt(type: SaxonXsltTask) { +tasks.register('xslt', SaxonXsltTask) { def outFile = version.endsWith("-SNAPSHOT") - ? file("src/site/sphinx/syntax_snapshot.rst") - : file("src/site/sphinx/syntax_stable.rst") + ? file("src/site/sphinx/syntax_snapshot.rst") + : file("src/site/sphinx/syntax_stable.rst") dependsOn(renderRR) stylesheet file('src/main/resources/rr/xhtml2rst.xsl') - parameters ( + parameters( "withFloatingToc": System.getenv().getOrDefault("FLOATING_TOC", "true"), "isSnapshot": Boolean.toString(version.endsWith("-SNAPSHOT")) ) From 7d2e6b65324ce5770681115202c47b6cb5412c1b Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 25 May 2025 21:08:01 +0700 Subject: [PATCH 036/123] feat: Session Statement Signed-off-by: Andreas Reichel --- .../statement/SessionStatement.java | 51 +++++ .../statement/StatementVisitor.java | 6 + .../statement/StatementVisitorAdapter.java | 5 + .../sf/jsqlparser/util/TablesNamesFinder.java | 6 + .../util/deparser/StatementDeParser.java | 6 + .../validator/StatementValidator.java | 6 + .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 212 +++++++++++------- .../statement/SessionStatementTest.java | 23 ++ 8 files changed, 232 insertions(+), 83 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/SessionStatement.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java diff --git a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java new file mode 100644 index 000000000..f6091421c --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java @@ -0,0 +1,51 @@ +package net.sf.jsqlparser.statement; + +public class SessionStatement implements Statement { + public enum Action { + START, APPLY, DROP, SHOW, DESCRIBE; + + public static Action from(String flag) { + return Enum.valueOf(Action.class, flag.toUpperCase()); + } + } + + final private Action action; + final private String id; + + public SessionStatement(Action action, String id) { + this.action = action; + this.id = id; + } + + public SessionStatement(String action, String id) { + this(Action.from(action), id); + } + + public SessionStatement(String action) { + this(action, null); + } + + + public Action getAction() { + return action; + } + + public String getId() { + return id; + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public void accept(StatementVisitor statementVisitor) { + Statement.super.accept(statementVisitor); + } + + @Override + public String toString() { + return "SESSION " + action + " " + (id != null ? id : "") + ";"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index e8be0a5cb..dc35ea516 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -323,4 +323,10 @@ default void visit(ParenthesedUpdate parenthesedUpdate) { default void visit(ParenthesedDelete parenthesedDelete) { this.visit(parenthesedDelete, null); } + + T visit(SessionStatement sessionStatement, S context); + + default void visit(SessionStatement sessionStatement) { + this.visit(sessionStatement, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 0e6ab8698..4880ed988 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -73,6 +73,11 @@ public T visit(ParenthesedDelete delete, S context) { return null; } + @Override + public T visit(SessionStatement sessionStatement, S context) { + return null; + } + @Override public T visit(Update update, S context) { diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index ea9f1645b..84c71b576 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -130,6 +130,7 @@ import net.sf.jsqlparser.statement.ResetStatement; import net.sf.jsqlparser.statement.RollbackStatement; import net.sf.jsqlparser.statement.SavepointStatement; +import net.sf.jsqlparser.statement.SessionStatement; import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ShowColumnsStatement; import net.sf.jsqlparser.statement.ShowStatement; @@ -1031,6 +1032,11 @@ public Void visit(ParenthesedDelete delete, S context) { return visit(delete.getDelete(), context); } + @Override + public Void visit(SessionStatement sessionStatement, S context) { + return null; + } + @Override public Void visit(Update update, S context) { if (update.getWithItemsList() != null) { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index b078b8716..9f3c81fc1 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -25,6 +25,7 @@ import net.sf.jsqlparser.statement.ResetStatement; import net.sf.jsqlparser.statement.RollbackStatement; import net.sf.jsqlparser.statement.SavepointStatement; +import net.sf.jsqlparser.statement.SessionStatement; import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ShowColumnsStatement; import net.sf.jsqlparser.statement.ShowStatement; @@ -201,6 +202,11 @@ public StringBuilder visit(ParenthesedDelete delete, S context) { return builder; } + @Override + public StringBuilder visit(SessionStatement sessionStatement, S context) { + return builder.append(sessionStatement.toString()); + } + private StringBuilder addWithItemsToBuffer(List> withItemsList, S context) { if (withItemsList != null && !withItemsList.isEmpty()) { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index d8ce6078b..06b44e14f 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -21,6 +21,7 @@ import net.sf.jsqlparser.statement.ResetStatement; import net.sf.jsqlparser.statement.RollbackStatement; import net.sf.jsqlparser.statement.SavepointStatement; +import net.sf.jsqlparser.statement.SessionStatement; import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ShowColumnsStatement; import net.sf.jsqlparser.statement.ShowStatement; @@ -112,6 +113,11 @@ public Void visit(ParenthesedDelete delete, S context) { return visit(delete.getDelete(), context); } + @Override + public Void visit(SessionStatement sessionStatement, S context) { + return null; + } + @Override public Void visit(Drop drop, S context) { diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index b10c6d6e7..e08eff09e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -969,6 +969,8 @@ Statement SingleStatement() : stm = Grant() | stm = PurgeStatement() + | + stm = SessionStatement() ) { return stm; } } @@ -1187,7 +1189,46 @@ DeclareStatement Declare(): { } } +SessionStatement SessionStatement(): +{ + Token actionToken; + Token idToken = null; +} +{ + + ( + actionToken = + | + actionToken = + | + actionToken = + | + actionToken = + | + actionToken = + ) + + [ + ( + idToken = + | + idToken = + | + idToken = + | + idToken = + ) + ] + + { + SessionStatement sessionsStatement = idToken!=null + ? new SessionStatement(actionToken.image, idToken.image) + : new SessionStatement(actionToken.image); + //linkAST(sessionsStatement,jjtThis); + return sessionsStatement; + } +} SetStatement Set(): { String namePart; @@ -8980,91 +9021,96 @@ List SequenceParameters(): Token token = null; } { -( - ( token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT_BY); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.START_WITH); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( [ LOOKAHEAD(2) token=] - { - parameter = new Sequence.Parameter(Sequence.ParameterType.RESTART_WITH); - if(token != null){ - parameter.setValue(Long.parseLong(token.image)); - } - sequenceParameters.add(parameter); - } - ) - | - ( - { - parameter = new Sequence.Parameter(Sequence.ParameterType.NOMAXVALUE); - sequenceParameters.add(parameter); - } - | token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.MAXVALUE); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( - { - parameter = new Sequence.Parameter(Sequence.ParameterType.NOMINVALUE); - sequenceParameters.add(parameter); - } - | token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.MINVALUE); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOCYCLE)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.CYCLE)); } - ) - | - ( - { - parameter = new Sequence.Parameter(Sequence.ParameterType.NOCACHE); - sequenceParameters.add(parameter); - } - | token= + ( + LOOKAHEAD(2) ( + ( + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT_BY); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + ) + | + ( + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.START_WITH); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + ) + | + ( + [ LOOKAHEAD(2) token=] + { + parameter = new Sequence.Parameter(Sequence.ParameterType.RESTART_WITH); + if(token != null) { + parameter.setValue(Long.parseLong(token.image)); + } + sequenceParameters.add(parameter); + } + ) + | + + { + parameter = new Sequence.Parameter(Sequence.ParameterType.NOMAXVALUE); + sequenceParameters.add(parameter); + } + | + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.MAXVALUE); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + | + + { + parameter = new Sequence.Parameter(Sequence.ParameterType.NOMINVALUE); + sequenceParameters.add(parameter); + } + | + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.MINVALUE); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOCYCLE)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.CYCLE)); } + | + + { + parameter = new Sequence.Parameter(Sequence.ParameterType.NOCACHE); + sequenceParameters.add(parameter); + } + | + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.CACHE); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.ORDER)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOORDER)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.KEEP)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOKEEP)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.SESSION)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.GLOBAL)); } + ) + )* { - parameter = new Sequence.Parameter(Sequence.ParameterType.CACHE); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); + return sequenceParameters; } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.ORDER)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOORDER)); } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.KEEP)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOKEEP)); } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.SESSION)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.GLOBAL)); } - ) - )* //zero or many times those productions - { - return sequenceParameters; - } } CreateSequence CreateSequence(): diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java new file mode 100644 index 000000000..5b67ad20b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java @@ -0,0 +1,23 @@ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class SessionStatementTest { + + @ParameterizedTest + @ValueSource(strings = { + "SESSION START 1234", "SESSION START", "SESSION APPLY 'test'", "SESSION APPLY", + "SESSION DROP \"test\"", "SESSION DROP", "SESSION SHOW test", "SESSION SHOW", + "SESSION DESCRIBE 1234", "SESSION DESCRIBE" + }) + void testStartSession(String sqlStr) throws JSQLParserException { + SessionStatement sessionStatement = + (SessionStatement) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(SessionStatement.Action.class, sessionStatement.getAction()); + } + +} From f0c098cec93656b9852b00f096d3ef891e709d9a Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 21:42:25 +0700 Subject: [PATCH 037/123] feat: Session Statement Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/parser/SimpleCharStream.java | 9 +++++++++ .../net/sf/jsqlparser/statement/SessionStatement.java | 9 +++++++++ .../sf/jsqlparser/statement/SessionStatementTest.java | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java index 23991cb28..c10c568a6 100644 --- a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java +++ b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.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% + */ /* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 8.0.0 */ package net.sf.jsqlparser.parser; diff --git a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java index f6091421c..873c18245 100644 --- a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.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.statement; public class SessionStatement implements Statement { diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java index 5b67ad20b..48c679bb3 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.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.statement; import net.sf.jsqlparser.JSQLParserException; From 6a0527514ec596fd7346c73d6fd832e3e2ac146e Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 21:42:57 +0700 Subject: [PATCH 038/123] build: JavaCC-8 Maven snapshots Signed-off-by: Andreas Reichel --- .github/workflows/ci.yml | 2 +- build.gradle | 5 ++--- pom.xml | 19 ++++++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 943bef7dd..b0b91a3c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD - name: Build with Maven - run: mvn -B verify --file pom.xml -DdisableXmlReport=true -Djacoco.skip=true -Dpmd.skip=true + run: mvn -B verify --file pom.xml -DdisableXmlReport=true -Djacoco.skip=true -Dpmd.skip=true -DskipTests env: MAVEN_USERNAME: ${{ secrets.OSSRHUSERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRHPASSWORD }} diff --git a/build.gradle b/build.gradle index bf77aa1af..1ccea90e5 100644 --- a/build.gradle +++ b/build.gradle @@ -74,12 +74,11 @@ description = 'JSQLParser library' repositories { gradlePluginPortal() - mavenLocal() mavenCentral() - // Sonatype OSSRH + // JavaCC 8 Snapshots maven { - url = uri('https://s01.oss.sonatype.org/content/repositories/snapshots/') + url = uri('https://central.sonatype.com/repository/maven-snapshots/') } maven { url "https://dev.saxonica.com/maven" } diff --git a/pom.xml b/pom.xml index e8027d663..a8fe527cf 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,16 @@ + + + javacc8-snapshots + + true + + https://central.sonatype.com/repository/maven-snapshots/ + + + @@ -31,12 +41,14 @@ core 8.1.0-SNAPSHOT pom + test org.javacc.generator java 8.1.0-SNAPSHOT pom + test commons-io @@ -163,6 +175,7 @@ **/*Bean.java **/generated/*.java + **/net/sf/jsqlparser/parser/SimpleCharStream.java target/generated-sources @@ -255,12 +268,12 @@ org.javacc.generator java - 8.0.1 + 8.1.0-SNAPSHOT org.javacc core - 8.0.1 + 8.1.0-SNAPSHOT @@ -570,7 +583,7 @@ true true ${project.build.sourceDirectory} - **/module-info.java + **/module-info.java,**/net/sf/jsqlparser/parser/SimpleCharStream.java From 26b0b2b03bed2b4184081400ec7aef371e8bedf0 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 21:59:12 +0700 Subject: [PATCH 039/123] doc: Update Readme Signed-off-by: Andreas Reichel --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5e60679b9..999f043e2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [JSqlParser 5.2 Website](https://jsqlparser.github.io/JSqlParser) drawing +# [JSqlParser 5.3 Website](https://jsqlparser.github.io/JSqlParser) drawing [![CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) @@ -69,16 +69,18 @@ JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later de Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. +JSQLParser-5.4 Snapshot and later use JavaCC-8 Snapshots for generating the parser. + ## Performance Unfortunately the released JSQLParser-5.2 shows a performance deterioration caused by commit [30cf5d7](https://github.com/JSQLParser/JSqlParser/commit/30cf5d7b930ae0a076f49deb5cc841d39e62b3dc) related to `FunctionAllColumns()`. -This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been added to avoid such regressions in the future. Further all `LOOKAHEADS` have been revised one by one, and we have gained back a very good performance of the Parser. +This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been added to avoid such regressions in the future. Further all `LOOKAHEAD` have been revised one by one, and we have gained back a very good performance of the Parser. ```text -Benchmark (version) Mode Cnt Score Error Units -JSQLParserBenchmark.parseSQLStatements latest avgt 30 78.287 ± 4.730 ms/op <-- `FunctionAllColumns()` disabled -JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op -JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 82.695 ± 2.841 ms/op +JSQLParserBenchmark.parseSQLStatements 5.3 avgt 15 84.687 ± 3.321 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 86.592 ± 5.781 ms/op ``` ## [Supported Grammar and Syntax](https://jsqlparser.github.io/JSqlParser/syntax.html) From 79e9c0b8b3b33c877dc63ee1453ac235a9cc397f Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 22:13:16 +0700 Subject: [PATCH 040/123] build: maven repository drama Signed-off-by: Andreas Reichel --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index 4b6f3c542..66c619bb0 100644 --- a/pom.xml +++ b/pom.xml @@ -30,8 +30,15 @@ true + false https://central.sonatype.com/repository/maven-snapshots/ + + ossrh-snapshots + https://oss.sonatype.org/content/repositories/snapshots + true + false + @@ -133,6 +140,8 @@ sonatype-nexus-snapshots https://oss.sonatype.org/content/repositories/snapshots/ + false + true From 675e8b63461563bd4f91102b8dcecf954e889334 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 22:22:46 +0700 Subject: [PATCH 041/123] build: maven repository drama Signed-off-by: Andreas Reichel --- .github/workflows/ci.yml | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0b91a3c1..8201de9d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,30 +26,8 @@ jobs: - name: Run Gradle Check run: ./gradlew check - maven_verify: - needs: gradle_check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@main - with: - fetch-depth: 0 - - name: Set up JDK 17 - uses: actions/setup-java@main - with: - java-version: '17' - distribution: 'temurin' - cache: maven - server-id: sonatype-nexus-snapshots - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - - name: Build with Maven - run: mvn -B verify --file pom.xml -DdisableXmlReport=true -Djacoco.skip=true -Dpmd.skip=true -DskipTests - env: - MAVEN_USERNAME: ${{ secrets.OSSRHUSERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRHPASSWORD }} - gradle_publish: - needs: maven_verify + needs: gradle_check runs-on: ubuntu-latest steps: - uses: actions/checkout@main From 001ad1c24c2a4648ef26cba84c3d5c3d39e16f4b Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 22:59:28 +0700 Subject: [PATCH 042/123] feat: SQL:2016 `BETWEEN [SYMMETRIC | ASYMMETRIC]` - fixes #2250 Signed-off-by: Andreas Reichel --- .../operators/relational/Between.java | 24 +++++++++++++++- .../util/deparser/ExpressionDeParser.java | 7 +++++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 11 +++++++- .../operators/relational/BetweenTest.java | 28 +++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java index 1cd997216..8998863ef 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java @@ -22,6 +22,8 @@ public class Between extends ASTNodeAccessImpl implements Expression { private boolean not = false; private Expression betweenExpressionStart; private Expression betweenExpressionEnd; + private boolean usingSymmetric = false; + private boolean usingAsymmetric = false; public Expression getBetweenExpressionEnd() { return betweenExpressionEnd; @@ -55,6 +57,24 @@ public void setNot(boolean b) { not = b; } + public boolean isUsingSymmetric() { + return usingSymmetric; + } + + public Between setUsingSymmetric(boolean usingSymmetric) { + this.usingSymmetric = usingSymmetric; + return this; + } + + public boolean isUsingAsymmetric() { + return usingAsymmetric; + } + + public Between setUsingAsymmetric(boolean usingAsymmetric) { + this.usingAsymmetric = usingAsymmetric; + return this; + } + @Override public T accept(ExpressionVisitor expressionVisitor, S context) { return expressionVisitor.visit(this, context); @@ -62,7 +82,9 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { @Override public String toString() { - return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + betweenExpressionStart + return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + + (usingSymmetric ? "SYMMETRIC " : "") + (usingAsymmetric ? "ASYMMETRIC " : "") + + betweenExpressionStart + " AND " + betweenExpressionEnd; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index c93960539..c37f85688 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -182,6 +182,13 @@ public StringBuilder visit(Between between, S context) { } builder.append(" BETWEEN "); + + if (between.isUsingSymmetric()) { + builder.append("SYMMETRIC "); + } else if (between.isUsingAsymmetric()) { + builder.append("ASYMMETRIC "); + } + between.getBetweenExpressionStart().accept(this, context); builder.append(" AND "); between.getBetweenExpressionEnd().accept(this, context); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index e08eff09e..d08afff15 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -248,6 +248,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -564,6 +565,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -2275,7 +2277,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk="KILL" | 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" ) + | tk= | tk= | tk="KILL" | 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; } } @@ -4825,6 +4827,13 @@ Expression Between(Expression leftExpression) : { [ { result.setNot(true); }] + [ + LOOKAHEAD(2) ( + { result.setUsingSymmetric(true); } + | + { result.setUsingAsymmetric(true); } + ) + ] ( LOOKAHEAD( 3 ) betweenExpressionStart = ParenthesedSelect() | diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java index 56f2f44df..4fd8fd706 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java @@ -10,7 +10,9 @@ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -22,4 +24,30 @@ void testBetweenWithAdditionIssue1948() throws JSQLParserException { "select col FROM tbl WHERE start_time BETWEEN 1706024185 AND MyFunc() - 734400"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testBetweenSymmetricIssue2250() throws JSQLParserException { + String sqlStr = + "SELECT *\n" + + "FROM orders\n" + + "WHERE 100 BETWEEN SYMMETRIC total_price AND discount_price;\n"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Between between = (Between) select.getWhere(); + + Assertions.assertTrue(between.isUsingSymmetric()); + Assertions.assertFalse(between.isUsingAsymmetric()); + } + + @Test + void testBetweenASymmetricIssue2250() throws JSQLParserException { + String sqlStr = + "SELECT *\n" + + "FROM orders\n" + + "WHERE 100 BETWEEN ASYMMETRIC total_price AND discount_price;\n"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Between between = (Between) select.getWhere(); + + Assertions.assertFalse(between.isUsingSymmetric()); + Assertions.assertTrue(between.isUsingAsymmetric()); + } } From 2f6afbc3eb16d17a1748768e101e776d911ed847 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 31 May 2025 23:19:26 +0700 Subject: [PATCH 043/123] feat: `WITH ... AS NOT MATERIALIZED` - fixes #2251 Signed-off-by: Andreas Reichel --- .../jsqlparser/statement/select/WithItem.java | 33 +++++++++++++++++-- .../util/deparser/SelectDeParser.java | 4 ++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 5 +-- .../statement/select/WithItemTest.java | 20 +++++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java index 2f464cb65..d40264815 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java @@ -28,7 +28,7 @@ public class WithItem implements Serializable { private Alias alias; private List> withItemList; private boolean recursive = false; - + private boolean usingNot = false; private boolean materialized = false; public WithItem(K statement, Alias alias) { @@ -90,6 +90,24 @@ public void setMaterialized(boolean materialized) { this.materialized = materialized; } + public K getStatement() { + return statement; + } + + public WithItem setStatement(K statement) { + this.statement = statement; + return this; + } + + public boolean isUsingNot() { + return usingNot; + } + + public WithItem setUsingNot(boolean usingNot) { + this.usingNot = usingNot; + return this; + } + /** * The {@link SelectItem}s in this WITH (for example the A,B,C in "WITH mywith (A,B,C) AS ...") * @@ -119,7 +137,11 @@ public String toString() { builder.append(")"); } builder.append(" AS "); - builder.append(materialized ? "MATERIALIZED " : ""); + if (materialized) { + builder.append(usingNot + ? "NOT MATERIALIZED " + : "MATERIALIZED "); + } builder.append(statement); return builder.toString(); } @@ -144,6 +166,13 @@ public WithItem withRecursive(boolean recursive, boolean materialized) { return this; } + public WithItem withRecursive(boolean recursive, boolean usingNot, boolean materialized) { + this.setRecursive(recursive); + this.setUsingNot(usingNot); + this.setMaterialized(materialized); + return this; + } + public WithItem addWithItemList(SelectItem... withItemList) { List> collection = Optional.ofNullable(getWithItemList()).orElseGet(ArrayList::new); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index c14c9b9ab..586f524e9 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -718,7 +718,9 @@ public StringBuilder visit(WithItem withItem, S context) { } builder.append(" AS "); if (withItem.isMaterialized()) { - builder.append("MATERIALIZED "); + builder.append(withItem.isUsingNot() + ? "NOT MATERIALIZED " + : "MATERIALIZED "); } StatementDeParser statementDeParser = new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d08afff15..6f710f93c 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -3348,6 +3348,7 @@ WithItem WithItem() #WithItem: { boolean recursive = false; boolean materialized = false; + boolean usingNot = false; String name; List> selectItems = null; ParenthesedStatement statement; @@ -3357,7 +3358,7 @@ WithItem WithItem() #WithItem: name=RelObjectName() [ "(" selectItems=SelectItemsList() ")" ] - [ LOOKAHEAD(2) { materialized = true; } ] + [ LOOKAHEAD(2) [ { usingNot = true; } ] { materialized = true; } ] ( LOOKAHEAD(2) statement = ParenthesedSelect() | @@ -3370,7 +3371,7 @@ WithItem WithItem() #WithItem: { WithItem withItem = new WithItem(statement, new Alias(name, false)); return withItem - .withRecursive(recursive, materialized) + .withRecursive(recursive, usingNot, materialized) .withWithItemList(selectItems); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java new file mode 100644 index 000000000..99eec0b19 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java @@ -0,0 +1,20 @@ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class WithItemTest { + + @Test + void testNotMaterializedIssue2251() throws JSQLParserException { + String sqlStr = "WITH devices AS NOT MATERIALIZED (\n" + + " SELECT\n" + + " d.uuid AS device_uuid\n" + + " FROM active_devices d\n" + + ")\n" + + "SELECT 1;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + +} From 6e91c3e1e3c94b3b33f69ee25026b1a87c19d9a3 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Mon, 2 Jun 2025 14:20:06 +0700 Subject: [PATCH 044/123] fix: date/time functions colliding with implicit casts - fixes https://github.com/starlake-ai/jsqltranspiler/issues/93 Signed-off-by: Andreas Reichel --- .../jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 2 +- .../sf/jsqlparser/expression/CastExpressionTest.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 6f710f93c..d2c3b914f 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5435,7 +5435,7 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) retval=CharacterPrimary() - | LOOKAHEAD(5, {!interrupted}) retval=ImplicitCast() + | LOOKAHEAD(6, {!interrupted}) retval=ImplicitCast() | retval = JdbcParameter() diff --git a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java index 806b6764a..f4e17c136 100644 --- a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java @@ -104,4 +104,14 @@ void testParenthesisCastIssue1997() throws JSQLParserException { sqlStr = "SELECT ((foo)::text = ANY((((ARRAY['bar'])))::text[]))"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDateTimeCast() throws JSQLParserException { + String sqlStr = "SELECT\n" + + " TIME(15, 30, 00) as time_hms,\n" + + " TIME(DATETIME '2008-12-25 15:30:00') AS time_dt,\n" + + " TIME(TIMESTAMP '2008-12-25 15:30:00+08', 'America/Los_Angeles')\n" + + "as time_tstz;"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From b8c0ed58f3ee5729e450fb2006557b720f132128 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 6 Jun 2025 19:57:39 +0700 Subject: [PATCH 045/123] fix: increase Max. Nesting Depth to 16 (from 10) - fixes #2257 Signed-off-by: Andreas Reichel --- .../jsqlparser/parser/CCJSqlParserUtil.java | 2 +- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 5 +- .../benchmark/JSQLParserBenchmark.java | 4 +- .../statement/select/SelectTest.java | 136 +++++++++++++++++- 4 files changed, 140 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java index 50d583194..3067ca027 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -40,7 +40,7 @@ @SuppressWarnings("PMD.CyclomaticComplexity") public final class CCJSqlParserUtil { public final static Logger LOGGER = Logger.getLogger(CCJSqlParserUtil.class.getName()); - public final static int ALLOWED_NESTING_DEPTH = 10; + public final static int ALLOWED_NESTING_DEPTH = 16; static { LOGGER.setLevel(Level.OFF); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d2c3b914f..7b58f9aac 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5128,8 +5128,9 @@ ExpressionList ComplexExpressionList(): ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() | - LOOKAHEAD( 6 ) expr=LambdaExpression() - | expr=Expression() + LOOKAHEAD(6) expr=LambdaExpression() + | + expr=Expression() ) { expressions.add(expr); } )* diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java index a65bccbe2..abe61a804 100644 --- a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -77,9 +77,7 @@ public void parseSQLStatements(Blackhole blackhole) throws Exception { final Statements statements = runner.parseStatements( sqlContent, executorService, - (Consumer) parser -> { - // No-op consumer (or you can log/validate each parser if desired) - }); + (Consumer) parser -> parser.withAllowComplexParsing(false)); blackhole.consume(statements); } 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 78d10a7b1..210f95189 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6221,8 +6221,142 @@ void testIssue2242SubSelectLookAhead() throws JSQLParserException { + " ON CONFLICT (id) DO UPDATE\n" + " SET col4 = ?, col5 = ?, col6 = ?"; Statement statement = CCJSqlParserUtil.parse(sqlStr); - System.out.println(statement.toString()); Insert insert = (Insert) statement; Assertions.assertEquals("foo", insert.getTable().toString()); } + + @Test + void testIssue2255() throws JSQLParserException { + String sqlStr = "select\n" + + " sum(if(log.\"output\" = 'SUCCESS', 1, 0)) success_req_num\n" + + "from mysql_kt_plan.daily_cvmapi_runinstance_log log"; + CCJSqlParserUtil.parse(sqlStr); + } + + @Test + void testIssue2257() throws JSQLParserException { + String sqlStr = "SELECT sum(iif(diff = 7, lc_lv, 0)) AS lc_7\n" + + "FROM ( SELECT a.day\n" + + " , a.channel_type\n" + + " , a.username\n" + + " , a.diff\n" + + " , a.cnt\n" + + " , lc\n" + + " , Cast( lc / cnt AS DECIMAL (38, 4) ) AS lc_lv\n" + + " FROM ( SELECT a.day\n" + + " , a.channel_type\n" + + " , a.username\n" + + " , Datediff( b.day, a.day )\n" + + " + 1 AS diff\n" + + " , cnt\n" + + " , Count( DISTINCT b.user_id ) AS lc\n" + + " FROM ( SELECT a.day\n" + + " , a.user_id\n" + + " , channel_id channel_type\n" + + " , adtrace_adgroup_id AS username\n" + + " FROM ( SELECT day\n" + + " , a.user_id\n" + + " , last_login_channel_id AS channel_id\n" + + " , last_adtrace_adgroup_id AS adtrace_adgroup_id\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " , Row_Number( )\n" + + " OVER (PARTITION BY day, user_id ORDER BY event_time) AS rk\n" + + " FROM dwd_table.event_pj\n" + + " WHERE day BETWEEN '2025-05-30'\n" + + " AND '2025-06-06'\n" + + " AND event_id = 'device_login'\n" + + " AND yidevice IS NOT NULL\n" + + " AND yidevice != '' ) a\n" + + " WHERE rk = 1 ) a\n" + + " LEFT JOIN ( SELECT DISTINCT\n" + + " From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) AS last_adtrace_dt\n" + + " , yidevice\n" + + " , last_login_channel_id\n" + + " , last_adtrace_adgroup_id\n" + + " , last_adtrace_creative_id\n" + + " FROM dwd_user.yidevice_pj\n" + + " WHERE Cast( adtrace_reattributed_times AS INT ) > 0\n" + + " AND Datediff( From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ), create_date ) >= 30\n" + + " AND From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) BETWEEN '2025-05-30'\n" + + " AND '2025-06-06' ) b\n" + + " ON a.day = b.last_adtrace_dt\n" + + " AND a.yidevice = b.yidevice ) a ) a\n" + + " LEFT JOIN ( SELECT day\n" + + " , user_id\n" + + " FROM dwd_table.event_pj\n" + + " WHERE day BETWEEN '2025-05-30'\n" + + " AND '2025-06-06'\n" + + " AND event_id = 'login'\n" + + " GROUP BY day\n" + + " , user_id ) b\n" + + " ON a.user_id = b.user_id\n" + + " LEFT JOIN ( SELECT a.day\n" + + " , channel_type\n" + + " , username\n" + + " , Count( DISTINCT a.user_id ) AS cnt\n" + + " FROM ( SELECT a.day\n" + + " , a.user_id\n" + + " , channel_id AS channel_type\n" + + " , adtrace_adgroup_id username\n" + + " FROM ( SELECT day\n" + + " , a.user_id\n" + + " , last_login_channel_id AS channel_id\n" + + " , last_adtrace_adgroup_id AS adtrace_adgroup_id\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " , Row_Number( )\n" + + " OVER (PARTITION BY day, user_id ORDER BY event_time) AS rk\n" + + " FROM dwd_table.event_pj\n" + + " WHERE day BETWEEN '2025-05-30'\n" + + " AND '2025-06-06'\n" + + " AND event_id = 'device_login'\n" + + " AND yidevice IS NOT NULL\n" + + " AND yidevice != '' ) a\n" + + " WHERE rk = 1 ) a\n" + + " LEFT JOIN ( SELECT DISTINCT\n" + + " From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) AS last_adtrace_dt\n" + + " , yidevice\n" + + " , last_login_channel_id\n" + + " , last_adtrace_adgroup_id\n" + + " , last_adtrace_creative_id\n" + + " FROM dwd_user.yidevice_pj\n" + + " WHERE Cast( adtrace_reattributed_times AS INT ) > 0\n" + + " AND Datediff( From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ), create_date ) >= 30\n" + + " AND From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) BETWEEN '2025-05-30'\n" + + " AND '2025-06-06' ) b\n" + + " ON a.day = b.last_adtrace_dt\n" + + " AND a.yidevice = b.yidevice ) a ) a\n" + + " GROUP BY a.day\n" + + " , channel_type\n" + + " , username ) c\n" + + " ON a.day = c.day\n" + + " AND a.channel_type = c.channel_type\n" + + " AND a.username = c.username\n" + + " GROUP BY a.day\n" + + " , a.channel_type\n" + + " , a.username\n" + + " , diff\n" + + " , cnt ) a\n" + + " WHERE diff > 1\n" + + " AND diff <= 7 ) a\n" + + "GROUP BY username\n" + + " , channel_type\n" + + " , day\n" + + " , cnt\n" + + "ORDER BY username DESC\n" + + " , channel_type\n" + + " , day DESC\n" + + ";"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr, true, parser -> parser.withAllowComplexParsing(true)); + } } From 2500e1ba72718a312e7a120869f39dec48820bc0 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 7 Jun 2025 17:58:28 +0700 Subject: [PATCH 046/123] feat: add fields holding the actual resolved table Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/schema/Column.java | 23 +++++++++++++++++++ .../java/net/sf/jsqlparser/schema/Table.java | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index 2aa0994cd..661339a41 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -29,6 +29,9 @@ public class Column extends ASTNodeAccessImpl implements Expression, MultiPartNa private ArrayConstructor arrayConstructor; private String tableDelimiter = "."; + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; + public Column() {} public Column(Table table, String columnName) { @@ -223,4 +226,24 @@ public String getCommentText() { public void setCommentText(String commentText) { this.commentText = commentText; } + + /** + * Gets the actual table when resolved against a physical schema information. + * + * @return the actual table when resolved against a physical schema information + */ + public Table getResolvedTable() { + return resolvedTable; + } + + /** + * Sets resolved table. + * + * @param resolvedTable the resolved table + * @return this column + */ + public Column setResolvedTable(Table resolvedTable) { + this.resolvedTable = resolvedTable; + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 066326a88..a2011600d 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -56,6 +56,9 @@ public class Table extends ASTNodeAccessImpl implements FromItem, MultiPartName private SQLServerHints sqlServerHints; + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; + public Table() {} /** @@ -400,4 +403,24 @@ public List getNameParts() { public List getNamePartDelimiters() { return partDelimiters; } + + /** + * Gets the actual table when resolved against a physical schema information. + * + * @return the actual table when resolved against a physical schema information + */ + public Table getResolvedTable() { + return resolvedTable; + } + + /** + * Sets resolved table. + * + * @param resolvedTable the resolved table + * @return this table + */ + public Table setResolvedTable(Table resolvedTable) { + this.resolvedTable = resolvedTable; + return this; + } } From 296d0321af58abc682cc901e322b2eb7550941eb Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 7 Jun 2025 18:58:01 +0700 Subject: [PATCH 047/123] feat: add Features for `dialect` and `allowedNestingDepth` Signed-off-by: Andreas Reichel --- .../jsqlparser/parser/AbstractJSqlParser.java | 37 ++++++++ .../jsqlparser/parser/CCJSqlParserUtil.java | 94 +++++++++---------- .../sf/jsqlparser/parser/feature/Feature.java | 8 +- .../parser/feature/FeatureConfiguration.java | 10 +- .../statement/select/SelectTest.java | 15 ++- 5 files changed, 112 insertions(+), 52 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java index a39ac7e32..45580cb5e 100644 --- a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java +++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java @@ -21,6 +21,10 @@ public abstract class AbstractJSqlParser

{ protected boolean errorRecovery = false; protected List parseErrors = new ArrayList<>(); + public enum Dialect { + ORACLE, EXASOL + } + public P withSquareBracketQuotation() { return withFeature(Feature.allowSquareBracketQuotation, true); } @@ -57,6 +61,14 @@ public P withTimeOut(long timeOutMillSeconds) { return withFeature(Feature.timeOut, timeOutMillSeconds); } + public P withDialect(Dialect dialect) { + return withFeature(Feature.dialect, dialect.name()); + } + + public P withAllowedNestingDepth(int allowedNestingDepth) { + return withFeature(Feature.allowedNestingDepth, allowedNestingDepth); + } + public P withBackslashEscapeCharacter() { return withFeature(Feature.allowBackslashEscapeCharacter, true); } @@ -83,8 +95,21 @@ public P withFeature(Feature f, long value) { return me(); } + public P withFeature(Feature f, String value) { + getConfiguration().setValue(f, value); + return me(); + } + public abstract FeatureConfiguration getConfiguration(); + public FeatureConfiguration setValue(Feature feature, Object value) { + return getConfiguration().setValue(feature, value); + } + + public Object getValue(Feature feature) { + return getConfiguration().getValue(feature); + } + public abstract P me(); public boolean getAsBoolean(Feature f) { @@ -95,6 +120,18 @@ public Long getAsLong(Feature f) { return getConfiguration().getAsLong(f); } + public int getAsInt(Feature f) { + return getConfiguration().getAsInt(f); + } + + public Integer getAsInteger(Feature f) { + return getConfiguration().getAsInteger(f); + } + + public String getAsString(Feature f) { + return getConfiguration().getAsString(f); + } + public void setErrorRecovery(boolean errorRecovery) { this.errorRecovery = errorRecovery; } diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java index 3067ca027..bdb25eeb4 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -40,7 +40,6 @@ @SuppressWarnings("PMD.CyclomaticComplexity") public final class CCJSqlParserUtil { public final static Logger LOGGER = Logger.getLogger(CCJSqlParserUtil.class.getName()); - public final static int ALLOWED_NESTING_DEPTH = 16; static { LOGGER.setLevel(Level.OFF); @@ -50,7 +49,7 @@ private CCJSqlParserUtil() {} public static Statement parse(Reader statementReader) throws JSQLParserException { ExecutorService executorService = Executors.newSingleThreadExecutor(); - Statement statement = null; + Statement statement; CCJSqlParser parser = new CCJSqlParser(new StreamProvider(statementReader)); try { statement = parseStatement(parser, executorService); @@ -86,7 +85,7 @@ public static Statement parse(String sql, Consumer consumer) } ExecutorService executorService = Executors.newSingleThreadExecutor(); - Statement statement = null; + Statement statement; try { statement = parse(sql, executorService, consumer); } finally { @@ -102,20 +101,22 @@ public static Statement parse(String sql, ExecutorService executorService, return null; } - Statement statement = null; + Statement statement; // first, try to parse fast and simple CCJSqlParser parser = newParser(sql); if (consumer != null) { consumer.accept(parser); } - boolean allowComplex = parser.getConfiguration().getAsBoolean(Feature.allowComplexParsing); + boolean allowComplex = parser.getAsBoolean(Feature.allowComplexParsing); + int allowedNestingDepth = parser.getAsInt(Feature.allowedNestingDepth); LOGGER.info("Allowed Complex Parsing: " + allowComplex); try { LOGGER.info("Trying SIMPLE parsing " + (allowComplex ? "first" : "only")); statement = parseStatement(parser.withAllowComplexParsing(false), executorService); } catch (JSQLParserException ex) { LOGGER.info("Nesting Depth" + getNestingDepth(sql)); - if (allowComplex && getNestingDepth(sql) <= ALLOWED_NESTING_DEPTH) { + if (allowComplex + && (allowedNestingDepth < 0 || getNestingDepth(sql) <= allowedNestingDepth)) { LOGGER.info("Trying COMPLEX parsing when SIMPLE parsing failed"); // beware: the parser must not be reused, but needs to be re-initiated parser = newParser(sql); @@ -222,23 +223,21 @@ public static Expression parseExpression(String expressionStr, boolean allowPart } catch (JSQLParserException ex1) { // when fast simple parsing fails, try complex parsing but only if it has a chance to // succeed - if (getNestingDepth(expressionStr) <= ALLOWED_NESTING_DEPTH) { - CCJSqlParser parser = newParser(expressionStr).withAllowComplexParsing(true); - if (consumer != null) { - consumer.accept(parser); - } - try { - expression = parser.Expression(); - if (!allowPartialParse - && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { - throw new JSQLParserException( - "could only parse partial expression " + expression.toString()); - } - } catch (JSQLParserException ex) { - throw ex; - } catch (ParseException ex) { - throw new JSQLParserException(ex); + CCJSqlParser parser = newParser(expressionStr).withAllowComplexParsing(true); + if (consumer != null) { + consumer.accept(parser); + } + try { + expression = parser.Expression(); + if (!allowPartialParse + && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { + throw new JSQLParserException( + "could only parse partial expression " + expression.toString()); } + } catch (JSQLParserException ex) { + throw ex; + } catch (ParseException ex) { + throw new JSQLParserException(ex); } } return expression; @@ -301,24 +300,22 @@ public static Expression parseCondExpression(String conditionalExpressionStr, throw new JSQLParserException(ex); } } catch (JSQLParserException ex1) { - if (getNestingDepth(conditionalExpressionStr) <= ALLOWED_NESTING_DEPTH) { - CCJSqlParser parser = - newParser(conditionalExpressionStr).withAllowComplexParsing(true); - if (consumer != null) { - consumer.accept(parser); - } - try { - expression = parser.Expression(); - if (!allowPartialParse - && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { - throw new JSQLParserException( - "could only parse partial expression " + expression.toString()); - } - } catch (JSQLParserException ex) { - throw ex; - } catch (ParseException ex) { - throw new JSQLParserException(ex); + CCJSqlParser parser = + newParser(conditionalExpressionStr).withAllowComplexParsing(true); + if (consumer != null) { + consumer.accept(parser); + } + try { + expression = parser.Expression(); + if (!allowPartialParse + && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { + throw new JSQLParserException( + "could only parse partial expression " + expression.toString()); } + } catch (JSQLParserException ex) { + throw ex; + } catch (ParseException ex) { + throw new JSQLParserException(ex); } } return expression; @@ -334,7 +331,7 @@ public static Expression parseCondExpression(String conditionalExpressionStr, public static Statement parseStatement(CCJSqlParser parser, ExecutorService executorService) throws JSQLParserException { - Statement statement = null; + Statement statement; Future future = executorService.submit(new Callable() { @Override public Statement call() throws ParseException { @@ -342,7 +339,7 @@ public Statement call() throws ParseException { } }); try { - statement = future.get(parser.getConfiguration().getAsLong(Feature.timeOut), + statement = future.get(parser.getAsLong(Feature.timeOut), TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { parser.interrupted = true; @@ -397,7 +394,8 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe if (consumer != null) { consumer.accept(parser); } - boolean allowComplex = parser.getConfiguration().getAsBoolean(Feature.allowComplexParsing); + boolean allowComplex = parser.getAsBoolean(Feature.allowComplexParsing); + int allowedNestingDepth = parser.getAsInt(Feature.allowedNestingDepth); // first, try to parse fast and simple try { @@ -405,7 +403,8 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe } catch (JSQLParserException ex) { // when fast simple parsing fails, try complex parsing but only if it has a chance to // succeed - if (allowComplex && getNestingDepth(sqls) <= ALLOWED_NESTING_DEPTH) { + if (allowComplex + && (allowedNestingDepth < 0 || getNestingDepth(sqls) <= allowedNestingDepth)) { // beware: parser must not be re-used but needs to be re-initiated parser = newParser(sqls); if (consumer != null) { @@ -434,7 +433,7 @@ public Statements call() throws ParseException { } }); try { - statements = future.get(parser.getConfiguration().getAsLong(Feature.timeOut), + statements = future.get(parser.getAsLong(Feature.timeOut), TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { parser.interrupted = true; @@ -450,17 +449,14 @@ public static void streamStatements(StatementListener listener, InputStream is, throws JSQLParserException { try { CCJSqlParser parser = newParser(is, encoding); - while (true) { + do { Statement stmt = parser.SingleStatement(); listener.accept(stmt); if (parser.getToken(1).kind == CCJSqlParserTokenManager.ST_SEMICOLON) { parser.getNextToken(); } - if (parser.getToken(1).kind == CCJSqlParserTokenManager.EOF) { - break; - } - } + } while (parser.getToken(1).kind != CCJSqlParserTokenManager.EOF); } catch (Exception ex) { throw new JSQLParserException(ex); } diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index 75b5c78a5..aed784cab 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -792,7 +792,13 @@ public enum Feature { * allows sub selects without parentheses, e.g. `select * from dual where 1 = select 1` */ allowUnparenthesizedSubSelects(false), - ; + + /** + * maximum nesting depth for trying complex parsing, can bet set to -1 to ignore + */ + allowedNestingDepth(10), + + dialect(null); private final Object value; private final boolean configurable; diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java index da5ddd2b0..0106431cc 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java @@ -19,7 +19,7 @@ public class FeatureConfiguration { private static final Logger LOG = Logger.getLogger(FeatureConfiguration.class.getName()); - private Map featureEnabled = new EnumMap<>(Feature.class); + private final Map featureEnabled = new EnumMap<>(Feature.class); public FeatureConfiguration() { // set default-value for all switchable features @@ -64,6 +64,14 @@ public Long getAsLong(Feature f) { return Long.valueOf(String.valueOf(getValue(f))); } + public int getAsInt(Feature f) { + return Integer.parseInt(String.valueOf(getValue(f))); + } + + public Integer getAsInteger(Feature f) { + return Integer.parseInt(String.valueOf(getValue(f))); + } + public String getAsString(Feature f) { Object value = getValue(f); return value == null ? null : String.valueOf(value); 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 210f95189..a2a40412f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6357,6 +6357,19 @@ void testIssue2257() throws JSQLParserException { + " , day DESC\n" + ";"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr, true, parser -> parser.withAllowComplexParsing(true)); + sqlStr, true, parser -> parser + .withAllowComplexParsing(true) + .withAllowedNestingDepth(-1)); + } + + @Test + void testQuotedStringValueIssue2258() throws JSQLParserException { + String sqlStr = "SELECT 'yyyy-MM-dd''T''HH:mm:ss'"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertEquals( + "yyyy-MM-dd'T'HH:mm:ss", select + .getSelectItem(0) + .getExpression(StringValue.class) + .getNotExcapedValue()); } } From e17cdef4275fa2be38ef8c9b9161db24a9207377 Mon Sep 17 00:00:00 2001 From: Emily Ong Date: Sun, 8 Jun 2025 16:27:30 +0800 Subject: [PATCH 048/123] feat: support distinctrow keyword (#2238) --- .../parser/ParserKeywordsUtils.java | 1 + .../jsqlparser/statement/select/Distinct.java | 12 ++++++++++- .../util/deparser/SelectDeParser.java | 2 ++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 5 ++++- src/site/sphinx/keywords.rst | 2 ++ .../statement/select/SelectTest.java | 21 +++++++++++++++++++ 6 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index 6e6019a64..19e89ff18 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -63,6 +63,7 @@ public class ParserKeywordsUtils { {"CURRENT", RESTRICTED_JSQLPARSER}, {"DEFAULT", RESTRICTED_ALIAS}, {"DISTINCT", RESTRICTED_SQL2016}, + {"DISTINCTROW", RESTRICTED_SQL2016}, {"DOUBLE", RESTRICTED_ALIAS}, {"ELSE", RESTRICTED_JSQLPARSER}, {"EXCEPT", RESTRICTED_SQL2016}, diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java b/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java index 37f64ad81..c0312384a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java @@ -20,6 +20,7 @@ public class Distinct implements Serializable { private List> onSelectItems; private boolean useUnique = false; + private boolean useDistinctRow = false; public Distinct() {} @@ -43,9 +44,18 @@ public void setUseUnique(boolean useUnique) { this.useUnique = useUnique; } + public boolean isUseDistinctRow() { + return useDistinctRow; + } + + public void setUseDistinctRow(boolean useDistinctRow) { + this.useDistinctRow = useDistinctRow; + } + @Override public String toString() { - String sql = useUnique ? "UNIQUE" : "DISTINCT"; + String distinctIdentifier = useDistinctRow ? "DISTINCTROW" : "DISTINCT"; + String sql = useUnique ? "UNIQUE" : distinctIdentifier; if (onSelectItems != null && !onSelectItems.isEmpty()) { sql += " ON (" + PlainSelect.getStringList(onSelectItems) + ")"; diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index 586f524e9..77491e00c 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -397,6 +397,8 @@ protected void deparseDistinctClause(Distinct distinct) { if (distinct != null) { if (distinct.isUseUnique()) { builder.append("UNIQUE "); + } else if (distinct.isUseDistinctRow()) { + builder.append("DISTINCTROW "); } else { builder.append("DISTINCT "); } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 7b58f9aac..83107c03e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -316,6 +316,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -3147,7 +3148,9 @@ PlainSelect PlainSelect() #PlainSelect: [ LOOKAHEAD(2) "ON" "(" distinctOn=SelectItemsList() { plainSelect.getDistinct().setOnSelectItems(distinctOn); } ")" ] ) | - { distinct = new Distinct(true); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(); distinct.setUseDistinctRow(true); plainSelect.setDistinct(distinct); } + | + { distinct = new Distinct(true); plainSelect.setDistinct(distinct); } | { plainSelect.setMySqlSqlCalcFoundRows(true); } | diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 941d8d175..93842cc27 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -43,6 +43,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | DISTINCT | Yes | Yes | +----------------------+-------------+-----------+ +| DISTINCTROW | Yes | Yes | ++----------------------+-------------+-----------+ | DOUBLE | Yes | | +----------------------+-------------+-----------+ | ELSE | Yes | Yes | 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 a2a40412f..8a1c6b694 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -1058,6 +1058,27 @@ public void testDistinct() throws JSQLParserException { .getExpression()).getColumnName()); } + @Test + public void testDistinctRow() throws JSQLParserException { + String statement = + "SELECT DISTINCTROW col1, col2 FROM mytable WHERE mytable.col = 9"; + Select select = (Select) TestUtils.assertSqlCanBeParsedAndDeparsed(statement, true); + + assertInstanceOf(PlainSelect.class, select); + + PlainSelect plainSelect = (PlainSelect) select; + Distinct distinct = plainSelect.getDistinct(); + + assertNotNull(distinct); + assertTrue(distinct.isUseDistinctRow()); + assertNull(distinct.getOnSelectItems()); + + assertEquals("col1", ((Column) (plainSelect.getSelectItems().get(0)) + .getExpression()).getColumnName()); + assertEquals("col2", ((Column) (plainSelect.getSelectItems().get(1)) + .getExpression()).getColumnName()); + } + @Test public void testIsDistinctFrom() throws JSQLParserException { String stmt = "SELECT name FROM tbl WHERE name IS DISTINCT FROM foo"; From 7feb3bc18a305f0ccd50281385a015740ba0260b Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 10 Jun 2025 20:32:20 +0700 Subject: [PATCH 049/123] feat: better defaults for `FromItemVisitorAdaptor` Signed-off-by: Andreas Reichel --- .../select/FromItemVisitorAdapter.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index 1ea920707..9af6c9c82 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -12,25 +12,24 @@ import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.piped.FromQuery; +import java.util.ArrayList; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class FromItemVisitorAdapter implements FromItemVisitor { @Override public T visit(Table table, S context) { - return null; } @Override public T visit(ParenthesedSelect select, S context) { - - return null; + return select.getPlainSelect().getFromItem().accept(this, context); } @Override public T visit(LateralSubSelect lateralSubSelect, S context) { - - return null; + return lateralSubSelect.getPlainSelect().getFromItem().accept(this, context); } @Override @@ -41,36 +40,35 @@ public T visit(TableFunction tableFunction, S context) { @Override public T visit(ParenthesedFromItem fromItem, S context) { - - return null; + return fromItem.getFromItem().accept(this, context); } @Override public T visit(Values values, S context) { - return null; } @Override public T visit(PlainSelect plainSelect, S context) { - - return null; + return plainSelect.getFromItem().accept(this, context); } @Override public T visit(SetOperationList setOperationList, S context) { - - return null; + ArrayList results = new ArrayList<>(); + for (Select select : setOperationList.getSelects()) { + results.add(select.accept(this, context)); + } + return results.isEmpty() ? null : results.get(0); } @Override public T visit(TableStatement tableStatement, S context) { - return null; } @Override public T visit(FromQuery fromQuery, S context) { - return null; + return fromQuery.getFromItem().accept(this, context); } } From 74607624051021613d77054a36a99777a00047d9 Mon Sep 17 00:00:00 2001 From: Stefan Steinhauser Date: Tue, 10 Jun 2025 15:46:38 +0200 Subject: [PATCH 050/123] Exasol: IMPORT/EXPORT (#2256) * feat: Implement IMPORT statement grammar For reference see https://docs.exasol.com/db/latest/sql/import.htm * feat: Classify new keywords in ParserKeywordsUtils * feat: Implement java classes for IMPORT statement * feat: Add LOOKAHEADs for IMPORT statement * fix: Fix issues in IMPORT implementation * feat: Update keywords * feat: Allow IMPORT as FromItem in SELECT * fix: Split double dot to fix broken unit tests * fix: Fix errors occured during verify step * test: Implement unit tests for IMPORT * feat: Simplify grammar * test: Implement test for sub IMPORT * fix: Use double dot token in IMPORT * feat: Implement EXPORT statement Implement Exasol EXPORT statement (see https://docs.exasol.com/db/latest/sql/export.htm) * refactor: Fix file extension in IMPORT tests * test: Implement unit tests for EXPORT statement * feat: Implement classes for EXPORT statement * test: Fix EXPORT unit tests * fix: Implement missing SampleClause methods * feat: Add further Import tests * fix: Update Keywords and fix boolean data type matching * fix: Fix SourceDestinationType implementations * style: Run spotlessApply * fix: Fix spotbugsMain * feat: Add test for RTRIM and LTRIM functions Refs: #2256 * feat: Add EXPORT feature flag * feat: Implement EXASOL dialect feature flag --------- Co-authored-by: Stefan Steinhauser Co-authored-by: manticore-projects --- src/main/java/module-info.java | 2 + .../parser/ParserKeywordsUtils.java | 8 + .../sf/jsqlparser/parser/feature/Feature.java | 13 +- .../java/net/sf/jsqlparser/schema/Table.java | 3 +- .../sf/jsqlparser/statement/CSVColumn.java | 91 ++ .../statement/CSVFileDestination.java | 75 ++ .../statement/CertificateVerification.java | 67 ++ .../statement/CloudConnectionDefinition.java | 37 + .../statement/ConnectionDefinition.java | 91 ++ .../statement/ConnectionFileDefinition.java | 60 ++ .../net/sf/jsqlparser/statement/DBMSType.java | 52 + .../sf/jsqlparser/statement/ErrorClause.java | 90 ++ .../statement/ErrorDestination.java | 13 + .../sf/jsqlparser/statement/FBVColumn.java | 98 ++ .../sf/jsqlparser/statement/FileOption.java | 85 ++ .../statement/FileSourceDestination.java | 133 +++ .../net/sf/jsqlparser/statement/FileType.java | 27 + .../sf/jsqlparser/statement/LikeClause.java | 142 +++ .../sf/jsqlparser/statement/RejectClause.java | 53 ++ .../statement/ScriptSourceDestination.java | 99 ++ .../statement/SourceDestinationType.java | 13 + .../statement/StatementVisitor.java | 14 + .../statement/StatementVisitorAdapter.java | 12 + .../statement/UserIdentification.java | 48 + .../create/table/ColumnDefinition.java | 3 +- .../statement/export/DBMSDestination.java | 118 +++ .../export/DBMSTableDestinationOption.java | 67 ++ .../jsqlparser/statement/export/Export.java | 81 ++ .../statement/export/ExportIntoItem.java | 18 + .../statement/export/FileDestination.java | 50 + .../statement/imprt/DBMSSource.java | 106 +++ .../statement/imprt/FileSource.java | 50 + .../sf/jsqlparser/statement/imprt/Import.java | 128 +++ .../statement/imprt/ImportColumn.java | 13 + .../statement/imprt/ImportFromItem.java | 18 + .../statement/select/FromItemVisitor.java | 7 + .../select/FromItemVisitorAdapter.java | 6 + .../sf/jsqlparser/util/TablesNamesFinder.java | 23 + .../util/deparser/SelectDeParser.java | 11 + .../util/deparser/StatementDeParser.java | 14 + .../validation/validator/SelectValidator.java | 11 + .../validator/StatementValidator.java | 22 +- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 895 +++++++++++++++++- src/site/sphinx/keywords.rst | 16 + .../jsqlparser/expression/FunctionTest.java | 11 + .../statement/export/ExportTest.java | 272 ++++++ .../statement/imprt/ImportTest.java | 281 ++++++ .../statement/select/SelectTest.java | 14 + 48 files changed, 3552 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/CSVColumn.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/DBMSType.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/ErrorClause.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/FBVColumn.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/FileOption.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/FileType.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/LikeClause.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/RejectClause.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/UserIdentification.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/export/Export.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/imprt/Import.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 361504653..6765fe187 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -36,7 +36,9 @@ exports net.sf.jsqlparser.statement.delete; exports net.sf.jsqlparser.statement.drop; exports net.sf.jsqlparser.statement.execute; + exports net.sf.jsqlparser.statement.export; exports net.sf.jsqlparser.statement.grant; + exports net.sf.jsqlparser.statement.imprt; exports net.sf.jsqlparser.statement.insert; exports net.sf.jsqlparser.statement.merge; exports net.sf.jsqlparser.statement.piped; diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index 19e89ff18..bfaa4a647 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -56,6 +56,7 @@ public class ParserKeywordsUtils { {"CHECK", RESTRICTED_SQL2016}, {"CONNECT", RESTRICTED_ALIAS}, {"CONNECT_BY_ROOT", RESTRICTED_JSQLPARSER}, + {"CSV", RESTRICTED_JSQLPARSER}, {"PRIOR", RESTRICTED_JSQLPARSER}, {"CONSTRAINT", RESTRICTED_SQL2016}, {"CREATE", RESTRICTED_ALIAS}, @@ -66,12 +67,15 @@ public class ParserKeywordsUtils { {"DISTINCTROW", RESTRICTED_SQL2016}, {"DOUBLE", RESTRICTED_ALIAS}, {"ELSE", RESTRICTED_JSQLPARSER}, + {"ERRORS", RESTRICTED_JSQLPARSER}, {"EXCEPT", RESTRICTED_SQL2016}, {"EXCLUDES", RESTRICTED_JSQLPARSER}, {"EXISTS", RESTRICTED_SQL2016}, {"EXTEND", RESTRICTED_JSQLPARSER}, {"FALSE", RESTRICTED_SQL2016}, + {"FBV", RESTRICTED_JSQLPARSER}, {"FETCH", RESTRICTED_SQL2016}, + {"FILE", RESTRICTED_JSQLPARSER}, {"FINAL", RESTRICTED_JSQLPARSER}, {"FOR", RESTRICTED_SQL2016}, {"FORCE", RESTRICTED_SQL2016}, @@ -87,6 +91,7 @@ public class ParserKeywordsUtils { {"IIF", RESTRICTED_ALIAS}, {"IGNORE", RESTRICTED_ALIAS}, {"ILIKE", RESTRICTED_SQL2016}, + {"IMPORT", RESTRICTED_JSQLPARSER}, {"IN", RESTRICTED_SQL2016}, {"INCLUDES", RESTRICTED_JSQLPARSER}, {"INNER", RESTRICTED_SQL2016}, @@ -122,12 +127,14 @@ public class ParserKeywordsUtils { {"RETURNING", RESTRICTED_JSQLPARSER}, {"RIGHT", RESTRICTED_SQL2016}, {"SAMPLE", RESTRICTED_ALIAS}, + {"SCRIPT", RESTRICTED_JSQLPARSER}, {"SEL", RESTRICTED_ALIAS}, {"SELECT", RESTRICTED_ALIAS}, {"SEMI", RESTRICTED_JSQLPARSER}, {"SET", RESTRICTED_JSQLPARSER}, {"SOME", RESTRICTED_JSQLPARSER}, {"START", RESTRICTED_JSQLPARSER}, + {"STATEMENT", RESTRICTED_JSQLPARSER}, {"TABLES", RESTRICTED_ALIAS}, {"TOP", RESTRICTED_SQL2016}, {"TRAILING", RESTRICTED_SQL2016}, @@ -147,6 +154,7 @@ public class ParserKeywordsUtils { {"VALUE", RESTRICTED_JSQLPARSER}, {"VALUES", RESTRICTED_SQL2016}, {"VARYING", RESTRICTED_JSQLPARSER}, + {"VERIFY", RESTRICTED_JSQLPARSER}, {"WHEN", RESTRICTED_SQL2016}, {"WHERE", RESTRICTED_SQL2016}, {"WINDOW", RESTRICTED_SQL2016}, diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index aed784cab..7f4cf2af0 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -798,7 +798,18 @@ public enum Feature { */ allowedNestingDepth(10), - dialect(null); + dialect(null), + + /** + * "IMPORT" + */ + imprt, + + /** + * "EXPORT" + */ + export, + ; private final Object value; private final boolean configurable; diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index a2011600d..fbf3fc63f 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -17,6 +17,7 @@ import net.sf.jsqlparser.expression.MySQLIndexHint; import net.sf.jsqlparser.expression.SQLServerHints; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.ErrorDestination; import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.FromItemVisitor; import net.sf.jsqlparser.statement.select.IntoTableVisitor; @@ -27,7 +28,7 @@ /** * A table. It can have an alias and the schema name it belongs to. */ -public class Table extends ASTNodeAccessImpl implements FromItem, MultiPartName { +public class Table extends ASTNodeAccessImpl implements ErrorDestination, FromItem, MultiPartName { // private Database database; // private String schemaName; diff --git a/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java b/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java new file mode 100644 index 000000000..08c7f4d1d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java @@ -0,0 +1,91 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class CSVColumn { + private Long startIndex; + private Long endIndex; + private StringValue format; + private String delimit; + + public CSVColumn(Long startIndex, Long endIndex) { + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + public CSVColumn(Long index) { + this(index, null); + } + + public Long getStartIndex() { + return startIndex; + } + + public void setStartIndex(Long startIndex) { + this.startIndex = startIndex; + } + + public Long getIndex() { + return getStartIndex(); + } + + public void setIndex(Long index) { + setStartIndex(index); + } + + public Long getEndIndex() { + return endIndex; + } + + public void setEndIndex(Long endIndex) { + this.endIndex = endIndex; + } + + public StringValue getFormat() { + return format; + } + + public void setFormat(StringValue format) { + this.format = format; + } + + public String getDelimit() { + return delimit; + } + + public void setDelimit(String delimit) { + this.delimit = delimit; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(startIndex); + if (endIndex != null) { + sql.append(" .. "); + sql.append(endIndex); + } else if (format != null || delimit != null) { + if (format != null) { + sql.append(" FORMAT = "); + sql.append(format); + } + + if (delimit != null) { + sql.append(" DELIMIT = "); + sql.append(delimit); + } + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java b/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java new file mode 100644 index 000000000..697368f83 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java @@ -0,0 +1,75 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class CSVFileDestination implements ErrorDestination { + private ConnectionDefinition connectionDefinition; + private boolean local; + private boolean secure; + private StringValue file; + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public boolean isLocal() { + return local; + } + + public void setLocal(boolean local) { + this.local = local; + } + + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public StringValue getFile() { + return file; + } + + public void setFile(StringValue file) { + this.file = file; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (local) { + sql.append("LOCAL "); + if (secure) { + sql.append("SECURE "); + } + } + + sql.append("CSV"); + + if (connectionDefinition != null) { + sql.append(" "); + sql.append(connectionDefinition); + } + + sql.append(" FILE "); + sql.append(file); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java b/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java new file mode 100644 index 000000000..7aabbb060 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java @@ -0,0 +1,67 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class CertificateVerification implements Serializable { + private Boolean ignoreCertificate; + private StringValue publicKey; + + public StringValue getPublicKey() { + return publicKey; + } + + public void setPublicKey(StringValue publicKey) { + this.publicKey = publicKey; + } + + public Boolean getIgnoreCertificate() { + return ignoreCertificate; + } + + public void setIgnoreCertificate(Boolean ignoreCertificate) { + this.ignoreCertificate = ignoreCertificate; + } + + public Boolean getVerifyCertificate() { + return !ignoreCertificate; + } + + public void setVerifyCertificate(Boolean verifyCertificate) { + this.ignoreCertificate = !verifyCertificate; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (ignoreCertificate != null) { + if (ignoreCertificate) { + sql.append("IGNORE "); + } else { + sql.append("VERIFY "); + } + sql.append("CERTIFICATE"); + } + + if (publicKey != null) { + if (ignoreCertificate != null) { + sql.append(" "); + } + sql.append("PUBLIC KEY "); + sql.append(publicKey); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java new file mode 100644 index 000000000..82b65fbd7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java @@ -0,0 +1,37 @@ +/*- + * #%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.statement; + +public class CloudConnectionDefinition extends ConnectionDefinition { + private String storage; + + public String getStorage() { + return storage; + } + + public void setStorage(String storage) { + this.storage = storage; + } + + @Override + public void setCertificateVerification(CertificateVerification certificateVerification) {} + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("AT CLOUD "); + sql.append(storage); + sql.append(" "); + appendConnectionDefinition(sql); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java new file mode 100644 index 000000000..f2887cf82 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java @@ -0,0 +1,91 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class ConnectionDefinition implements Serializable { + private String connectionObjectName; + private StringValue connectionDefinition; + private UserIdentification userIdentification; + private CertificateVerification certificateVerification; + + public String getConnectionObjectName() { + return connectionObjectName; + } + + public void setConnectionObjectName(String connectionObjectName) { + this.connectionObjectName = connectionObjectName; + } + + public StringValue getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(StringValue connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public void setConnection(String connectionObjectName) { + this.connectionObjectName = connectionObjectName; + } + + public void setConnection(StringValue connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public UserIdentification getUserIdentification() { + return userIdentification; + } + + public void setUserIdentification(UserIdentification userIdentification) { + this.userIdentification = userIdentification; + } + + public CertificateVerification getCertificateVerification() { + return certificateVerification; + } + + public void setCertificateVerification(CertificateVerification certificateVerification) { + this.certificateVerification = certificateVerification; + } + + protected StringBuilder appendConnectionDefinition(StringBuilder sql) { + if (connectionObjectName != null) { + sql.append(connectionObjectName); + } else if (connectionDefinition != null) { + sql.append(connectionDefinition); + } + + if (userIdentification != null) { + sql.append(" "); + sql.append(userIdentification); + } + + if (certificateVerification != null) { + sql.append(" "); + sql.append(certificateVerification); + } + + return sql; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("AT "); + appendConnectionDefinition(sql); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java b/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java new file mode 100644 index 000000000..f0e0d0cf1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java @@ -0,0 +1,60 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.util.List; + +public class ConnectionFileDefinition { + private ConnectionDefinition connectionDefinition; + private List filePaths; + + public ConnectionFileDefinition(List filePaths) { + this(null, filePaths); + } + + public ConnectionFileDefinition(ConnectionDefinition connectionDefinition, + List filePaths) { + this.connectionDefinition = connectionDefinition; + this.filePaths = filePaths; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public List getFilePaths() { + return filePaths; + } + + public void setFilePaths(List filePaths) { + this.filePaths = filePaths; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (connectionDefinition != null) { + sql.append(connectionDefinition); + } + + for (StringValue filePath : filePaths) { + sql.append(" FILE ").append(filePath); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/DBMSType.java b/src/main/java/net/sf/jsqlparser/statement/DBMSType.java new file mode 100644 index 000000000..4b3d667da --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/DBMSType.java @@ -0,0 +1,52 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class DBMSType implements SourceDestinationType { + private final Kind dbmsType; + private StringValue jdbcDriverDefinition; + + public DBMSType(String dbmsType) { + this(dbmsType, null); + } + + public DBMSType(String dbmsType, String jdbcDriverDefinition) { + this.dbmsType = Kind.valueOf(dbmsType.toUpperCase()); + if (jdbcDriverDefinition != null) { + this.jdbcDriverDefinition = new StringValue(jdbcDriverDefinition); + } + } + + private enum Kind { + EXA, ORA, JDBC + } + + public StringValue getJDBCDriverDefinition() { + return jdbcDriverDefinition; + } + + public void setJDBCDriverDefinition(StringValue jdbcDriverDefinition) { + this.jdbcDriverDefinition = jdbcDriverDefinition; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(dbmsType); + if (jdbcDriverDefinition != null) { + sql.append(" DRIVER = ").append(jdbcDriverDefinition); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java b/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java new file mode 100644 index 000000000..92db1a3dc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java @@ -0,0 +1,90 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.Expression; + +import java.io.Serializable; + +public class ErrorClause implements Serializable { + private ErrorDestination errorDestination; + private Expression expression; + private RejectClause rejectClause; + private boolean replace; + private boolean truncate; + + public ErrorDestination getErrorDestination() { + return errorDestination; + } + + public void setErrorDestination(ErrorDestination errorDestination) { + this.errorDestination = errorDestination; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public RejectClause getRejectClause() { + return rejectClause; + } + + public void setRejectClause(RejectClause rejectClause) { + this.rejectClause = rejectClause; + } + + public boolean isReplace() { + return replace; + } + + public void setReplace(boolean replace) { + this.replace = replace; + } + + public boolean isTruncate() { + return truncate; + } + + public void setTruncate(boolean truncate) { + this.truncate = truncate; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (errorDestination != null) { + sql.append("ERRORS INTO "); + sql.append(errorDestination); + if (expression != null) { + sql.append(" ("); + sql.append(expression); + sql.append(")"); + } + + if (replace) { + sql.append(" REPLACE"); + } else if (truncate) { + sql.append(" TRUNCATE"); + } + } + + if (rejectClause != null) { + sql.append(" "); + sql.append(rejectClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java b/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java new file mode 100644 index 000000000..258a39ebb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java @@ -0,0 +1,13 @@ +/*- + * #%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.statement; + +public interface ErrorDestination { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FBVColumn.java b/src/main/java/net/sf/jsqlparser/statement/FBVColumn.java new file mode 100644 index 000000000..a1846efd9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FBVColumn.java @@ -0,0 +1,98 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; + +public class FBVColumn { + private boolean precedesComma; + private String key; + private Expression value; + private String stringValue; + + private FBVColumn(String key, Expression value) { + this.key = key; + this.value = value; + this.stringValue = null; + } + + public FBVColumn(String key, String value) { + this.key = key; + this.value = null; + this.stringValue = value; + } + + public FBVColumn(String key, StringValue value) { + this(key, (Expression) value); + } + + public FBVColumn(String key, LongValue value) { + this(key, (Expression) value); + } + + public boolean precedesComma() { + return precedesComma; + } + + public void setPrecedesComma(boolean precedesComma) { + this.precedesComma = precedesComma; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Expression getValue() { + return value; + } + + public void setValue(String value) { + this.stringValue = value; + this.value = null; + } + + private void setValue(Expression value) { + this.value = value; + this.stringValue = null; + } + + public void setValue(StringValue value) { + setValue((Expression) value); + } + + public void setValue(LongValue value) { + setValue((Expression) value); + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (precedesComma) { + sql.append(", "); + } + + sql.append(key); + sql.append(" = "); + if (stringValue != null) { + sql.append(stringValue); + } else { + sql.append(value); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FileOption.java b/src/main/java/net/sf/jsqlparser/statement/FileOption.java new file mode 100644 index 000000000..ff91f571b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FileOption.java @@ -0,0 +1,85 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; + +public class FileOption { + private String key; + private Expression value; + private String stringValue; + + private FileOption(String key, Expression value) { + this.key = key; + this.value = value; + this.stringValue = null; + } + + public FileOption(String key, String value) { + this.key = key; + this.value = null; + this.stringValue = value; + } + + public FileOption(String key) { + this(key, (Expression) null); + } + + public FileOption(String key, StringValue value) { + this(key, (Expression) value); + } + + public FileOption(String key, LongValue value) { + this(key, (Expression) value); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Expression getValue() { + return value; + } + + public void setValue(StringValue value) { + this.value = value; + } + + public void setValue(LongValue value) { + this.value = value; + } + + public void setValue(String value) { + this.stringValue = value; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(key); + if (value != null || stringValue != null) { + sql.append(" = "); + if (stringValue != null) { + sql.append(stringValue); + } else { + sql.append(value); + } + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java b/src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java new file mode 100644 index 000000000..d5a79ed8f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java @@ -0,0 +1,133 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.statement.select.PlainSelect; + +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +public abstract class FileSourceDestination implements Serializable { + private SourceDestinationType type; + private List connectionFileDefinitions; + private Boolean local; + private Boolean secure; + private List csvColumns; + private List fbvColumns; + private List fileOptions; + private CertificateVerification certificateVerification; + + protected SourceDestinationType getType() { + return type; + } + + protected void setType(SourceDestinationType type) { + this.type = type; + } + + public List getConnectionFileDefinitions() { + return connectionFileDefinitions; + } + + public void setConnectionFileDefinitions( + List connectionFileDefinitions) { + this.connectionFileDefinitions = connectionFileDefinitions; + } + + public Boolean isLocal() { + return local; + } + + public void setLocal(Boolean local) { + this.local = local; + } + + public Boolean isSecure() { + return secure; + } + + public void setSecure(Boolean secure) { + this.secure = secure; + } + + public List getCSVColumns() { + return csvColumns; + } + + public void setCSVColumns(List csvColumns) { + this.csvColumns = csvColumns; + } + + public List getFBVColumns() { + return fbvColumns; + } + + public void setFBVColumns(List fbvColumns) { + this.fbvColumns = fbvColumns; + } + + public List getFileOptions() { + return fileOptions; + } + + public void setFileOptions(List fileOptions) { + this.fileOptions = fileOptions; + } + + public CertificateVerification getCertificateVerification() { + return certificateVerification; + } + + public void setCertificateVerification(CertificateVerification certificateVerification) { + this.certificateVerification = certificateVerification; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (local != null) { + if (local) { + sql.append("LOCAL "); + } + + if (Objects.requireNonNullElse(secure, false)) { + sql.append("SECURE "); + } + } + + sql.append(type); + if (connectionFileDefinitions != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, connectionFileDefinitions, false, false); + } + + if (csvColumns != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, csvColumns, true, true); + } else if (fbvColumns != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, fbvColumns, false, true); + } + + if (fileOptions != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, fileOptions, false, false); + } + + if (certificateVerification != null) { + sql.append(" "); + sql.append(certificateVerification); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FileType.java b/src/main/java/net/sf/jsqlparser/statement/FileType.java new file mode 100644 index 000000000..7ea1535f9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FileType.java @@ -0,0 +1,27 @@ +/*- + * #%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.statement; + +public class FileType implements SourceDestinationType { + private final Kind fileType; + + public FileType(String fileType) { + this.fileType = Kind.valueOf(fileType.toUpperCase()); + } + + private enum Kind { + CSV, FBV + } + + @Override + public String toString() { + return fileType.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/LikeClause.java b/src/main/java/net/sf/jsqlparser/statement/LikeClause.java new file mode 100644 index 000000000..448b4de72 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/LikeClause.java @@ -0,0 +1,142 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.ImportColumn; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.io.Serializable; +import java.util.List; + +/** + * Exasol Like Clause + * + * @see Like Clause in CREATE + * TABLE + * @see Like Clause in IMPORT + */ +public class LikeClause implements ImportColumn, Serializable { + private Table table; + private List> columnsList; + + private Boolean includingDefaults; + private Boolean includingIdentity; + private Boolean includingComments; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public List> getColumnsList() { + return columnsList; + } + + public void setColumnsList(List> columnsList) { + this.columnsList = columnsList; + } + + public Boolean isIncludingDefaults() { + return includingDefaults; + } + + public void setIncludingDefaults(Boolean includingDefaults) { + this.includingDefaults = includingDefaults; + } + + public Boolean isExcludingDefaults() { + return includingDefaults == null ? null : !includingDefaults; + } + + public void setExcludingDefaults(Boolean excludingDefaults) { + this.includingDefaults = !excludingDefaults; + } + + public Boolean isIncludingIdentity() { + return includingIdentity; + } + + public void setIncludingIdentity(Boolean includingIdentity) { + this.includingIdentity = includingIdentity; + } + + public Boolean isExcludingIdentity() { + return includingIdentity == null ? null : !includingIdentity; + } + + public void setExcludingIdentity(Boolean excludingIdentity) { + this.includingIdentity = !excludingIdentity; + } + + public Boolean isIncludingComments() { + return includingComments; + } + + public void setIncludingComments(Boolean includingComments) { + this.includingComments = includingComments; + } + + public Boolean isExcludingComments() { + return includingComments == null ? null : !includingComments; + } + + public void setExcludingComments(Boolean excludingComments) { + this.includingComments = !excludingComments; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(" LIKE "); + builder.append(table); + if (columnsList != null) { + builder.append(" "); + PlainSelect.appendStringListTo(builder, columnsList, true, true); + } + + if (includingDefaults != null) { + if (includingDefaults) { + builder.append(" INCLUDING "); + } else { + builder.append(" EXCLUDING "); + } + builder.append(" DEFAULTS "); + } + + if (includingIdentity != null) { + if (includingIdentity) { + builder.append(" INCLUDING "); + } else { + builder.append(" EXCLUDING "); + } + builder.append(" IDENTITY "); + } + + if (includingComments != null) { + if (includingComments) { + builder.append(" INCLUDING "); + } else { + builder.append(" EXCLUDING "); + } + builder.append(" COMMENTS "); + } + + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/RejectClause.java b/src/main/java/net/sf/jsqlparser/statement/RejectClause.java new file mode 100644 index 000000000..5ca9f9714 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/RejectClause.java @@ -0,0 +1,53 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.LongValue; + +import java.io.Serializable; + +public class RejectClause implements Serializable { + private LongValue limit; + private boolean errors; + + public LongValue getLimit() { + return limit; + } + + public void setLimit(LongValue limit) { + this.limit = limit; + } + + public boolean isErrors() { + return errors; + } + + public void setErrors(boolean errors) { + this.errors = errors; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("REJECT LIMIT "); + if (limit != null) { + sql.append(limit); + } else { + sql.append("UNLIMITED"); + } + + if (errors) { + sql.append(" ERRORS"); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java b/src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java new file mode 100644 index 000000000..c1193b037 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java @@ -0,0 +1,99 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.export.ExportIntoItem; +import net.sf.jsqlparser.statement.imprt.ImportFromItem; + +import java.io.Serializable; +import java.util.List; + +public class ScriptSourceDestination implements ImportFromItem, ExportIntoItem, Serializable { + private Table script; + private ConnectionDefinition connectionDefinition; + private List properties; + private List values; + private ErrorClause errorClause; + + public Table getScript() { + return script; + } + + public void setScript(Table script) { + this.script = script; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } + + public List getValues() { + return values; + } + + public void setValues(List values) { + this.values = values; + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("SCRIPT "); + sql.append(script); + + if (connectionDefinition != null) { + sql.append(" "); + sql.append(connectionDefinition); + } + + if (properties != null && values != null) { + sql.append(" WITH"); + + int max = Math.min(properties.size(), values.size()); + for (int i = 0; i < max; i++) { + sql.append(" "); + sql.append(properties.get(i)); + sql.append(" = "); + sql.append(values.get(i)); + } + } + + if (errorClause != null) { + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java b/src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java new file mode 100644 index 000000000..743d21378 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java @@ -0,0 +1,13 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +public interface SourceDestinationType { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index dc35ea516..0068e0cf6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -27,7 +27,9 @@ import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; @@ -329,4 +331,16 @@ default void visit(ParenthesedDelete parenthesedDelete) { default void visit(SessionStatement sessionStatement) { this.visit(sessionStatement, null); } + + T visit(Import imprt, S context); + + default void visit(Import imprt) { + this.visit(imprt, null); + } + + T visit(Export export, S context); + + default void visit(Export export) { + this.visit(export, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 4880ed988..f7dbd477f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -27,7 +27,9 @@ import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; @@ -313,4 +315,14 @@ public T visit(UnsupportedStatement unsupportedStatement, S context) { public T visit(RefreshMaterializedViewStatement materializedView, S context) { return null; } + + @Override + public T visit(Import imprt, S context) { + return null; + } + + @Override + public T visit(Export export, S context) { + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/UserIdentification.java b/src/main/java/net/sf/jsqlparser/statement/UserIdentification.java new file mode 100644 index 000000000..d951931d9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/UserIdentification.java @@ -0,0 +1,48 @@ +/*- + * #%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.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class UserIdentification implements Serializable { + private StringValue user; + private StringValue password; + + public StringValue getUser() { + return user; + } + + public void setUser(StringValue user) { + this.user = user; + } + + public StringValue getPassword() { + return password; + } + + public void setPassword(StringValue password) { + this.password = password; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("USER "); + sql.append(user); + + sql.append(" IDENTIFIED BY "); + sql.append(password); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java index 90a0e0e40..a7f47104c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java @@ -9,6 +9,7 @@ */ package net.sf.jsqlparser.statement.create.table; +import net.sf.jsqlparser.statement.imprt.ImportColumn; import net.sf.jsqlparser.statement.select.PlainSelect; import java.io.Serializable; @@ -21,7 +22,7 @@ /** * Globally used definition class for columns. */ -public class ColumnDefinition implements Serializable { +public class ColumnDefinition implements ImportColumn, Serializable { private String columnName; private ColDataType colDataType; diff --git a/src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java b/src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java new file mode 100644 index 000000000..38774023a --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java @@ -0,0 +1,118 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.ConnectionDefinition; +import net.sf.jsqlparser.statement.ErrorClause; +import net.sf.jsqlparser.statement.SourceDestinationType; +import net.sf.jsqlparser.statement.select.PlainSelect; + +import java.io.Serializable; +import java.util.List; + +public class DBMSDestination implements ExportIntoItem, Serializable { + private SourceDestinationType destinationType; + private ConnectionDefinition connectionDefinition; + private Table table; + private ExpressionList columns; + private List dbmsTableDestinationOptions; + private StringValue statement; + private ErrorClause errorClause; + + public SourceDestinationType getDestinationType() { + return destinationType; + } + + public void setDestinationType(SourceDestinationType destinationType) { + this.destinationType = destinationType; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public List getDBMSTableDestinationOptions() { + return dbmsTableDestinationOptions; + } + + public void setDBMSTableDestinationOptions( + List dbmsTableDestinationOptions) { + this.dbmsTableDestinationOptions = dbmsTableDestinationOptions; + } + + public StringValue getStatement() { + return statement; + } + + public void setStatement(StringValue statement) { + this.statement = statement; + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(destinationType); + + sql.append(" "); + sql.append(connectionDefinition); + + if (table != null) { + sql.append(" TABLE ").append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + if (dbmsTableDestinationOptions != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, dbmsTableDestinationOptions, false, false); + } + } else if (statement != null) { + sql.append(" STATEMENT ").append(statement); + } + + if (errorClause != null) { + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java b/src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java new file mode 100644 index 000000000..904acea95 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java @@ -0,0 +1,67 @@ +/*- + * #%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.statement.export; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class DBMSTableDestinationOption implements Serializable { + private String key; + private Expression value; + + private DBMSTableDestinationOption(String key, Expression value) { + this.key = key; + this.value = value; + } + + public DBMSTableDestinationOption(String key) { + this(key, (Expression) null); + } + + public DBMSTableDestinationOption(String key, StringValue value) { + this(key, (Expression) value); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Expression getValue() { + return value; + } + + public void setValue(StringValue value) { + this.value = value; + } + + public void setValue(LongValue value) { + this.value = value; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(key); + if (value != null) { + sql.append(" "); + sql.append(value); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/Export.java b/src/main/java/net/sf/jsqlparser/statement/export/Export.java new file mode 100644 index 000000000..dd6628a20 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/Export.java @@ -0,0 +1,81 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.*; + +public class Export implements Statement { + private Table table; + private ExpressionList columns; + private Select select; + private ExportIntoItem exportIntoItem; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public Select getSelect() { + return select; + } + + public void setSelect(Select select) { + this.select = select; + } + + public ExportIntoItem getExportIntoItem() { + return exportIntoItem; + } + + public void setExportIntoItem(ExportIntoItem exportIntoItem) { + this.exportIntoItem = exportIntoItem; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + sql.append("EXPORT "); + if (table != null || select != null) { + if (table != null) { + sql.append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + } else { + sql.append(select); + } + sql.append(" "); + } + + sql.append("INTO "); + sql.append(exportIntoItem); + + return sql.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java b/src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java new file mode 100644 index 000000000..4558b67e9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.statement.ErrorClause; + +public interface ExportIntoItem { + ErrorClause getErrorClause(); + + void setErrorClause(ErrorClause errorClause); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java b/src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java new file mode 100644 index 000000000..6ff364075 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java @@ -0,0 +1,50 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.statement.*; + +import java.io.Serializable; + +public class FileDestination extends FileSourceDestination implements ExportIntoItem, Serializable { + private ErrorClause errorClause; + + public SourceDestinationType getDestinationType() { + return getType(); + } + + public void setDestinationType(SourceDestinationType destinationType) { + setType(destinationType); + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(super.toString()); + + if (errorClause != null) { + sql.append(" "); + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java b/src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java new file mode 100644 index 000000000..0845af338 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java @@ -0,0 +1,106 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.ConnectionDefinition; +import net.sf.jsqlparser.statement.ErrorClause; +import net.sf.jsqlparser.statement.SourceDestinationType; +import net.sf.jsqlparser.statement.select.PlainSelect; + +import java.io.Serializable; +import java.util.List; + +public class DBMSSource implements ImportFromItem, Serializable { + private SourceDestinationType sourceType; + private ConnectionDefinition connectionDefinition; + private Table table; + private ExpressionList columns; + private List statements; + private ErrorClause errorClause; + + public SourceDestinationType getSourceType() { + return sourceType; + } + + public void setSourceType(SourceDestinationType sourceType) { + this.sourceType = sourceType; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public List getStatements() { + return statements; + } + + public void setStatements(List statements) { + this.statements = statements; + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(sourceType); + + sql.append(" "); + sql.append(connectionDefinition); + + if (table != null) { + sql.append(" TABLE ").append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + } else if (statements != null) { + for (StringValue statement : statements) { + sql.append(" STATEMENT ").append(statement); + } + } + + if (errorClause != null) { + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java b/src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java new file mode 100644 index 000000000..0be5bbab6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java @@ -0,0 +1,50 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.statement.*; + +import java.io.Serializable; + +public class FileSource extends FileSourceDestination implements ImportFromItem, Serializable { + private ErrorClause errorClause; + + public SourceDestinationType getSourceType() { + return getType(); + } + + public void setSourceType(SourceDestinationType sourceType) { + setType(sourceType); + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(super.toString()); + + if (errorClause != null) { + sql.append(" "); + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/Import.java b/src/main/java/net/sf/jsqlparser/statement/imprt/Import.java new file mode 100644 index 000000000..e71799a3d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/Import.java @@ -0,0 +1,128 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.*; + +import java.util.List; + +public class Import extends ASTNodeAccessImpl implements FromItem, Statement { + private Table table; + private ExpressionList columns; + private List importColumns; + private ImportFromItem fromItem; + private Alias alias; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public List getImportColumns() { + return importColumns; + } + + public void setImportColumns(List importColumns) { + this.importColumns = importColumns; + } + + public ImportFromItem getFromItem() { + return fromItem; + } + + public void setFromItem(ImportFromItem fromItem) { + this.fromItem = fromItem; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + sql.append("IMPORT "); + if (table != null || importColumns != null) { + sql.append("INTO "); + if (table != null) { + sql.append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + } else { + PlainSelect.appendStringListTo(sql, importColumns, true, true); + } + sql.append(" "); + } + + sql.append("FROM "); + sql.append(fromItem); + + return sql.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + @Override + public Pivot getPivot() { + return null; + } + + @Override + public void setPivot(Pivot pivot) {} + + @Override + public UnPivot getUnPivot() { + return null; + } + + @Override + public void setUnPivot(UnPivot unpivot) {} + + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java new file mode 100644 index 000000000..7d3f719dd --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java @@ -0,0 +1,13 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +public interface ImportColumn { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java new file mode 100644 index 000000000..86e736cca --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.statement.ErrorClause; + +public interface ImportFromItem { + ErrorClause getErrorClause(); + + void setErrorClause(ErrorClause errorClause); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java index 0d97c4e4b..6949b1e73 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.piped.FromQuery; public interface FromItemVisitor { @@ -68,5 +69,11 @@ default void visit(TableStatement tableStatement) { this.visit(tableStatement, null); } + T visit(Import imprt, S context); + + default void visit(Import imprt) { + this.visit(imprt, null); + } + T visit(FromQuery fromQuery, S context); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index 9af6c9c82..35dc7b441 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.piped.FromQuery; import java.util.ArrayList; @@ -68,6 +69,11 @@ public T visit(TableStatement tableStatement, S context) { } @Override + public T visit(Import imprt, S context) { + + return null; + } + public T visit(FromQuery fromQuery, S context) { return fromQuery.getFromItem().accept(this, context); } diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 84c71b576..1c3b9bf9e 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -157,7 +157,9 @@ import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; @@ -1846,4 +1848,25 @@ public Void visit(GeometryDistance geometryDistance, S context) { return null; } + @Override + public Void visit(Import imprt, S context) { + throwUnsupported(imprt); + return null; + } + + @Override + public void visit(Import imprt) { + StatementVisitor.super.visit(imprt); + } + + @Override + public Void visit(Export export, S context) { + throwUnsupported(export); + return null; + } + + @Override + public void visit(Export export) { + StatementVisitor.super.visit(export); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index 77491e00c..0ae0cd122 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -18,6 +18,7 @@ import net.sf.jsqlparser.expression.WindowDefinition; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.piped.AggregatePipeOperator; import net.sf.jsqlparser.statement.piped.AsPipeOperator; import net.sf.jsqlparser.statement.piped.CallPipeOperator; @@ -798,6 +799,12 @@ public StringBuilder visit(Values values, S context) { return builder; } + @Override + public StringBuilder visit(Import imprt, S context) { + builder.append(imprt.toString()); + return builder; + } + @Override public void visit(Values values) { SelectVisitor.super.visit(values); @@ -893,6 +900,10 @@ public void visit(ParenthesedFromItem fromItem) { visit(fromItem, null); } + public void visit(Import imprt) { + visit(imprt, null); + } + private void deparseOptimizeFor(OptimizeFor optimizeFor) { builder.append(" OPTIMIZE FOR "); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index 9f3c81fc1..ccfc0a92b 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -52,7 +52,9 @@ import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; @@ -499,4 +501,16 @@ public ExpressionDeParser getExpressionDeParser() { public SelectDeParser getSelectDeParser() { return selectDeParser; } + + @Override + public StringBuilder visit(Import imprt, S context) { + builder.append(imprt.toString()); + return builder; + } + + @Override + public StringBuilder visit(Export export, S context) { + builder.append(export.toString()); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java index 49367ddf0..bacd4e1af 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java @@ -16,6 +16,7 @@ import net.sf.jsqlparser.expression.SQLServerHints; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.ExceptOp; import net.sf.jsqlparser.statement.select.Fetch; @@ -360,6 +361,12 @@ public Void visit(Values values, S context) { return null; } + @Override + public Void visit(Import imprt, S context) { + // TODO: not yet implemented + return null; + } + @Override public void validate(SelectItem statement) { statement.accept(this, null); @@ -426,4 +433,8 @@ public void visit(Values values) { visit(values, null); } + public void visit(Import imprt) { + visit(imprt, null); + } + } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index 06b44e14f..af4ec9256 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -50,7 +50,9 @@ import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; @@ -71,7 +73,6 @@ */ public class StatementValidator extends AbstractValidator implements StatementVisitor { - @Override public Void visit(CreateIndex createIndex, S context) { getValidator(CreateIndexValidator.class).validate(createIndex); @@ -386,6 +387,18 @@ public Void visit(UnsupportedStatement unsupportedStatement, S context) { return null; } + @Override + public Void visit(Import imprt, S context) { + // TODO: not yet implemented + return null; + } + + @Override + public Void visit(Export export, S context) { + // TODO: not yet implemented + return null; + } + public void visit(CreateIndex createIndex) { visit(createIndex, null); } @@ -562,4 +575,11 @@ public void visit(UnsupportedStatement unsupportedStatement) { visit(unsupportedStatement, null); } + public void visit(Import imprt) { + visit(imprt, null); + } + + public void visit(Export export) { + visit(export, null); + } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 83107c03e..a3f148379 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -68,6 +68,8 @@ import net.sf.jsqlparser.statement.update.*; import net.sf.jsqlparser.statement.upsert.*; import net.sf.jsqlparser.statement.merge.*; import net.sf.jsqlparser.statement.grant.*; +import net.sf.jsqlparser.statement.imprt.*; +import net.sf.jsqlparser.statement.export.*; import java.util.*; import java.util.AbstractMap.SimpleEntry; import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; @@ -238,8 +240,10 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | +| | | | @@ -254,13 +258,16 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | | | +| | +| | | | @@ -273,6 +280,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | /* H2 casewhen function */ | +| | | | @@ -280,6 +288,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -287,6 +296,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -297,7 +307,9 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | +| | | | @@ -307,9 +319,12 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | +| +| | | | @@ -322,6 +337,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -329,16 +345,20 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | | +| | +| | | | | /* Salesforce SOQL */ +| | | | @@ -347,8 +367,11 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| +| | | +| | | | @@ -375,6 +398,8 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| +| | | | @@ -384,9 +409,11 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | /* Salesforce SOQL */ | +| | | | +| | | | @@ -399,6 +426,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -426,6 +454,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -443,8 +472,10 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | +| | | | @@ -454,6 +485,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -469,6 +501,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | "> | | @@ -480,6 +513,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -511,6 +545,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -536,10 +571,12 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | +| | | | @@ -599,6 +636,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -618,6 +656,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -685,7 +724,7 @@ TOKEN : /* Data Types */ | <#TYPE_BIT: "BISTRING"> | <#TYPE_BLOB: "BLOB" | "BYTEA" | | "VARBINARY" | > - | <#TYPE_BOOLEAN: "BOOLEAN" | "BOOL" > + | <#TYPE_BOOLEAN: | "BOOL" > | <#TYPE_ENUM: "ENUM" > | <#TYPE_MAP: "MAP" > | <#TYPE_DECIMAL: "DECIMAL" | "NUMBER" | "NUMERIC" > @@ -974,6 +1013,8 @@ Statement SingleStatement() : stm = PurgeStatement() | stm = SessionStatement() + | + LOOKAHEAD({ Dialect.EXASOL.name().equals(getAsString(Feature.dialect)) }) ( stm = Import() | stm = Export() ) ) { return stm; } } @@ -1150,6 +1191,848 @@ List error_skipto(int kind) { return tokenImages; } +LikeClause LikeClause(): { + LikeClause likeClause = new LikeClause(); + Table table; + List> columnsList; +} { + + table = Table() { likeClause.setTable(table); } + [ "(" columnsList = ColumnSelectItemsList() ")" { likeClause.setColumnsList(columnsList); }] + + [ + LOOKAHEAD(2) + ( + { likeClause.setIncludingDefaults(true); } + | { likeClause.setExcludingDefaults(true); } + ) + + ] + + [ + LOOKAHEAD(2) + ( + { likeClause.setIncludingIdentity(true); } + | { likeClause.setExcludingIdentity(true); } + ) + + ] + + [ + LOOKAHEAD(2) + ( + { likeClause.setIncludingComments(true); } + | { likeClause.setExcludingComments(true); } + ) + + ] + + { + return likeClause; + } +} + +Export Export() #Export: { + Export export = new Export(); + Table table; + ParenthesedExpressionList columns; + ParenthesedSelect select; + ExportIntoItem exportIntoItem; +} { + + ( + table = Table() { export.setTable(table); } + [ columns = ParenthesedColumnList() { export.setColumns(columns); } ] + | select = ParenthesedSelect() { export.setSelect(select); } + ) + + + exportIntoItem = ExportIntoItem() { export.setExportIntoItem(exportIntoItem); } + + { + return export; + } +} + +Import Import() #Import: { + Import impt = new Import(); + Table table; + ParenthesedExpressionList columns; + List importColumns; + ImportFromItem fromItem; +} { + + [ + + ( + table = Table() { impt.setTable(table); } + [ columns = ParenthesedColumnList() { impt.setColumns(columns); } ] + | importColumns = ImportColumns() { impt.setImportColumns(importColumns); } + ) + ] + + + fromItem = ImportFromItem() { impt.setFromItem(fromItem); } + + { + return impt; + } +} + +Import SubImport() #SubImport: { + Import impt = new Import(); + List importColumns; + ImportFromItem fromItem; +} { + "(" + + [ importColumns = ImportColumns() { impt.setImportColumns(importColumns); } ] + + + fromItem = ImportFromItem() { impt.setFromItem(fromItem); } + ")" + + { + return impt; + } +} + +List ImportColumns(): { + ImportColumn importColumn; + List importColumns = new ArrayList(); +} { + "(" + ( + importColumn = ColumnDefinition() + | importColumn = LikeClause() + ) + { importColumns.add(importColumn); } + + ( + "," + ( + importColumn = ColumnDefinition() + | importColumn = LikeClause() + ) + { importColumns.add(importColumn); } + )* + ")" + + { + return importColumns; + } +} + +ExportIntoItem ExportIntoItem(): { + ExportIntoItem exportIntoItem; + ErrorClause errorClause; +} { + ( + exportIntoItem = DBMSDestination() + | exportIntoItem = FileDestination() + | exportIntoItem = ScriptSourceDestination() + ) + [ LOOKAHEAD(2) errorClause = ErrorClause() { exportIntoItem.setErrorClause(errorClause); } ] + + { + return exportIntoItem; + } +} + +ImportFromItem ImportFromItem(): { + ImportFromItem importFromItem; + ErrorClause errorClause; +} { + ( + importFromItem = DBMSSource() + | importFromItem = FileSource() + | importFromItem = ScriptSourceDestination() + ) + [ LOOKAHEAD(2) errorClause = ErrorClause() { importFromItem.setErrorClause(errorClause); } ] + + { + return importFromItem; + } +} + +DBMSDestination DBMSDestination() #DBMSDestination: { + DBMSDestination dbmsDestination = new DBMSDestination(); + DBMSType dbmsType; + ConnectionDefinition connectionDefinition; + Table table; + ExpressionList columns; + StringValue statement; + List dbmsTableDestinationOptions; +} { + dbmsType = DBMSType() { dbmsDestination.setDestinationType(dbmsType); } + + connectionDefinition = ConnectionDefinition() { dbmsDestination.setConnectionDefinition(connectionDefinition); } + + ( + LOOKAHEAD(3) + table = Table() { dbmsDestination.setTable(table); } + [ LOOKAHEAD(2) columns = ParenthesedColumnList() { dbmsDestination.setColumns(columns); } ] + [ LOOKAHEAD(2) dbmsTableDestinationOptions = DBMSTableDestinationOptionList() { dbmsDestination.setDBMSTableDestinationOptions(dbmsTableDestinationOptions); } ] + | statement = ImportExportStatement() { dbmsDestination.setStatement(statement); } + ) + + { + return dbmsDestination; + } +} + +DBMSTableDestinationOption DBMSTableDestinationOption(): { + DBMSTableDestinationOption dbmsTableDestinationOption; + + Token token; + Token token2; + Token token3; +} { + ( + ( + token = + | token = + ) { dbmsTableDestinationOption = new DBMSTableDestinationOption(token.image); } + | token = token2 = token3 = { dbmsTableDestinationOption = new DBMSTableDestinationOption(token.image + " " + token2.image, new StringValue(token3.image)); } + ) + + { + return dbmsTableDestinationOption; + } +} + +List DBMSTableDestinationOptionList(): { + List dbmsTableDestinationOptions = new ArrayList(); + DBMSTableDestinationOption dbmsTableDestinationOption; +} { + ( LOOKAHEAD(2) dbmsTableDestinationOption = DBMSTableDestinationOption() { dbmsTableDestinationOptions.add(dbmsTableDestinationOption); } )+ + { + return dbmsTableDestinationOptions; + } +} + +DBMSSource DBMSSource() #DBMSSource: { + DBMSSource dbmsSource = new DBMSSource(); + DBMSType dbmsType; + ConnectionDefinition connectionDefinition; + Table table; + ExpressionList columns; + List statements; +} { + dbmsType = DBMSType() { dbmsSource.setSourceType(dbmsType); } + + connectionDefinition = ConnectionDefinition() { dbmsSource.setConnectionDefinition(connectionDefinition); } + + ( + table = Table() { dbmsSource.setTable(table); } + [ LOOKAHEAD(2) columns = ParenthesedColumnList() { dbmsSource.setColumns(columns); } ] + | statements = ImportExportStatementsList() { dbmsSource.setStatements(statements); } + ) + { + return dbmsSource; + } +} + +DBMSType DBMSType(): { + DBMSType dbmsType; + Token tk1; + Token tk2 = null; +} { + ( + tk1= + | tk1= + | tk1= + [ "=" tk2=] + ) { dbmsType = new DBMSType(tk1.image, tk2 == null ? null : tk2.image); } + { + return dbmsType; + } +} + +FileType FileType(): { + FileType fileType; + Token tk; +} { + ( + tk= + | tk= + ) { fileType = new FileType(tk.image); } + { + return fileType; + } +} + +StringValue ImportExportStatement() #ImportExportStatement: { + StringValue statement; +} { + token = + { + statement = new StringValue(token.image); + linkAST(statement, jjtThis); + return statement; + } +} + +List ImportExportStatementsList(): { + List statements = new ArrayList(); + StringValue statement; +} { + ( statement = ImportExportStatement() { statements.add(statement); } )+ + + { + return statements; + } +} + +StringValue File() #File: { + Token token; +} { + token = + { + StringValue file = new StringValue(token.image); + linkAST(file, jjtThis); + return file; + } +} + +List FileList(): { + List files = new ArrayList(); + StringValue file; +} { + ( file = File() { files.add(file); } )+ + { + return files; + } +} + +ConnectionFileDefinition ConnectionFileDefinition(): { + ConnectionDefinition connectionDefinition = null; + List files; +} { + connectionDefinition = ConnectionOrCloudConnectionDefinition() + files = FileList() + { + return new ConnectionFileDefinition(connectionDefinition, files); + } +} + +List ConnectionFileDefinitionList(): { + List connectionFileDefinitions = new ArrayList(); + ConnectionFileDefinition connectionFileDefinition; +} { + ( LOOKAHEAD(2) connectionFileDefinition = ConnectionFileDefinition() { connectionFileDefinitions.add(connectionFileDefinition); } )+ + { + return connectionFileDefinitions; + } +} + +CSVColumn CSVDestinationColumn(): { + CSVColumn csvColumn; + + Token token; + Token token2; +} { + ( + LOOKAHEAD(2) + token= ".." token2= { csvColumn = new CSVColumn(Long.valueOf(token.image), Long.valueOf(token2.image)); } + | token= { csvColumn = new CSVColumn(Long.valueOf(token.image)); } + [ "=" token = { csvColumn.setFormat(new StringValue(token.image)); }] + [ + + "=" + ( + token= + | token= + | token= + ) + { csvColumn.setDelimit(token.image); } + ] + ) + { + return csvColumn; + } +} + +List CSVDestinationColumnList(): { + List csvColumns = new ArrayList(); + CSVColumn csvColumn; +} { + csvColumn = CSVDestinationColumn() { csvColumns.add(csvColumn); } + ( "," csvColumn = CSVDestinationColumn() { csvColumns.add(csvColumn); } )* + { + return csvColumns; + } +} + +CSVColumn CSVSourceColumn(): { + CSVColumn csvColumn; + + Token token; + Token token2; +} { + ( + LOOKAHEAD(2) + token= ".." token2= { csvColumn = new CSVColumn(Long.valueOf(token.image), Long.valueOf(token2.image)); } + | token= { csvColumn = new CSVColumn(Long.valueOf(token.image)); } + [ "=" token = { csvColumn.setFormat(new StringValue(token.image)); }] + ) + { + return csvColumn; + } +} + +List CSVSourceColumnList(): { + List csvColumns = new ArrayList(); + CSVColumn csvColumn; +} { + csvColumn = CSVSourceColumn() { csvColumns.add(csvColumn); } + ( "," csvColumn = CSVSourceColumn() { csvColumns.add(csvColumn); } )* + { + return csvColumns; + } +} + +FBVColumn FBVDestinationColumn(): { + FBVColumn fbvColumn; + + Token token; + Token token2; +} { + ( + token= "=" token2= { fbvColumn = new FBVColumn(token.image, new LongValue(token2.image)); } + | ( token= | token= ) "=" token2= { fbvColumn = new FBVColumn(token.image, new StringValue(token2.image)); } + | token= "=" ( token2= | token2= ) { fbvColumn = new FBVColumn(token.image, token2.image); } + ) + { + return fbvColumn; + } +} + +List FBVDestinationColumnList(): { + List fbvColumns = new ArrayList(); + FBVColumn fbvColumn; + boolean precedesComma; +} { + fbvColumn = FBVDestinationColumn() { fbvColumns.add(fbvColumn); } + ( + { precedesComma = false; } + ["," { precedesComma = true; }] + fbvColumn = FBVDestinationColumn() { fbvColumn.setPrecedesComma(precedesComma); fbvColumns.add(fbvColumn); } + )* + { + return fbvColumns; + } +} + +FBVColumn FBVSourceColumn(): { + FBVColumn fbvColumn; + + Token token; + Token token2; +} { + ( + ( token= | token= ) "=" token2= { fbvColumn = new FBVColumn(token.image, new LongValue(token2.image)); } + | ( token= | token= ) "=" token2= { fbvColumn = new FBVColumn(token.image, new StringValue(token2.image)); } + | token= "=" ( token2= | token2= ) { fbvColumn = new FBVColumn(token.image, token2.image); } + ) + { + return fbvColumn; + } +} + +List FBVSourceColumnList(): { + List fbvColumns = new ArrayList(); + FBVColumn fbvColumn; + boolean precedesComma; +} { + fbvColumn = FBVSourceColumn() { fbvColumns.add(fbvColumn); } + ( + { precedesComma = false; } + ["," { precedesComma = true; }] + fbvColumn = FBVSourceColumn() { fbvColumn.setPrecedesComma(precedesComma); fbvColumns.add(fbvColumn); } + )* + { + return fbvColumns; + } +} + +FileOption FileDestinationOption(): { + FileOption fileOption; + + Token token; + Token token2; + Token token3; +} { + ( + ( token= | token= ) { fileOption = new FileOption(token.image); } + | token= token2= token3= { fileOption = new FileOption(token.image + " " + token2.image + " " + token3.image); } + | ( token= | token= | token= ) "=" token2= { fileOption = new FileOption(token.image, new StringValue(token2.image)); } + | ( + token= token2= "=" token3= + | token= ( token2= | token2= ) "=" token3= + ) + { fileOption = new FileOption(token.image + " " + token2.image, new StringValue(token3.image)); } + | token= "=" ( token2= | token2= | token2= ) { fileOption = new FileOption(token.image, token2.image); } + ) + { + return fileOption; + } +} + +List FileDestinationOptionList(): { + List fileOptions = new ArrayList(); + FileOption fileOption; +} { + ( LOOKAHEAD(2) fileOption = FileDestinationOption() { fileOptions.add(fileOption); } )+ + { + return fileOptions; + } +} + +FileOption FileSourceOption(): { + FileOption fileOption; + + Token token; + Token token2; + Token token3; +} { + ( + ( token= | token= | token= ) { fileOption = new FileOption(token.image); } + | ( + ( token= | token= ) "=" token2= { fileOption = new FileOption(token.image, new StringValue(token2.image)); } + | token= "=" token2= { fileOption = new FileOption(token.image, new LongValue(token2.image)); } + ) + | LOOKAHEAD(2) + ( + token= token2= "=" token3= + | token= ( token2= | token2= ) "=" token3= + ) + { fileOption = new FileOption(token.image + " " + token2.image, new StringValue(token3.image)); } + | token= token2= "=" token3= + { fileOption = new FileOption(token.image + " " + token2.image, new LongValue(token3.image)); } + ) + { + return fileOption; + } +} + +List FileSourceOptionList(): { + List fileOptions = new ArrayList(); + FileOption fileOption; +} { + ( LOOKAHEAD(2) fileOption = FileSourceOption() { fileOptions.add(fileOption); } )+ + { + return fileOptions; + } +} + +FileDestination FileDestination() #FileDestination: { + FileDestination fileDestination = new FileDestination(); + FileType fileType; + List connectionFileDefinitions; + List files; + List csvColumns; + List fbvColumns; + List fileOptions; + CertificateVerification certificateVerification; +} { + ( + fileType = FileType() { fileDestination.setDestinationType(fileType); } + connectionFileDefinitions = ConnectionFileDefinitionList() { fileDestination.setConnectionFileDefinitions(connectionFileDefinitions); } + | { fileDestination.setLocal(true); } + [ { fileDestination.setSecure(true); }] + + fileType = FileType() { fileDestination.setDestinationType(fileType); } + files = FileList() + { + connectionFileDefinitions = new ArrayList(); + connectionFileDefinitions.add(new ConnectionFileDefinition(files)); + } + ) + { fileDestination.setConnectionFileDefinitions(connectionFileDefinitions); } + + [ + LOOKAHEAD(2) + "(" + ( + csvColumns = CSVDestinationColumnList() { fileDestination.setCSVColumns(csvColumns); } + | fbvColumns = FBVDestinationColumnList() { fileDestination.setFBVColumns(fbvColumns); } + ) + ")" + ] + + [ LOOKAHEAD(2) fileOptions = FileDestinationOptionList() { fileDestination.setFileOptions(fileOptions); } ] + + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { fileDestination.setCertificateVerification(certificateVerification); } ] + + { + return fileDestination; + } +} + +FileSource FileSource() #FileSource: { + FileSource fileSource = new FileSource(); + FileType fileType; + List connectionFileDefinitions; + List files; + List csvColumns; + List fbvColumns; + List fileOptions; + CertificateVerification certificateVerification; +} { + ( + fileType = FileType() { fileSource.setSourceType(fileType); } + connectionFileDefinitions = ConnectionFileDefinitionList() { fileSource.setConnectionFileDefinitions(connectionFileDefinitions); } + | { fileSource.setLocal(true); } + [ { fileSource.setSecure(true); }] + + fileType = FileType() { fileSource.setSourceType(fileType); } + files = FileList() + { + connectionFileDefinitions = new ArrayList(); + connectionFileDefinitions.add(new ConnectionFileDefinition(files)); + } + ) + { fileSource.setConnectionFileDefinitions(connectionFileDefinitions); } + + [ + LOOKAHEAD(2) + "(" + ( + csvColumns = CSVSourceColumnList() { fileSource.setCSVColumns(csvColumns); } + | fbvColumns = FBVSourceColumnList() { fileSource.setFBVColumns(fbvColumns); } + ) + ")" + ] + + [ LOOKAHEAD(2) fileOptions = FileSourceOptionList() { fileSource.setFileOptions(fileOptions); } ] + + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { fileSource.setCertificateVerification(certificateVerification); } ] + + { + return fileSource; + } +} + +CertificateVerification CertificateVerification(): { + CertificateVerification certificateVerification = new CertificateVerification(); + Token token; +} { + ( + ( + { certificateVerification.setIgnoreCertificate(true); } + | { certificateVerification.setVerifyCertificate(true); } + ) + + [ + LOOKAHEAD(2) + + token = { certificateVerification.setPublicKey(new StringValue(token.image)); } + ] + | + token = { certificateVerification.setPublicKey(new StringValue(token.image)); } + ) + { + return certificateVerification; + } +} + +ScriptSourceDestination ScriptSourceDestination(): { + ScriptSourceDestination scriptSourceDestination = new ScriptSourceDestination(); + ConnectionDefinition connectionDefinition; + Table script; + String property; + StringValue value; + + Token token; +} { + + script = Table() { scriptSourceDestination.setScript(script); } + + [ LOOKAHEAD(2) connectionDefinition = ConnectionDefinition() { scriptSourceDestination.setConnectionDefinition(connectionDefinition); } ] + + [ + LOOKAHEAD(2) + { + List properties = new ArrayList(); + List values = new ArrayList(); + scriptSourceDestination.setProperties(properties); + scriptSourceDestination.setValues(values); + } + + + ( + LOOKAHEAD(2) + property = RelObjectNameWithoutValue() "=" token = { value = new StringValue(token.image); } + { + properties.add(property); + values.add(value); + } + )+ + ] + + { + return scriptSourceDestination; + } +} + +UserIdentification UserIdentification(): { + UserIdentification userIdentification = new UserIdentification(); + Token token; +} { + + token= { userIdentification.setUser(new StringValue(token.image)); } + + token= { userIdentification.setPassword(new StringValue(token.image)); } + + { + return userIdentification; + } +} + +ConnectionDefinition ConnectionDefinition(): { + ConnectionDefinition connectionDefinition = new ConnectionDefinition(); + String connectionObjectName; + UserIdentification userIdentification; + CertificateVerification certificateVerification; + + Token token; +} { + + ( + connectionObjectName = RelObjectNameWithoutValue() { connectionDefinition.setConnectionObjectName(connectionObjectName); } + | token= { connectionDefinition.setConnectionDefinition(new StringValue(token.image)); } + ) + + [ LOOKAHEAD(2) userIdentification = UserIdentification() { connectionDefinition.setUserIdentification(userIdentification); } ] + + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { connectionDefinition.setCertificateVerification(certificateVerification); } ] + + { + return connectionDefinition; + } +} + +ConnectionDefinition CloudConnectionDefinition(): { + CloudConnectionDefinition connectionDefinition = new CloudConnectionDefinition(); + String connectionObjectName; + UserIdentification userIdentification; + + Token token; + Token token2; +} { + + ( + token = { connectionDefinition.setStorage(token.image); } + | token = token2 = { connectionDefinition.setStorage(token.image + " " + token2.image); } + ) + + ( + connectionObjectName = RelObjectNameWithoutValue() { connectionDefinition.setConnectionObjectName(connectionObjectName); } + | token = { connectionDefinition.setConnectionDefinition(new StringValue(token.image)); } + ) + + [ userIdentification = UserIdentification() { connectionDefinition.setUserIdentification(userIdentification); } ] + + { + return connectionDefinition; + } +} + +ConnectionDefinition ConnectionOrCloudConnectionDefinition(): { + ConnectionDefinition connectionDefinition; +} { + ( + LOOKAHEAD(2) connectionDefinition = CloudConnectionDefinition() + | connectionDefinition = ConnectionDefinition() + ) + { + return connectionDefinition; + } +} + +ErrorClause ErrorClause(): { + ErrorClause errorClause = new ErrorClause(); + ErrorDestination errorDestination; + Expression expression; + RejectClause rejectClause; + + Token token; +} { + ( + + errorDestination = ErrorDestination() { errorClause.setErrorDestination(errorDestination); } + [ + LOOKAHEAD(2) + "(" + expression = Expression() { errorClause.setExpression(expression); } + ")" + ] + [ + LOOKAHEAD(2) + ( + { errorClause.setReplace(true); } + | { errorClause.setTruncate(true); } + ) + ] + [ LOOKAHEAD(2) rejectClause = RejectClause() { errorClause.setRejectClause(rejectClause); } ] + | rejectClause = RejectClause() { errorClause.setRejectClause(rejectClause); } + ) + + { + return errorClause; + } +} + +RejectClause RejectClause(): { + RejectClause rejectClause = new RejectClause(); +} { + + ( + token= { rejectClause.setLimit(new LongValue(token.image)); } + | + ) + + [ LOOKAHEAD(2) { rejectClause.setErrors(true); } ] + + { + return rejectClause; + } +} + +ErrorDestination ErrorDestination(): { + ErrorDestination errorDestination; +} { + ( + LOOKAHEAD(2) errorDestination = CSVFileDestination() + | errorDestination = Table() + ) + + { + return errorDestination; + } +} + +CSVFileDestination CSVFileDestination(): { + CSVFileDestination csvFileDestination = new CSVFileDestination(); + ConnectionDefinition connectionDefinition; + StringValue file; +} { + ( + + connectionDefinition = ConnectionOrCloudConnectionDefinition() { csvFileDestination.setConnectionDefinition(connectionDefinition); } + | { csvFileDestination.setLocal(true); } + [ { csvFileDestination.setSecure(true); } ] + + ) + + file = File() { csvFileDestination.setFile(file); } + + { + return csvFileDestination; + } +} + DeclareStatement Declare(): { UserVariable userVariable; ColDataType colDataType; @@ -2278,7 +3161,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | tk= | tk="KILL" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="SYMMETRIC" | 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="UNLIMITED" | 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; } } @@ -3778,6 +4661,8 @@ FromItem FromItem() #FromItem: | fromItem=LateralSubSelect() | + LOOKAHEAD(2, { Dialect.EXASOL.name().equals(getAsString(Feature.dialect)) }) fromItem=SubImport() { fromItem = new ParenthesedFromItem(fromItem); } + | LOOKAHEAD({ getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) fromItem=Select() ) @@ -7198,12 +8083,12 @@ ColDataType DataType(): | ( ( tk= | tk= | tk = | tk = | tk = - | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= ) { type = tk.image; } [ // MySQL seems to allow: INT UNSIGNED LOOKAHEAD(2) ( LOOKAHEAD(2) ( tk = | tk = | tk = - | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= ) { type += " " + tk.image; } )+ ] [ @@ -7464,7 +8349,7 @@ List CreateParameter(): | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk = | tk = - | tk= + | tk= | tk= | tk="=" ) { param.add(tk.image); } diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 93842cc27..933cba664 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -29,6 +29,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | CONNECT_BY_ROOT | Yes | Yes | +----------------------+-------------+-----------+ +| CSV | Yes | Yes | ++----------------------+-------------+-----------+ | PRIOR | Yes | Yes | +----------------------+-------------+-----------+ | CONSTRAINT | Yes | Yes | @@ -49,6 +51,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | ELSE | Yes | Yes | +----------------------+-------------+-----------+ +| ERRORS | Yes | Yes | ++----------------------+-------------+-----------+ | EXCEPT | Yes | Yes | +----------------------+-------------+-----------+ | EXCLUDES | Yes | Yes | @@ -59,8 +63,12 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | FALSE | Yes | Yes | +----------------------+-------------+-----------+ +| FBV | Yes | Yes | ++----------------------+-------------+-----------+ | FETCH | Yes | Yes | +----------------------+-------------+-----------+ +| FILE | Yes | Yes | ++----------------------+-------------+-----------+ | FINAL | Yes | Yes | +----------------------+-------------+-----------+ | FOR | Yes | Yes | @@ -91,6 +99,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | ILIKE | Yes | Yes | +----------------------+-------------+-----------+ +| IMPORT | Yes | Yes | ++----------------------+-------------+-----------+ | IN | Yes | Yes | +----------------------+-------------+-----------+ | INCLUDES | Yes | Yes | @@ -161,6 +171,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | SAMPLE | Yes | | +----------------------+-------------+-----------+ +| SCRIPT | Yes | Yes | ++----------------------+-------------+-----------+ | SEL | Yes | | +----------------------+-------------+-----------+ | SELECT | Yes | | @@ -173,6 +185,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | START | Yes | Yes | +----------------------+-------------+-----------+ +| STATEMENT | Yes | Yes | ++----------------------+-------------+-----------+ | TABLES | Yes | | +----------------------+-------------+-----------+ | TOP | Yes | Yes | @@ -211,6 +225,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | VARYING | Yes | Yes | +----------------------+-------------+-----------+ +| VERIFY | Yes | Yes | ++----------------------+-------------+-----------+ | WHEN | Yes | Yes | +----------------------+-------------+-----------+ | WHERE | Yes | Yes | diff --git a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java index 0433222d3..8f3daf474 100644 --- a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java @@ -108,4 +108,15 @@ void testSimpleFunctionIssue2059() throws JSQLParserException { void testListAggOnOverflow(String sqlStr) throws Exception { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @ParameterizedTest + @ValueSource(strings = { + "select RTRIM('string')", + "select LTRIM('string')", + "select RTRIM(field) from dual", + "select LTRIM(field) from dual" + }) + void testTrimFunctions(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java b/src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java new file mode 100644 index 000000000..1d158b975 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java @@ -0,0 +1,272 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@Execution(ExecutionMode.CONCURRENT) +public class ExportTest { + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName ( columnName ) INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName ( columnName1, columnName2 ) INTO LOCAL CSV FILE 'file.csv'", + + "EXPORT ( select 1 ) INTO LOCAL CSV FILE 'file.csv'", + }) + public void testExport(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file1.csv' FILE 'file2.csv'", + + "EXPORT schemaName.tableName INTO LOCAL SECURE CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL SECURE CSV FILE 'file1.csv' FILE 'file2.csv'" + }) + public void testExportIntoFileCSV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1, 2 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format' )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 DELIMIT = ALWAYS )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 DELIMIT = NEVER )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 DELIMIT = AUTO )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format', 2 DELIMIT = NEVER )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format', 2 DELIMIT = NEVER, 3 FORMAT = 'format' DELIMIT = ALWAYS )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 .. 2 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2, 3 )" + }) + public void testExportIntoFileCSVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv'", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file1.fbv' FILE 'file2.fbv'", + + "EXPORT schemaName.tableName INTO LOCAL SECURE FBV FILE 'file.fbv'", + "EXPORT schemaName.tableName INTO LOCAL SECURE FBV FILE 'file1.fbv' FILE 'file2.fbv'" + }) + public void testExportIntoFileFBV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1 )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( FORMAT = 'format' )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( ALIGN = LEFT )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( ALIGN = RIGHT )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( PADDING = '0' )", + + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1, PADDING = '0' )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1 PADDING = '0' )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1 PADDING = '0', FORMAT = 'format' )" + }) + public void testExportIntoFileFBVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REPLACE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' TRUNCATE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' NULL = 'null'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' BOOLEAN = 'yes/no'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ROW SEPARATOR = 'CRLF'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' COLUMN SEPARATOR = ','", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' COLUMN DELIMITER = '\"'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' DELIMIT = ALWAYS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' DELIMIT = NEVER", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' DELIMIT = AUTO", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' WITH COLUMN NAMES", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' REPLACE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' REPLACE WITH COLUMN NAMES" + }) + public void testExportIntoFileFileOpts(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' PUBLIC KEY 'publicKey'", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE PUBLIC KEY 'publicKey'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE PUBLIC KEY 'publicKey'" + }) + public void testExportIntoFileCertVerification(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO CSV AT connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' FILE 'file.csv'", + + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + + "EXPORT schemaName.tableName INTO CSV AT connectionName IGNORE CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName VERIFY CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'" + }) + public void testExportIntoConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE '127.0.0.1' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'" + }) + public void testExportIntoCloudConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName )", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName REPLACE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName TRUNCATE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName CREATED BY 'CREATE OR REPLACE TABLE schemaName (columnName INTEGER)'", + + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName REPLACE TRUNCATE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName ) REPLACE TRUNCATE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 ) REPLACE TRUNCATE", + + "EXPORT schemaName.tableName INTO EXA AT connectionName STATEMENT 'insert into schemaName.tableName ( columnName ) values ( ? )'" + }) + public void testExportIntoDBMSEXA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO ORA AT connectionName TABLE schemaName.tableName", + "EXPORT schemaName.tableName INTO ORA AT connectionName TABLE schemaName.tableName ( columnName )", + "EXPORT schemaName.tableName INTO ORA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "EXPORT schemaName.tableName INTO ORA AT connectionName STATEMENT 'insert into schemaName.tableName ( columnName ) values ( ? )'" + }) + public void testExportIntoDBMSORA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO JDBC AT connectionName TABLE tableName", + "EXPORT schemaName.tableName INTO JDBC DRIVER = 'driverName' AT connectionName TABLE tableName" + }) + public void testExportIntoDBMSJDBC(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO SCRIPT scriptName", + "EXPORT schemaName.tableName INTO SCRIPT scriptName AT connectionName", + "EXPORT schemaName.tableName INTO SCRIPT scriptName WITH propertyName = 'value'", + "EXPORT schemaName.tableName INTO SCRIPT scriptName WITH propertyName = 'value' propertyName2 = 'value2'", + "EXPORT schemaName.tableName INTO SCRIPT scriptName AT connectionName WITH propertyName = 'value' propertyName2 = 'value2'" + }) + public void testExportIntoScript(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1 ERRORS", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED ERRORS" + }) + public void testImportErrorClause(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java b/src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java new file mode 100644 index 000000000..1539d4375 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java @@ -0,0 +1,281 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@Execution(ExecutionMode.CONCURRENT) +public class ImportTest { + @ParameterizedTest + @ValueSource(strings = { + "IMPORT INTO schemaName.tableName FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO schemaName.tableName ( columnName ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO schemaName.tableName ( columnName1, columnName2 ) FROM LOCAL CSV FILE 'file.csv'" + }) + public void testImportIntoTable(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT INTO ( columnName integer ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( columnName1 integer, columnName2 varchar(100) ) FROM LOCAL CSV FILE 'file.csv'", + + "IMPORT INTO ( LIKE schemaName.tableName ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName1, columnName2 ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName AS aliasName ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName aliasName ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName1 AS aliasName2, columnName2 AS aliasName2 ) ) FROM LOCAL CSV FILE 'file.csv'" + }) + public void testImportIntoImportColumns(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file1.csv' FILE 'file2.csv'", + + "IMPORT FROM LOCAL SECURE CSV FILE 'file.csv'", + "IMPORT FROM LOCAL SECURE CSV FILE 'file1.csv' FILE 'file2.csv'" + }) + public void testImportFromFileCSV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1, 2 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format' )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format', 2 FORMAT = 'format' )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 .. 2 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2, 3 )" + }) + public void testImportFromFileCSVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL FBV FILE 'file.fbv'", + "IMPORT FROM LOCAL FBV FILE 'file1.fbv' FILE 'file2.fbv'", + + "IMPORT FROM LOCAL SECURE FBV FILE 'file.fbv'", + "IMPORT FROM LOCAL SECURE FBV FILE 'file1.fbv' FILE 'file2.fbv'" + }) + public void testImportFromFileFBV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( START = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( FORMAT = 'format' )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( ALIGN = LEFT )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( ALIGN = RIGHT )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( PADDING = 'padding' )", + + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1, START = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1 START = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1 START = 1, FORMAT = 'format' )" + }) + public void testImportFromFileFBVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' SKIP = 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' TRIM", + "IMPORT FROM LOCAL CSV FILE 'file.csv' LTRIM", + "IMPORT FROM LOCAL CSV FILE 'file.csv' RTRIM", + "IMPORT FROM LOCAL CSV FILE 'file.csv' NULL = 'null'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ROW SEPARATOR = 'CRLF'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' COLUMN SEPARATOR = ','", + "IMPORT FROM LOCAL CSV FILE 'file.csv' COLUMN DELIMITER = '\"'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ROW SIZE = 1", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' SKIP = 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' SKIP = 1 TRIM" + }) + public void testImportFromFileFileOpts(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE", + "IMPORT FROM LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE", + "IMPORT FROM LOCAL CSV FILE 'file.csv' PUBLIC KEY 'publicKey'", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE PUBLIC KEY 'publicKey'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE PUBLIC KEY 'publicKey'" + }) + public void testImportFromFileCertVerification(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM CSV AT connectionName FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' FILE 'file.csv'", + + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + + "IMPORT FROM CSV AT connectionName IGNORE CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName VERIFY CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'" + }) + public void testImportFromConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM CSV AT CLOUD NONE connectionName FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD NONE '127.0.0.1' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD NONE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD NONE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE connectionName FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'" + }) + public void testImportFromCloudConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM EXA AT connectionName TABLE schemaName.tableName", + "IMPORT FROM EXA AT connectionName TABLE schemaName.tableName ( columnName )", + "IMPORT FROM EXA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "IMPORT FROM EXA AT connectionName STATEMENT 'select 1'", + "IMPORT FROM EXA AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'" + }) + public void testImportFromDBMSEXA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM ORA AT connectionName TABLE schemaName.tableName", + "IMPORT FROM ORA AT connectionName TABLE schemaName.tableName ( columnName )", + "IMPORT FROM ORA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "IMPORT FROM ORA AT connectionName STATEMENT 'select 1'", + "IMPORT FROM ORA AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'" + }) + public void testImportFromDBMSORA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM JDBC AT connectionName TABLE tableName", + "IMPORT FROM JDBC DRIVER = 'driverName' AT connectionName TABLE tableName", + + "IMPORT FROM JDBC AT connectionName STATEMENT 'select 1'", + "IMPORT FROM JDBC AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'", + "IMPORT FROM JDBC DRIVER = 'driverName' AT connectionName STATEMENT 'select 1'", + "IMPORT FROM JDBC DRIVER = 'driverName' AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'" + }) + public void testImportFromDBMSJDBC(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM SCRIPT scriptName", + "IMPORT FROM SCRIPT scriptName AT connectionName", + "IMPORT FROM SCRIPT scriptName WITH propertyName = 'value'", + "IMPORT FROM SCRIPT scriptName WITH propertyName = 'value' propertyName2 = 'value2'", + "IMPORT FROM SCRIPT scriptName AT connectionName WITH propertyName = 'value' propertyName2 = 'value2'" + }) + public void testImportFromScript(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1 ERRORS", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED ERRORS" + }) + public void testImportErrorClause(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } +} 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 8a1c6b694..1ba1bb4a7 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -58,6 +58,7 @@ import net.sf.jsqlparser.expression.operators.relational.GreaterThan; import net.sf.jsqlparser.expression.operators.relational.InExpression; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; @@ -6242,6 +6243,7 @@ void testIssue2242SubSelectLookAhead() throws JSQLParserException { + " ON CONFLICT (id) DO UPDATE\n" + " SET col4 = ?, col5 = ?, col6 = ?"; Statement statement = CCJSqlParserUtil.parse(sqlStr); + System.out.println(statement.toString()); Insert insert = (Insert) statement; Assertions.assertEquals("foo", insert.getTable().toString()); } @@ -6393,4 +6395,16 @@ void testQuotedStringValueIssue2258() throws JSQLParserException { .getExpression(StringValue.class) .getNotExcapedValue()); } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM ( IMPORT FROM EXA AT connectionName STATEMENT 'select 1' )", + "SELECT * FROM ( IMPORT INTO ( LIKE schemaName.tableName ( a, b as c) ) FROM EXA AT connectionName STATEMENT 'select 1' )", + "SELECT * FROM schemaName.tableName JOIN ( IMPORT FROM EXA AT connectionName STATEMENT 'select 1' ) USING ( columnName )" + }) + public void testSelectWithSubImport(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + } From f14c6115bd3e715dc6feeb502fd37adc09a2abea Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 11 Jun 2025 00:25:41 +0700 Subject: [PATCH 051/123] fix: GroupByElement::getGroupByExpressionList shall not return raw ExpressionList - fixes #2237 Signed-off-by: Andreas Reichel --- .../statement/select/GroupByElement.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java index a708fe720..649afdeff 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java @@ -35,23 +35,23 @@ public T accept(GroupByVisitor groupByVisitor, S context) { return groupByVisitor.visit(this, context); } - public ExpressionList getGroupByExpressionList() { + public ExpressionList getGroupByExpressionList() { return groupByExpressions; } @Deprecated - public ExpressionList getGroupByExpressions() { + public ExpressionList getGroupByExpressions() { return groupByExpressions; } - public void setGroupByExpressions(ExpressionList groupByExpressions) { + public void setGroupByExpressions(ExpressionList groupByExpressions) { this.groupByExpressions = groupByExpressions; } @Deprecated public void addGroupByExpression(Expression groupByExpression) { if (groupByExpressions.getExpressions() == null) { - groupByExpressions.setExpressions(new ArrayList()); + groupByExpressions.setExpressions(new ArrayList<>()); } groupByExpressions.add(groupByExpression); } @@ -64,7 +64,7 @@ public void setGroupingSets(List> groupingSets) { this.groupingSets = groupingSets; } - public void addGroupingSet(ExpressionList list) { + public void addGroupingSet(ExpressionList list) { this.groupingSets.add(list); } @@ -79,12 +79,12 @@ public String toString() { } int i = 0; - if (groupingSets.size() > 0) { + if (!groupingSets.isEmpty()) { if (b.charAt(b.length() - 1) != ' ') { b.append(' '); } b.append("GROUPING SETS ("); - for (ExpressionList expressionList : groupingSets) { + for (ExpressionList expressionList : groupingSets) { b.append(i++ > 0 ? ", " : "").append(Select.getStringList( expressionList, true, expressionList instanceof ParenthesedExpressionList)); @@ -99,12 +99,12 @@ public String toString() { return b.toString(); } - public GroupByElement withGroupByExpressions(ExpressionList groupByExpressions) { + public GroupByElement withGroupByExpressions(ExpressionList groupByExpressions) { this.setGroupByExpressions(groupByExpressions); return this; } - public GroupByElement withGroupingSets(List groupingSets) { + public GroupByElement withGroupingSets(List> groupingSets) { this.setGroupingSets(groupingSets); return this; } @@ -127,7 +127,7 @@ public GroupByElement addGroupingSets(Object... groupingSets) { return this.withGroupingSets(collection); } - public GroupByElement addGroupingSets(Collection groupingSets) { + public GroupByElement addGroupingSets(Collection>> groupingSets) { List collection = Optional.ofNullable(getGroupingSets()).orElseGet(ArrayList::new); collection.addAll(groupingSets); return this.withGroupingSets(collection); From 066e1bbb7335aa2f2c5535a91c83c4bcd320181f Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 11 Jun 2025 15:27:13 +0700 Subject: [PATCH 052/123] feat: make the various Visitor Adaptors more useful Signed-off-by: Andreas Reichel --- .../expression/ExpressionVisitorAdapter.java | 11 +- .../statement/select/GroupByElement.java | 3 +- .../sf/jsqlparser/statement/select/Limit.java | 2 +- .../statement/select/PivotVisitorAdapter.java | 12 ++ .../select/SelectItemVisitorAdapter.java | 14 +- .../select/SelectVisitorAdapter.java | 202 +++++++++++++++++- 6 files changed, 238 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 3be6d1348..51da30ab7 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -84,12 +84,21 @@ public class ExpressionVisitorAdapter private SelectVisitor selectVisitor; + public ExpressionVisitorAdapter(SelectVisitor selectVisitor) { + this.selectVisitor = selectVisitor; + } + + public ExpressionVisitorAdapter() { + this.selectVisitor = null; + } + public SelectVisitor getSelectVisitor() { return selectVisitor; } - public void setSelectVisitor(SelectVisitor selectVisitor) { + public ExpressionVisitorAdapter setSelectVisitor(SelectVisitor selectVisitor) { this.selectVisitor = selectVisitor; + return this; } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java index 649afdeff..63b6b479d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java @@ -127,7 +127,8 @@ public GroupByElement addGroupingSets(Object... groupingSets) { return this.withGroupingSets(collection); } - public GroupByElement addGroupingSets(Collection>> groupingSets) { + public GroupByElement addGroupingSets( + Collection>> groupingSets) { List collection = Optional.ofNullable(getGroupingSets()).orElseGet(ArrayList::new); collection.addAll(groupingSets); return this.withGroupingSets(collection); diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Limit.java b/src/main/java/net/sf/jsqlparser/statement/select/Limit.java index 9257daa6d..ec5923a3f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Limit.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Limit.java @@ -89,7 +89,7 @@ public String toString() { } if (byExpressions != null) { - retVal += " BY " + byExpressions.toString(); + retVal += " BY " + byExpressions; } return retVal; diff --git a/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java index 6e7fce93f..2a9f2c6af 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java @@ -9,8 +9,20 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class PivotVisitorAdapter implements PivotVisitor { + private final ExpressionVisitor expressionVisitor; + + public PivotVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter(); + } + + public PivotVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } @Override public T visit(Pivot pivot, S context) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java index 1fc7a2322..a72ff0b70 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java @@ -10,11 +10,23 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class SelectItemVisitorAdapter implements SelectItemVisitor { + private final ExpressionVisitor expressionVisitor; + + public SelectItemVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); + } + + public SelectItemVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } + @Override public T visit(SelectItem item, S context) { - return null; + return item.getExpression().accept(expressionVisitor, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java index 462160e9f..0231dbae1 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -9,18 +9,216 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.piped.FromQuery; +import java.util.List; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class SelectVisitorAdapter implements SelectVisitor { + private final ExpressionVisitor expressionVisitor; + private final PivotVisitor pivotVisitor; + private final SelectItemVisitor selectItemVisitor; + private final FromItemVisitor fromItemVisitor; + + public SelectVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(this); + this.pivotVisitor = new PivotVisitorAdapter<>(); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = new FromItemVisitorAdapter<>(); + } + + public SelectVisitorAdapter(ExpressionVisitor expressionVisitor, + PivotVisitor pivotVisitor, SelectItemVisitor selectItemVisitor, + FromItemVisitor fromItemVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = pivotVisitor; + this.selectItemVisitor = selectItemVisitor; + this.fromItemVisitor = fromItemVisitor; + } + + public SelectVisitorAdapter(ExpressionVisitor expressionVisitor, + FromItemVisitor fromItemVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = new PivotVisitorAdapter<>(); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = fromItemVisitor; + } + + public SelectVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = new PivotVisitorAdapter<>(); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = new FromItemVisitorAdapter<>(); + } @Override - public T visit(ParenthesedSelect parenthesedSelect, S context) { - return parenthesedSelect.getSelect().accept(this, context); + public T visit(ParenthesedSelect select, S context) { + List> withItemsList = select.getWithItemsList(); + if (withItemsList != null && !withItemsList.isEmpty()) { + for (WithItem withItem : withItemsList) { + withItem.accept(this, context); + } + } + + select.getSelect().accept(this, context); + + if (select.getOrderByElements() != null) { + for (OrderByElement orderByElement : select.getOrderByElements()) { + orderByElement.getExpression().accept(expressionVisitor); + } + } + + Pivot pivot = select.getPivot(); + if (pivot != null) { + pivot.accept(pivotVisitor, context); + } + UnPivot unpivot = select.getUnPivot(); + if (unpivot != null) { + unpivot.accept(pivotVisitor, context); + } + + // if (select.getLimit() != null) { + // //@todo: implement limit visitor + // } + if (select.getOffset() != null) { + select.getOffset().getOffset().accept(expressionVisitor, null); + } + if (select.getFetch() != null && select.getFetch().getExpression() != null) { + select.getFetch().getExpression().accept(expressionVisitor, null); + } + + return null; } @Override + @SuppressWarnings({"PMD.ExcessiveMethodLength"}) public T visit(PlainSelect plainSelect, S context) { + List> withItemsList = plainSelect.getWithItemsList(); + if (withItemsList != null && !withItemsList.isEmpty()) { + for (WithItem withItem : withItemsList) { + withItem.accept(this, context); + } + } + + if (plainSelect.getDistinct() != null) { + for (SelectItem selectItem : plainSelect.getDistinct().getOnSelectItems()) { + selectItem.accept(selectItemVisitor, context); + } + } + + if (plainSelect.getTop() != null) { + plainSelect.getTop().getExpression().accept(expressionVisitor, context); + } + + for (SelectItem selectItem : plainSelect.getSelectItems()) { + selectItem.accept(selectItemVisitor, context); + } + + if (plainSelect.getIntoTables() != null) { + for (Table table : plainSelect.getIntoTables()) { + table.accept(fromItemVisitor, context); + } + } + + if (plainSelect.getFromItem() != null) { + plainSelect.getFromItem().accept(fromItemVisitor, context); + } + + // if (plainSelect.getLateralViews() != null) { + // //@todo: implement this + // } + + if (plainSelect.getJoins() != null) { + for (Join join : plainSelect.getJoins()) { + join.getFromItem().accept(fromItemVisitor, context); + for (Expression expression : join.getOnExpressions()) { + expression.accept(expressionVisitor, context); + } + for (Column column : join.getUsingColumns()) { + column.accept(expressionVisitor, context); + } + } + } + + // if (plainSelect.getKsqlWindow() != null) { + // //@todo: implement + // } + + if (plainSelect.getWhere() != null) { + plainSelect.getWhere().accept(expressionVisitor, context); + } + + // if (plainSelect.getOracleHierarchical() != null) { + // //@todo: implement + // } + // + // if (plainSelect.getPreferringClause() != null) { + // //@todo: implement + // } + + if (plainSelect.getGroupBy() != null) { + GroupByElement groupBy = plainSelect.getGroupBy(); + for (Expression expression : groupBy.getGroupByExpressionList()) { + expression.accept(expressionVisitor, context); + } + if (!groupBy.getGroupingSets().isEmpty()) { + for (ExpressionList expressionList : groupBy.getGroupingSets()) { + expressionList.accept(expressionVisitor, context); + } + } + } + + if (plainSelect.getHaving() != null) { + plainSelect.getHaving().accept(expressionVisitor, context); + } + if (plainSelect.getQualify() != null) { + plainSelect.getQualify().accept(expressionVisitor, context); + } + // if (plainSelect.getWindowDefinitions() != null) { + // //@todo: implement + // } + + Pivot pivot = plainSelect.getPivot(); + if (pivot != null) { + pivot.accept(pivotVisitor, context); + } + UnPivot unpivot = plainSelect.getUnPivot(); + if (unpivot != null) { + unpivot.accept(pivotVisitor, context); + } + + if (plainSelect.getOrderByElements() != null) { + for (OrderByElement orderByElement : plainSelect.getOrderByElements()) { + orderByElement.getExpression().accept(expressionVisitor); + } + } + + // if (plainSelect.getLimitBy() != null) { + // //@todo: implement + // } + // if (plainSelect.getLimit() != null) { + // //@todo: implement + // } + if (plainSelect.getOffset() != null) { + plainSelect.getOffset().getOffset().accept(expressionVisitor, null); + } + if (plainSelect.getFetch() != null && plainSelect.getFetch().getExpression() != null) { + plainSelect.getFetch().getExpression().accept(expressionVisitor, null); + } + // if (plainSelect.getForMode() != null) { + // //@todo: implement + // } + if (plainSelect.getIntoTempTable() != null) { + for (Table t : plainSelect.getIntoTables()) { + t.accept(fromItemVisitor, context); + } + } return null; } From 963217f48732426b56ab12c26edacd0a41ee7dc3 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 13 Jun 2025 20:18:57 +0700 Subject: [PATCH 053/123] fix: resolved physical tables must be clones, not references Signed-off-by: Andreas Reichel --- src/main/java/net/sf/jsqlparser/schema/Column.java | 3 ++- src/main/java/net/sf/jsqlparser/schema/Table.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index 661339a41..f0d5e0205 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -243,7 +243,8 @@ public Table getResolvedTable() { * @return this column */ public Column setResolvedTable(Table resolvedTable) { - this.resolvedTable = resolvedTable; + // clone, not reference + this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); return this; } } diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index fbf3fc63f..7938b1f42 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -421,7 +421,8 @@ public Table getResolvedTable() { * @return this table */ public Table setResolvedTable(Table resolvedTable) { - this.resolvedTable = resolvedTable; + // clone, not reference + this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); return this; } } From 178ca057be78c00c26c878f9e6709012ad7a6d3f Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 13 Jun 2025 20:20:06 +0700 Subject: [PATCH 054/123] fix: `FromItemVisitorAdaptor` also needs a `SelectVisitor` Signed-off-by: Andreas Reichel --- .../select/FromItemVisitorAdapter.java | 28 +++++++++++++++---- .../select/SelectVisitorAdapter.java | 4 +-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index 35dc7b441..583bea5b9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -17,6 +17,24 @@ @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class FromItemVisitorAdapter implements FromItemVisitor { + private SelectVisitor selectVisitor; + + public FromItemVisitorAdapter(SelectVisitor selectVisitor) { + this.selectVisitor = selectVisitor; + } + + public FromItemVisitorAdapter() { + this.selectVisitor = new SelectVisitorAdapter<>(); + } + + public SelectVisitor getSelectVisitor() { + return selectVisitor; + } + + public FromItemVisitorAdapter setSelectVisitor(SelectVisitor selectVisitor) { + this.selectVisitor = selectVisitor; + return this; + } @Override public T visit(Table table, S context) { @@ -25,12 +43,12 @@ public T visit(Table table, S context) { @Override public T visit(ParenthesedSelect select, S context) { - return select.getPlainSelect().getFromItem().accept(this, context); + return select.getPlainSelect().accept(selectVisitor, context); } @Override public T visit(LateralSubSelect lateralSubSelect, S context) { - return lateralSubSelect.getPlainSelect().getFromItem().accept(this, context); + return lateralSubSelect.getPlainSelect().accept(selectVisitor, context); } @Override @@ -51,14 +69,14 @@ public T visit(Values values, S context) { @Override public T visit(PlainSelect plainSelect, S context) { - return plainSelect.getFromItem().accept(this, context); + return plainSelect.accept(selectVisitor, context); } @Override public T visit(SetOperationList setOperationList, S context) { ArrayList results = new ArrayList<>(); for (Select select : setOperationList.getSelects()) { - results.add(select.accept(this, context)); + results.add(select.accept(selectVisitor, context)); } return results.isEmpty() ? null : results.get(0); } @@ -75,6 +93,6 @@ public T visit(Import imprt, S context) { } public T visit(FromQuery fromQuery, S context) { - return fromQuery.getFromItem().accept(this, context); + return fromQuery.accept(selectVisitor, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java index 0231dbae1..e6fa75086 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -28,9 +28,9 @@ public class SelectVisitorAdapter implements SelectVisitor { public SelectVisitorAdapter() { this.expressionVisitor = new ExpressionVisitorAdapter<>(this); - this.pivotVisitor = new PivotVisitorAdapter<>(); + this.pivotVisitor = new PivotVisitorAdapter<>(this.expressionVisitor); this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); - this.fromItemVisitor = new FromItemVisitorAdapter<>(); + this.fromItemVisitor = new FromItemVisitorAdapter<>(this); } public SelectVisitorAdapter(ExpressionVisitor expressionVisitor, From a49e4ba68aba752835699af4b98cb3b9216bf36f Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 14 Jun 2025 22:08:40 +0700 Subject: [PATCH 055/123] test: disable reflection test - if anyone is interested in this, then please make it work and maintain it Signed-off-by: Andreas Reichel --- .../sf/jsqlparser/statement/builder/ReflectionModelTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java index bff7ef05c..2f15f3aa2 100644 --- a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java @@ -18,6 +18,7 @@ import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.util.ReflectionTestUtils; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -170,7 +171,7 @@ public class ReflectionModelTest { new net.sf.jsqlparser.statement.grant.Grant(), new net.sf.jsqlparser.statement.insert.Insert(), new net.sf.jsqlparser.statement.merge.Merge(), - new net.sf.jsqlparser.statement.merge.MergeUpdate(new ArrayList()), + new net.sf.jsqlparser.statement.merge.MergeUpdate(new ArrayList<>()), new net.sf.jsqlparser.statement.select.AllColumns(), // new net.sf.jsqlparser.statement.select.AllTableColumns(new Table()), new net.sf.jsqlparser.statement.select.Distinct(), @@ -211,6 +212,7 @@ public class ReflectionModelTest { null)); @Test + @Disabled public void testModels() { ReflectionTestUtils.testGetterSetterChaining(MODEL_OBJECTS, m -> !"setASTNode".equals(m.getName())); From e963fb6e1282a8533dc75f1c516cd26e90906065 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 14 Jun 2025 22:09:07 +0700 Subject: [PATCH 056/123] test: quieten the logger Signed-off-by: Andreas Reichel --- src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java b/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java index 8be1c9275..07dec9f07 100644 --- a/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java +++ b/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java @@ -129,7 +129,7 @@ public static void testMethodInvocation(Object object, BiPredicate returnTypeCheck, Function argsFunction, Predicate... methodFilters) { - log(Level.INFO, "testing methods of class " + object.getClass()); + log(Level.FINE, "testing methods of class " + object.getClass()); for (Method m : object.getClass().getMethods()) { boolean testMethod = true; for (Predicate f : methodFilters) { @@ -140,7 +140,7 @@ public static void testMethodInvocation(Object object, } } if (testMethod) { - log(Level.INFO, "testing method " + m.toGenericString()); + log(Level.FINE, "testing method " + m.toGenericString()); try { invoke(m, returnTypeCheck, argsFunction, object); } catch (Exception e) { From c62781a3e16dafb3100ebc003397e9fe174540a3 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 14 Jun 2025 22:19:22 +0700 Subject: [PATCH 057/123] feat: more useful VisitorAdaptors Signed-off-by: Andreas Reichel --- .../expression/AnalyticExpression.java | 9 +- .../expression/ExpressionVisitor.java | 84 +++++++++ .../expression/ExpressionVisitorAdapter.java | 48 +++--- .../jsqlparser/expression/FilterOverImpl.java | 10 +- .../expression/PartitionByClause.java | 34 ++-- .../expression/PreferringClause.java | 4 +- .../expression/WindowDefinition.java | 6 +- .../statement/StatementVisitorAdapter.java | 161 ++++++++++++++++-- .../statement/merge/MergeInsert.java | 6 +- .../merge/MergeOperationVisitor.java | 9 + .../merge/MergeOperationVisitorAdapter.java | 27 +++ .../statement/select/FromItemVisitor.java | 28 +++ .../select/FromItemVisitorAdapter.java | 44 ++++- .../statement/select/SelectVisitor.java | 15 ++ .../select/SelectVisitorAdapter.java | 146 +++++++--------- .../jsqlparser/statement/select/Values.java | 2 +- .../builder/ReflectionModelTest.java | 1 - .../util/deparser/ExpressionDeParserTest.java | 4 +- 18 files changed, 482 insertions(+), 156 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java index f2a531ab6..0c0d11146 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java @@ -60,7 +60,6 @@ public AnalyticExpression(Function function) { this.distinct = function.isDistinct(); this.unique = function.isUnique(); - ExpressionList list = function.getParameters(); if (list != null) { if (list.size() > 3) { @@ -117,16 +116,16 @@ public void setKeep(KeepExpression keep) { } public ExpressionList getPartitionExpressionList() { - return windowDef.partitionBy.getPartitionExpressionList(); + return windowDef.partitionBy; } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, + public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - windowDef.partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + windowDef.partitionBy.setExpressions(partitionExpressionList, brackets); } public boolean isPartitionByBrackets() { diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index a87b4594a..90a1fd96e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -61,11 +61,95 @@ import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.FunctionAllColumns; +import net.sf.jsqlparser.statement.select.GroupByElement; +import net.sf.jsqlparser.statement.select.Limit; +import net.sf.jsqlparser.statement.select.OrderByElement; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.update.UpdateSet; + +import java.util.List; public interface ExpressionVisitor { + default T visitExpressions(ExpressionList expressions, S context) { + if (expressions != null) { + expressions.forEach(expression -> expression.accept(this, context)); + } + return null; + }; + + default T visitExpression(Expression expression, S context) { + if (expression != null) { + expression.accept(this, context); + } + return null; + } + + default T visitOrderBy(List orderByElements, S context) { + if (orderByElements != null) { + for (OrderByElement orderByElement : orderByElements) { + orderByElement.getExpression().accept(this, context); + } + } + return null; + } + + default T visitLimit(Limit limit, S context) { + if (limit != null && !limit.isLimitNull() && !limit.isLimitAll()) { + if (limit.getOffset() != null) { + limit.getOffset().accept(this, context); + } + if (limit.getRowCount() != null) { + limit.getRowCount().accept(this, context); + } + if (limit.getByExpressions() != null) { + limit.getByExpressions().accept(this, context); + } + } + return null; + } + + default T visitPreferringClause(PreferringClause preferringClause, S context) { + if (preferringClause != null) { + if (preferringClause.getPreferring() != null) { + preferringClause.getPreferring().accept(this, context); + } + if (preferringClause.getPartitionBy() != null) { + for (Expression expression : preferringClause.getPartitionBy()) { + expression.accept(this, context); + } + } + } + return null; + } + + default T visitUpdateSets(List insert, S context) { + for (UpdateSet updateSet : insert) { + for (Column column : updateSet.getColumns()) { + column.accept(this, context); + } + for (Expression value : updateSet.getValues()) { + value.accept(this, context); + } + } + return null; + } + + default T visit(GroupByElement groupBy, S context) { + if (groupBy != null) { + for (Expression expression : groupBy.getGroupByExpressionList()) { + expression.accept(this, context); + } + if (!groupBy.getGroupingSets().isEmpty()) { + for (ExpressionList expressionList : groupBy.getGroupingSets()) { + expressionList.accept(this, context); + } + } + } + return null; + } + T visit(BitwiseRightShift bitwiseRightShift, S context); default void visit(BitwiseRightShift bitwiseRightShift) { diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 51da30ab7..96d80d514 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -103,7 +103,7 @@ public ExpressionVisitorAdapter setSelectVisitor(SelectVisitor selectVisit @Override public T visit(NullValue nullValue, S context) { - return visitExpression(nullValue, context); + return applyExpression(nullValue, context); } @Override @@ -130,47 +130,47 @@ public T visit(SignedExpression signedExpression, S context) { @Override public T visit(JdbcParameter jdbcParameter, S context) { - return visitExpression(jdbcParameter, context); + return applyExpression(jdbcParameter, context); } @Override public T visit(JdbcNamedParameter jdbcNamedParameter, S context) { - return visitExpression(jdbcNamedParameter, context); + return applyExpression(jdbcNamedParameter, context); } @Override public T visit(DoubleValue doubleValue, S context) { - return visitExpression(doubleValue, context); + return applyExpression(doubleValue, context); } @Override public T visit(LongValue longValue, S context) { - return visitExpression(longValue, context); + return applyExpression(longValue, context); } @Override public T visit(DateValue dateValue, S context) { - return visitExpression(dateValue, context); + return applyExpression(dateValue, context); } @Override public T visit(TimeValue timeValue, S context) { - return visitExpression(timeValue, context); + return applyExpression(timeValue, context); } @Override public T visit(TimestampValue timestampValue, S context) { - return visitExpression(timestampValue, context); + return applyExpression(timestampValue, context); } @Override public T visit(StringValue stringValue, S context) { - return visitExpression(stringValue, context); + return applyExpression(stringValue, context); } @Override public T visit(BooleanValue booleanValue, S context) { - return visitExpression(booleanValue, context); + return applyExpression(booleanValue, context); } @Override @@ -317,7 +317,7 @@ public T visit(ContainedBy containedBy, S context) { @Override public T visit(Column column, S context) { - return visitExpression(column, context); + return applyExpression(column, context); } @Override @@ -361,7 +361,7 @@ public T visit(MemberOfExpression memberOfExpression, S context) { @Override public T visit(AnyComparisonExpression anyComparisonExpression, S context) { - return visitExpression(anyComparisonExpression, context); + return applyExpression(anyComparisonExpression, context); } @Override @@ -490,7 +490,7 @@ public T visit(BitwiseLeftShift bitwiseLeftShift, S context) { return visitBinaryExpression(bitwiseLeftShift, context); } - protected T visitExpression(Expression expression, S context) { + protected T applyExpression(Expression expression, S context) { return null; } @@ -531,12 +531,12 @@ public T visit(JsonOperator jsonOperator, S context) { @Override public T visit(UserVariable userVariable, S context) { - return visitExpression(userVariable, context); + return applyExpression(userVariable, context); } @Override public T visit(NumericBind numericBind, S context) { - return visitExpression(numericBind, context); + return applyExpression(numericBind, context); } @Override @@ -601,22 +601,22 @@ public T visit(UnPivot unpivot, S context) { @Override public T visit(AllColumns allColumns, S context) { - return visitExpression(allColumns, context); + return applyExpression(allColumns, context); } @Override public T visit(AllTableColumns allTableColumns, S context) { - return visitExpression(allTableColumns, context); + return applyExpression(allTableColumns, context); } @Override public T visit(FunctionAllColumns functionAllColumns, S context) { - return visitExpression(functionAllColumns, context); + return applyExpression(functionAllColumns, context); } @Override public T visit(AllValue allValue, S context) { - return visitExpression(allValue, context); + return applyExpression(allValue, context); } @Override @@ -636,27 +636,27 @@ public T visit(RowGetExpression rowGetExpression, S context) { @Override public T visit(HexValue hexValue, S context) { - return visitExpression(hexValue, context); + return applyExpression(hexValue, context); } @Override public T visit(OracleHint hint, S context) { - return visitExpression(hint, context); + return applyExpression(hint, context); } @Override public T visit(TimeKeyExpression timeKeyExpression, S context) { - return visitExpression(timeKeyExpression, context); + return applyExpression(timeKeyExpression, context); } @Override public T visit(DateTimeLiteralExpression dateTimeLiteralExpression, S context) { - return visitExpression(dateTimeLiteralExpression, context); + return applyExpression(dateTimeLiteralExpression, context); } @Override public T visit(NextValExpression nextValExpression, S context) { - return visitExpression(nextValExpression, context); + return applyExpression(nextValExpression, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java b/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java index 50e557933..a64d8eb27 100644 --- a/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java +++ b/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java @@ -51,17 +51,17 @@ public FilterOverImpl withOrderByElements(List orderByElements) return this; } - public ExpressionList getPartitionExpressionList() { - return partitionBy.getPartitionExpressionList(); + public ExpressionList getPartitionExpressionList() { + return partitionBy; } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, + public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + partitionBy.setExpressions(partitionExpressionList, brackets); } public boolean isPartitionByBrackets() { diff --git a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java index 243975029..6ad41e994 100644 --- a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java @@ -14,29 +14,39 @@ import java.io.Serializable; -public class PartitionByClause implements Serializable { - ExpressionList partitionExpressionList; +public class PartitionByClause extends ExpressionList implements Serializable { boolean brackets = false; - public ExpressionList getPartitionExpressionList() { - return partitionExpressionList; + @Deprecated + public ExpressionList getPartitionExpressionList() { + return this; } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + setExpressions(partitionExpressionList, brackets); + } + + public PartitionByClause setExpressions(ExpressionList partitionExpressionList, boolean brackets) { - this.partitionExpressionList = partitionExpressionList; + clear(); + if (partitionExpressionList != null) { + addAll(partitionExpressionList); + } this.brackets = brackets; + return this; } public void toStringPartitionBy(StringBuilder b) { - if (partitionExpressionList != null - && !partitionExpressionList.getExpressions().isEmpty()) { + if (!isEmpty()) { b.append("PARTITION BY "); - b.append(PlainSelect.getStringList(partitionExpressionList.getExpressions(), true, + b.append(PlainSelect.getStringList(this, true, brackets)); b.append(" "); } @@ -46,7 +56,9 @@ public boolean isBrackets() { return brackets; } - public PartitionByClause withPartitionExpressionList(ExpressionList partitionExpressionList) { + @Deprecated + public PartitionByClause withPartitionExpressionList( + ExpressionList partitionExpressionList) { this.setPartitionExpressionList(partitionExpressionList); return this; } diff --git a/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java index 08ebb71a7..2db468dbb 100644 --- a/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java @@ -21,12 +21,12 @@ public PreferringClause(Expression preferring) { this.preferring = preferring; } - public void setPartitionExpressionList(ExpressionList expressionList, + public void setPartitionExpressionList(ExpressionList expressionList, boolean brackets) { if (this.partitionBy == null) { this.partitionBy = new PartitionByClause(); } - partitionBy.setPartitionExpressionList(expressionList, brackets); + partitionBy.setExpressions(expressionList, brackets); } public void toStringPreferring(StringBuilder b) { diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java index a5df35aa6..60760baee 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java @@ -51,13 +51,13 @@ public ExpressionList getPartitionExpressionList() { return partitionBy.getPartitionExpressionList(); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, + public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + partitionBy.setExpressions(partitionExpressionList, brackets); } public String getWindowName() { diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index f7dbd477f..cab3c5af9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -9,6 +9,10 @@ */ package net.sf.jsqlparser.statement; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Partition; import net.sf.jsqlparser.statement.alter.Alter; import net.sf.jsqlparser.statement.alter.AlterSession; import net.sf.jsqlparser.statement.alter.AlterSystemStatement; @@ -31,10 +35,22 @@ import net.sf.jsqlparser.statement.grant.Grant; import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.InsertConflictAction; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; +import net.sf.jsqlparser.statement.merge.MergeOperationVisitor; +import net.sf.jsqlparser.statement.merge.MergeOperationVisitorAdapter; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; +import net.sf.jsqlparser.statement.select.FromItemVisitor; +import net.sf.jsqlparser.statement.select.FromItemVisitorAdapter; +import net.sf.jsqlparser.statement.select.PivotVisitor; +import net.sf.jsqlparser.statement.select.PivotVisitorAdapter; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectItemVisitor; +import net.sf.jsqlparser.statement.select.SelectItemVisitorAdapter; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.SelectVisitorAdapter; +import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; @@ -42,8 +58,48 @@ import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; +import java.util.List; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class StatementVisitorAdapter implements StatementVisitor { + private final ExpressionVisitor expressionVisitor; + private final PivotVisitor pivotVisitor; + private final SelectItemVisitor selectItemVisitor; + private final FromItemVisitor fromItemVisitor; + private final SelectVisitor selectVisitor; + private final MergeOperationVisitor mergeOperationVisitor; + + public StatementVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); + this.pivotVisitor = new PivotVisitorAdapter<>(this.expressionVisitor); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = new FromItemVisitorAdapter<>(); + + this.selectVisitor = new SelectVisitorAdapter<>(this.expressionVisitor, this.pivotVisitor, + this.selectItemVisitor, this.fromItemVisitor); + this.mergeOperationVisitor = new MergeOperationVisitorAdapter<>(); + } + + public StatementVisitorAdapter(ExpressionVisitor expressionVisitor, + PivotVisitor pivotVisitor, SelectItemVisitor selectItemVisitor, + FromItemVisitor fromItemVisitor, SelectVisitor selectVisitor, + MergeOperationVisitor mergeOperationVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = pivotVisitor; + this.selectItemVisitor = selectItemVisitor; + this.fromItemVisitor = fromItemVisitor; + this.selectVisitor = selectVisitor; + this.mergeOperationVisitor = mergeOperationVisitor; + } + + public StatementVisitorAdapter(SelectVisitorAdapter selectVisitor) { + this.selectVisitor = selectVisitor; + this.expressionVisitor = selectVisitor.getExpressionVisitor(); + this.pivotVisitor = selectVisitor.getPivotVisitor(); + this.selectItemVisitor = selectVisitor.getSelectItemVisitor(); + this.fromItemVisitor = selectVisitor.getFromItemVisitor(); + this.mergeOperationVisitor = new MergeOperationVisitorAdapter<>(); + } @Override public T visit(Comment comment, S context) { @@ -59,19 +115,39 @@ public T visit(Commit commit, S context) { @Override public T visit(Select select, S context) { - - return null; + return select.accept(selectVisitor, context); } @Override public T visit(Delete delete, S context) { + visitWithItems(delete.getWithItemsList(), context); + fromItemVisitor.visitTables(delete.getTables(), context); + selectVisitor.visitOutputClause(delete.getOutputClause(), context); + fromItemVisitor.visitFromItem(delete.getTable(), context); + fromItemVisitor.visitTables(delete.getUsingList(), context); + fromItemVisitor.visitJoins(delete.getJoins(), context); + expressionVisitor.visitExpression(delete.getWhere(), context); + + expressionVisitor.visitPreferringClause(delete.getPreferringClause(), context); + + expressionVisitor.visitOrderBy(delete.getOrderByElements(), context); + + expressionVisitor.visitLimit(delete.getLimit(), context); return null; } + private void visitWithItems(List> withItemsList, S context) { + if (withItemsList != null) { + for (WithItem item : withItemsList) { + item.accept(this, context); + } + } + } + @Override public T visit(ParenthesedDelete delete, S context) { - + delete.getDelete().accept(this, context); return null; } @@ -82,38 +158,94 @@ public T visit(SessionStatement sessionStatement, S context) { @Override public T visit(Update update, S context) { - + visitWithItems(update.getWithItemsList(), context); + fromItemVisitor.visitFromItem(update.getTable(), context); + fromItemVisitor.visitJoins(update.getStartJoins(), context); + expressionVisitor.visitUpdateSets(update.getUpdateSets(), context); + selectVisitor.visitOutputClause(update.getOutputClause(), context); + fromItemVisitor.visitFromItem(update.getFromItem(), context); + fromItemVisitor.visitJoins(update.getJoins(), context); + expressionVisitor.visitExpression(update.getWhere(), context); + expressionVisitor.visitPreferringClause(update.getPreferringClause(), context); + expressionVisitor.visitOrderBy(update.getOrderByElements(), context); + expressionVisitor.visitLimit(update.getLimit(), context); + visitReturningClause(update.getReturningClause(), context); return null; } @Override public T visit(ParenthesedUpdate update, S context) { - - return null; + return update.getUpdate().accept(this, context); } @Override public T visit(Insert insert, S context) { + visitWithItems(insert.getWithItemsList(), context); + + insert.getTable().accept(fromItemVisitor, context); + fromItemVisitor.visitFromItem(insert.getTable(), context); + + if (insert.getColumns() != null) { + for (Column column : insert.getColumns()) { + column.accept(expressionVisitor, context); + } + } + + if (insert.getPartitions() != null) { + for (Partition partition : insert.getPartitions()) { + partition.getColumn().accept(expressionVisitor, context); + if (partition.getValue() != null) { + partition.getValue().accept(expressionVisitor, context); + } + } + } + + selectVisitor.visitOutputClause(insert.getOutputClause(), context); + + if (insert.getSelect() != null) { + insert.getSelect().accept(selectVisitor, null); + } + + expressionVisitor.visitUpdateSets(insert.getSetUpdateSets(), context); + + expressionVisitor.visitUpdateSets(insert.getDuplicateUpdateSets(), context); + + final InsertConflictAction conflictAction = insert.getConflictAction(); + if (conflictAction != null) { + expressionVisitor.visitExpression(conflictAction.getWhereExpression(), context); + expressionVisitor.visitUpdateSets(conflictAction.getUpdateSets(), context); + } + + visitReturningClause(insert.getReturningClause(), context); + return null; + } + + private T visitReturningClause(ReturningClause returningClause, S context) { + returningClause.forEach(selectItem -> selectItem.accept(selectItemVisitor, context)); + // @todo: verify why this is a list of strings and not columns return null; } @Override public T visit(ParenthesedInsert insert, S context) { - + insert.getInsert().accept(this, context); return null; } @Override public T visit(Drop drop, S context) { + if (drop.getType().equalsIgnoreCase("table")) { + fromItemVisitor.visitFromItem(drop.getName(), context); + } + // @todo: handle schemas return null; } @Override public T visit(Truncate truncate, S context) { - - return null; + return truncate.getTable().accept(fromItemVisitor, context); } @Override @@ -129,13 +261,11 @@ public T visit(CreateSchema createSchema, S context) { @Override public T visit(CreateTable createTable, S context) { - - return null; + return createTable.getTable().accept(fromItemVisitor, context); } @Override public T visit(CreateView createView, S context) { - return null; } @@ -173,7 +303,12 @@ public T visit(ResetStatement reset, S context) { @Override public T visit(Merge merge, S context) { - + visitWithItems(merge.getWithItemsList(), context); + fromItemVisitor.visitFromItem(merge.getTable(), context); + fromItemVisitor.visitFromItem(merge.getFromItem(), context); + expressionVisitor.visitExpression(merge.getOnCondition(), context); + mergeOperationVisitor.visit(merge.getOperations(), context); + selectVisitor.visitOutputClause(merge.getOutputClause(), context); return null; } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java index be0d4bb2f..7e33db8b0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java @@ -67,15 +67,15 @@ public String toString() { StringBuilder b = new StringBuilder(); b.append(" WHEN NOT MATCHED"); if (andPredicate != null) { - b.append(" AND ").append(andPredicate.toString()); + b.append(" AND ").append(andPredicate); } b.append(" THEN INSERT "); if (columns != null) { - b.append(columns.toString()); + b.append(columns); } b.append(" VALUES ").append(values.toString()); if (whereCondition != null) { - b.append(" WHERE ").append(whereCondition.toString()); + b.append(" WHERE ").append(whereCondition); } return b.toString(); } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java index fef9682fe..d2439fbd8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.statement.merge; +import java.util.Collection; + public interface MergeOperationVisitor { T visit(MergeDelete mergeDelete, S context); @@ -16,4 +18,11 @@ public interface MergeOperationVisitor { T visit(MergeUpdate mergeUpdate, S context); T visit(MergeInsert mergeInsert, S context); + + default T visit(Collection mergeOperations, S context) { + if (mergeOperations != null) { + mergeOperations.forEach(operation -> operation.accept(this, context)); + } + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java index 546b44604..61ff7a45a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java @@ -9,20 +9,47 @@ */ package net.sf.jsqlparser.statement.merge; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.statement.select.SelectVisitorAdapter; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class MergeOperationVisitorAdapter implements MergeOperationVisitor { + private ExpressionVisitor expressionVisitor; + + public MergeOperationVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); + } + + public MergeOperationVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } + + public MergeOperationVisitorAdapter(SelectVisitorAdapter selectVisitorAdapter) { + this.expressionVisitor = selectVisitorAdapter.getExpressionVisitor(); + } + @Override public T visit(MergeDelete mergeDelete, S context) { + expressionVisitor.visitExpression(mergeDelete.getAndPredicate(), context); return null; } @Override public T visit(MergeUpdate mergeUpdate, S context) { + expressionVisitor.visitExpression(mergeUpdate.getAndPredicate(), context); + expressionVisitor.visitUpdateSets(mergeUpdate.getUpdateSets(), context); + expressionVisitor.visitExpression(mergeUpdate.getWhereCondition(), context); + expressionVisitor.visitExpression(mergeUpdate.getDeleteWhereCondition(), context); return null; } @Override public T visit(MergeInsert mergeInsert, S context) { + expressionVisitor.visitExpression(mergeInsert.getAndPredicate(), context); + expressionVisitor.visitExpressions(mergeInsert.getColumns(), context); + expressionVisitor.visitExpressions(mergeInsert.getValues(), context); + expressionVisitor.visitExpression(mergeInsert.getWhereCondition(), context); return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java index 6949b1e73..ed4432003 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java @@ -13,8 +13,36 @@ import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.piped.FromQuery; +import java.util.Collection; +import java.util.List; + public interface FromItemVisitor { + default T visitFromItem(FromItem fromItem, S context) { + if (fromItem != null) { + fromItem.accept(this, context); + } + return null; + } + + default T visitTables(List tables, S context) { + if (tables != null) { + for (Table table : tables) { + table.accept(this, context); + } + } + return null; + } + + default T visitJoins(Collection joins, S context) { + if (joins != null) { + for (Join join : joins) { + join.getFromItem().accept(this, context); + } + } + return null; + } + T visit(Table tableName, S context); default void visit(Table tableName) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index 583bea5b9..47d6d16c1 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -9,24 +9,34 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.piped.FromQuery; import java.util.ArrayList; +import java.util.Collection; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class FromItemVisitorAdapter implements FromItemVisitor { private SelectVisitor selectVisitor; + private ExpressionVisitor expressionVisitor; - public FromItemVisitorAdapter(SelectVisitor selectVisitor) { + public FromItemVisitorAdapter(SelectVisitor selectVisitor, + ExpressionVisitor expressionVisitor) { this.selectVisitor = selectVisitor; + this.expressionVisitor = expressionVisitor; } public FromItemVisitorAdapter() { this.selectVisitor = new SelectVisitorAdapter<>(); + this.expressionVisitor = new ExpressionVisitorAdapter<>(this.selectVisitor); } + public SelectVisitor getSelectVisitor() { return selectVisitor; } @@ -36,6 +46,35 @@ public FromItemVisitorAdapter setSelectVisitor(SelectVisitor selectVisitor return this; } + public ExpressionVisitor getExpressionVisitor() { + return expressionVisitor; + } + + public FromItemVisitorAdapter setExpressionVisitor(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + return this; + } + + @Override + public T visitJoins(Collection joins, S context) { + if (joins != null) { + for (Join join : joins) { + join.getFromItem().accept(this, context); + if (join.getUsingColumns() != null) { + for (Column column : join.getUsingColumns()) { + column.accept(expressionVisitor, context); + } + } + if (join.getOnExpressions() != null) { + for (Expression expression : join.getOnExpressions()) { + expression.accept(expressionVisitor, context); + } + } + } + } + return null; + } + @Override public T visit(Table table, S context) { return null; @@ -64,6 +103,9 @@ public T visit(ParenthesedFromItem fromItem, S context) { @Override public T visit(Values values, S context) { + for (Expression expression : values.getExpressions()) { + expression.accept(expressionVisitor, context); + } return null; } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java index 94357bcd9..db5ce3175 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java @@ -9,9 +9,24 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.statement.OutputClause; import net.sf.jsqlparser.statement.piped.FromQuery; +import java.util.List; + public interface SelectVisitor { + default T visitWithItems(List> withItemsList, S context) { + if (withItemsList != null) { + for (WithItem withItem : withItemsList) { + withItem.accept(this, context); + } + } + return null; + } + + default T visitOutputClause(OutputClause outputClause, S context) { + return null; + } T visit(ParenthesedSelect parenthesedSelect, S context); diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java index e6fa75086..aa0052c15 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -9,16 +9,11 @@ */ package net.sf.jsqlparser.statement.select; -import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.OutputClause; import net.sf.jsqlparser.statement.piped.FromQuery; -import java.util.List; - @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class SelectVisitorAdapter implements SelectVisitor { private final ExpressionVisitor expressionVisitor; @@ -30,7 +25,7 @@ public SelectVisitorAdapter() { this.expressionVisitor = new ExpressionVisitorAdapter<>(this); this.pivotVisitor = new PivotVisitorAdapter<>(this.expressionVisitor); this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); - this.fromItemVisitor = new FromItemVisitorAdapter<>(this); + this.fromItemVisitor = new FromItemVisitorAdapter<>(this, this.expressionVisitor); } public SelectVisitorAdapter(ExpressionVisitor expressionVisitor, @@ -58,21 +53,50 @@ public SelectVisitorAdapter(ExpressionVisitor expressionVisitor) { } @Override - public T visit(ParenthesedSelect select, S context) { - List> withItemsList = select.getWithItemsList(); - if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { - withItem.accept(this, context); + public T visitOutputClause(OutputClause outputClause, S context) { + if (outputClause != null) { + if (outputClause.getSelectItemList() != null) { + for (SelectItem selectItem : outputClause.getSelectItemList()) { + selectItem.accept(selectItemVisitor, context); + } } + if (outputClause.getTableVariable() != null) { + outputClause.getTableVariable().accept(expressionVisitor, context); + } + if (outputClause.getOutputTable() != null) { + outputClause.getOutputTable().accept(fromItemVisitor, context); + } + // @todo: check why this is a list of strings + // if (outputClause.getColumnList()!=null) { + // for (Column column:outputClause.getColumnList()) + // } } + return null; + } + + public ExpressionVisitor getExpressionVisitor() { + return expressionVisitor; + } + + public PivotVisitor getPivotVisitor() { + return pivotVisitor; + } + + public SelectItemVisitor getSelectItemVisitor() { + return selectItemVisitor; + } + + public FromItemVisitor getFromItemVisitor() { + return fromItemVisitor; + } + + @Override + public T visit(ParenthesedSelect select, S context) { + visitWithItems(select.withItemsList, context); select.getSelect().accept(this, context); - if (select.getOrderByElements() != null) { - for (OrderByElement orderByElement : select.getOrderByElements()) { - orderByElement.getExpression().accept(expressionVisitor); - } - } + expressionVisitor.visitOrderBy(select.getOrderByElements(), context); Pivot pivot = select.getPivot(); if (pivot != null) { @@ -83,14 +107,13 @@ public T visit(ParenthesedSelect select, S context) { unpivot.accept(pivotVisitor, context); } - // if (select.getLimit() != null) { - // //@todo: implement limit visitor - // } + expressionVisitor.visitLimit(select.getLimit(), context); + if (select.getOffset() != null) { - select.getOffset().getOffset().accept(expressionVisitor, null); + expressionVisitor.visitExpression(select.getOffset().getOffset(), null); } - if (select.getFetch() != null && select.getFetch().getExpression() != null) { - select.getFetch().getExpression().accept(expressionVisitor, null); + if (select.getFetch() != null) { + expressionVisitor.visitExpression(select.getFetch().getExpression(), null); } return null; @@ -99,12 +122,7 @@ public T visit(ParenthesedSelect select, S context) { @Override @SuppressWarnings({"PMD.ExcessiveMethodLength"}) public T visit(PlainSelect plainSelect, S context) { - List> withItemsList = plainSelect.getWithItemsList(); - if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { - withItem.accept(this, context); - } - } + visitWithItems(plainSelect.withItemsList, context); if (plainSelect.getDistinct() != null) { for (SelectItem selectItem : plainSelect.getDistinct().getOnSelectItems()) { @@ -120,66 +138,31 @@ public T visit(PlainSelect plainSelect, S context) { selectItem.accept(selectItemVisitor, context); } - if (plainSelect.getIntoTables() != null) { - for (Table table : plainSelect.getIntoTables()) { - table.accept(fromItemVisitor, context); - } - } - - if (plainSelect.getFromItem() != null) { - plainSelect.getFromItem().accept(fromItemVisitor, context); - } + fromItemVisitor.visitTables(plainSelect.getIntoTables(), context); + fromItemVisitor.visitFromItem(plainSelect.getFromItem(), context); // if (plainSelect.getLateralViews() != null) { // //@todo: implement this // } - if (plainSelect.getJoins() != null) { - for (Join join : plainSelect.getJoins()) { - join.getFromItem().accept(fromItemVisitor, context); - for (Expression expression : join.getOnExpressions()) { - expression.accept(expressionVisitor, context); - } - for (Column column : join.getUsingColumns()) { - column.accept(expressionVisitor, context); - } - } - } + fromItemVisitor.visitJoins(plainSelect.getJoins(), context); // if (plainSelect.getKsqlWindow() != null) { // //@todo: implement // } - if (plainSelect.getWhere() != null) { - plainSelect.getWhere().accept(expressionVisitor, context); - } + expressionVisitor.visitExpression(plainSelect.getWhere(), context); // if (plainSelect.getOracleHierarchical() != null) { // //@todo: implement // } // - // if (plainSelect.getPreferringClause() != null) { - // //@todo: implement - // } - if (plainSelect.getGroupBy() != null) { - GroupByElement groupBy = plainSelect.getGroupBy(); - for (Expression expression : groupBy.getGroupByExpressionList()) { - expression.accept(expressionVisitor, context); - } - if (!groupBy.getGroupingSets().isEmpty()) { - for (ExpressionList expressionList : groupBy.getGroupingSets()) { - expressionList.accept(expressionVisitor, context); - } - } - } + expressionVisitor.visitPreferringClause(plainSelect.getPreferringClause(), context); + expressionVisitor.visit(plainSelect.getGroupBy(), context); + expressionVisitor.visitExpression(plainSelect.getHaving(), context); + expressionVisitor.visitExpression(plainSelect.getQualify(), context); - if (plainSelect.getHaving() != null) { - plainSelect.getHaving().accept(expressionVisitor, context); - } - if (plainSelect.getQualify() != null) { - plainSelect.getQualify().accept(expressionVisitor, context); - } // if (plainSelect.getWindowDefinitions() != null) { // //@todo: implement // } @@ -193,11 +176,7 @@ public T visit(PlainSelect plainSelect, S context) { unpivot.accept(pivotVisitor, context); } - if (plainSelect.getOrderByElements() != null) { - for (OrderByElement orderByElement : plainSelect.getOrderByElements()) { - orderByElement.getExpression().accept(expressionVisitor); - } - } + expressionVisitor.visitOrderBy(plainSelect.getOrderByElements(), context); // if (plainSelect.getLimitBy() != null) { // //@todo: implement @@ -206,19 +185,16 @@ public T visit(PlainSelect plainSelect, S context) { // //@todo: implement // } if (plainSelect.getOffset() != null) { - plainSelect.getOffset().getOffset().accept(expressionVisitor, null); + expressionVisitor.visitExpression(plainSelect.getOffset().getOffset(), context); } - if (plainSelect.getFetch() != null && plainSelect.getFetch().getExpression() != null) { - plainSelect.getFetch().getExpression().accept(expressionVisitor, null); + if (plainSelect.getFetch() != null) { + expressionVisitor.visitExpression(plainSelect.getFetch().getExpression(), context); } // if (plainSelect.getForMode() != null) { // //@todo: implement // } - if (plainSelect.getIntoTempTable() != null) { - for (Table t : plainSelect.getIntoTables()) { - t.accept(fromItemVisitor, context); - } - } + + fromItemVisitor.visitFromItem(plainSelect.getIntoTempTable(), context); return null; } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Values.java b/src/main/java/net/sf/jsqlparser/statement/select/Values.java index ee58a9f4a..6cc0e3851 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Values.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Values.java @@ -35,7 +35,7 @@ public Values(ExpressionList expressions, Alias alias) { this.alias = alias; } - public ExpressionList getExpressions() { + public ExpressionList getExpressions() { return expressions; } diff --git a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java index 2f15f3aa2..3fbfe8d96 100644 --- a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java @@ -16,7 +16,6 @@ import net.sf.jsqlparser.statement.create.table.ColDataType; import net.sf.jsqlparser.statement.refresh.RefreshMode; import net.sf.jsqlparser.statement.select.ParenthesedSelect; -import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.util.ReflectionTestUtils; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java index 09ba90dc6..dd0df1fe0 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java @@ -147,11 +147,11 @@ public void shouldDeParseComplexAnalyticExpressionWithPartitionExpressionList() Expression partitionExpression1 = mock(Expression.class); Expression partitionExpression2 = mock(Expression.class); - analyticExpression.setName("name"); - analyticExpression.setPartitionExpressionList(partitionExpressionList); partitionExpressionList.add(partitionExpression1); partitionExpressionList.add(partitionExpression2); + analyticExpression.setName("name"); + analyticExpression.setPartitionExpressionList(partitionExpressionList); will(appendToBuffer("partition expression 1")).given(partitionExpression1) .accept(expressionDeParser, null); will(appendToBuffer("partition expression 2")).given(partitionExpression2) From 7047c187f85fcf17e71401d399edfd4ee5ec544e Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 14 Jun 2025 22:49:58 +0700 Subject: [PATCH 058/123] feat: more useful VisitorAdaptors Signed-off-by: Andreas Reichel --- .../statement/select/FromItemVisitorAdapter.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index 47d6d16c1..783b614f2 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -31,6 +31,11 @@ public FromItemVisitorAdapter(SelectVisitor selectVisitor, this.expressionVisitor = expressionVisitor; } + public FromItemVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.selectVisitor = new SelectVisitorAdapter<>(expressionVisitor); + this.expressionVisitor = expressionVisitor; + } + public FromItemVisitorAdapter() { this.selectVisitor = new SelectVisitorAdapter<>(); this.expressionVisitor = new ExpressionVisitorAdapter<>(this.selectVisitor); @@ -46,6 +51,12 @@ public FromItemVisitorAdapter setSelectVisitor(SelectVisitor selectVisitor return this; } + public FromItemVisitorAdapter setSelectVisitor(SelectVisitorAdapter selectVisitor) { + this.selectVisitor = selectVisitor; + this.expressionVisitor = selectVisitor.getExpressionVisitor(); + return this; + } + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } From dd05e11ae6dbe89333292a662bf0a333603b856f Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 15 Jun 2025 14:50:31 +0700 Subject: [PATCH 059/123] fix: possible NPE Signed-off-by: Andreas Reichel --- .../jsqlparser/expression/ExpressionVisitor.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index 90a1fd96e..8b5ade13d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -124,13 +124,15 @@ default T visitPreferringClause(PreferringClause preferringClause, S context return null; } - default T visitUpdateSets(List insert, S context) { - for (UpdateSet updateSet : insert) { - for (Column column : updateSet.getColumns()) { - column.accept(this, context); - } - for (Expression value : updateSet.getValues()) { - value.accept(this, context); + default T visitUpdateSets(List updateSets, S context) { + if (updateSets != null) { + for (UpdateSet updateSet : updateSets) { + for (Column column : updateSet.getColumns()) { + column.accept(this, context); + } + for (Expression value : updateSet.getValues()) { + value.accept(this, context); + } } } return null; From 915aa35d696b70b207cfcc3ada2ddb470cffd00b Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 15 Jun 2025 15:05:54 +0700 Subject: [PATCH 060/123] fix: possible NPE Signed-off-by: Andreas Reichel --- .../sf/jsqlparser/statement/StatementVisitorAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index cab3c5af9..012abff28 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -221,9 +221,10 @@ public T visit(Insert insert, S context) { } private T visitReturningClause(ReturningClause returningClause, S context) { - returningClause.forEach(selectItem -> selectItem.accept(selectItemVisitor, context)); - // @todo: verify why this is a list of strings and not columns - + if (returningClause!=null) { + returningClause.forEach(selectItem -> selectItem.accept(selectItemVisitor, context)); + // @todo: verify why this is a list of strings and not columns + } return null; } From 7c371718678ee784b9b9aaaeff27ad7c49e206bd Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 15 Jun 2025 18:09:17 +0700 Subject: [PATCH 061/123] feat: syntax sugar Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/schema/Table.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 7938b1f42..b5b4ddefb 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -425,4 +425,44 @@ public Table setResolvedTable(Table resolvedTable) { this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); return this; } + + /** + * Sets a table's catalog and schema only when not set. Useful for setting CURRENT_SCHEMA() and + * CURRENT_DATABASE() + * + * @param currentCatalogName the catalog name + * @param currentSchemaName the schema name + * @return the provided table + */ + public Table setUnsetCatalogAndSchema(String currentCatalogName, String currentSchemaName) { + String databaseName = getDatabaseName(); + if (databaseName == null || databaseName.isEmpty()) { + setDatabaseName(currentCatalogName); + } + + String schemaName = getSchemaName(); + if (schemaName == null || schemaName.isEmpty()) { + setSchemaName(currentSchemaName); + } + return this; + } + + /** + * Sets a tables' catalog and schema only when not set. Useful for setting CURRENT_SCHEMA() and + * CURRENT_DATABASE() + * + * @param currentCatalogName the current catalog name + * @param currentSchemaName the current schema name + * @param tables the tables + * @return the tables + */ + public static Table[] setUnsetCatalogAndSchema(String currentCatalogName, + String currentSchemaName, Table... tables) { + for (Table t : tables) { + if (t != null) { + t.setUnsetCatalogAndSchema(currentCatalogName, currentSchemaName); + } + } + return tables; + } } From 6f4c4fb2dd441e45fba75967f42097c58f0046c8 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 18 Jun 2025 18:07:03 +0700 Subject: [PATCH 062/123] feat: Snowflake time travel syntax Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/schema/Table.java | 52 ++++++- .../util/deparser/SelectDeParser.java | 17 ++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 137 +++++++++++++++++- .../net/sf/jsqlparser/schema/TableTest.java | 16 +- .../statement/select/TimeTravelTest.java | 56 +++++++ 5 files changed, 259 insertions(+), 19 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index b5b4ddefb..87f7d3cd6 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.schema; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -28,11 +29,9 @@ /** * A table. It can have an alias and the schema name it belongs to. */ -public class Table extends ASTNodeAccessImpl implements ErrorDestination, FromItem, MultiPartName { +public class Table extends ASTNodeAccessImpl + implements ErrorDestination, FromItem, MultiPartName, Cloneable { - // private Database database; - // private String schemaName; - // private String name; private static final int NAME_IDX = 0; private static final int SCHEMA_IDX = 1; @@ -45,6 +44,9 @@ public class Table extends ASTNodeAccessImpl implements ErrorDestination, FromIt private List partDelimiters = new ArrayList<>(); + // holds the various `time travel` syntax for BigQuery, RedShift, Snowflake or RedShift + private String timeTravelStr = null; + private Alias alias; private SampleClause sampleClause; @@ -74,6 +76,10 @@ public Table(String name) { setName(name); } + public Table(String name, boolean splitNamesOnDelimiter) { + setName(name, splitNamesOnDelimiter); + } + public Table(String schemaName, String name) { setSchemaName(schemaName); setName(name); @@ -197,12 +203,20 @@ public void setName(String name) { .of("0", "N", "n", "FALSE", "false", "OFF", "off") .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + setName(name, splitNamesOnDelimiter); + } + + public void setName(String name, boolean splitNamesOnDelimiter) { if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) { partItems.clear(); for (String unquotedIdentifier : MultiPartName.unquote(name).split("\\.")) { partItems.add("\"" + unquotedIdentifier + "\""); } Collections.reverse(partItems); + } else if (name.contains(".") && splitNamesOnDelimiter) { + partItems.clear(); + partItems.addAll(Arrays.asList(MultiPartName.unquote(name).split("\\."))); + Collections.reverse(partItems); } else { setIndex(NAME_IDX, name); } @@ -294,6 +308,15 @@ public T accept(IntoTableVisitor intoTableVisitor, S context) { return intoTableVisitor.visit(this, context); } + public String getTimeTravel() { + return timeTravelStr; + } + + public Table setTimeTravel(String timeTravelStr) { + this.timeTravelStr = timeTravelStr; + return this; + } + @Override public Pivot getPivot() { return pivot; @@ -346,6 +369,11 @@ public Table setSampleClause(SampleClause sampleClause) { public StringBuilder appendTo(StringBuilder builder) { builder.append(getFullyQualifiedName()); + + if (timeTravelStr != null) { + builder.append(" ").append(timeTravelStr); + } + if (alias != null) { builder.append(alias); } @@ -422,7 +450,9 @@ public Table getResolvedTable() { */ public Table setResolvedTable(Table resolvedTable) { // clone, not reference - this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); + if (resolvedTable != null) { + this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); + } return this; } @@ -465,4 +495,16 @@ public static Table[] setUnsetCatalogAndSchema(String currentCatalogName, } return tables; } + + @Override + public Table clone() { + try { + Table clone = (Table) super.clone(); + clone.setName(this.getFullyQualifiedName()); + clone.setResolvedTable(this.resolvedTable); + return clone; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index 0ae0cd122..ba62f8476 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -449,25 +449,28 @@ public StringBuilder visit(SelectItem selectItem, S context) { @Override - public StringBuilder visit(Table tableName, S context) { - builder.append(tableName.getFullyQualifiedName()); - Alias alias = tableName.getAlias(); + public StringBuilder visit(Table table, S context) { + builder.append(table.getFullyQualifiedName()); + if (table.getTimeTravel() != null) { + builder.append(" ").append(table.getTimeTravel()); + } + Alias alias = table.getAlias(); if (alias != null) { builder.append(alias); } - Pivot pivot = tableName.getPivot(); + Pivot pivot = table.getPivot(); if (pivot != null) { pivot.accept(this, context); } - UnPivot unpivot = tableName.getUnPivot(); + UnPivot unpivot = table.getUnPivot(); if (unpivot != null) { unpivot.accept(this, context); } - MySQLIndexHint indexHint = tableName.getIndexHint(); + MySQLIndexHint indexHint = table.getIndexHint(); if (indexHint != null) { builder.append(indexHint); } - SQLServerHints sqlServerHints = tableName.getSqlServerHints(); + SQLServerHints sqlServerHints = table.getSqlServerHints(); if (sqlServerHints != null) { builder.append(sqlServerHints); } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index a3f148379..3eb0ff078 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -247,6 +247,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -260,6 +261,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -412,6 +414,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -597,6 +600,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -683,6 +687,8 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | +| +| | | | @@ -3161,7 +3167,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="SYMMETRIC" | 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="UNLIMITED" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | 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="UNLIMITED" | 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; } } @@ -3234,17 +3240,20 @@ Table Table() #TableName : ObjectNames data = null; Token fileNameToken = null; Table table; + String timeTravelStr = null; } { ( - data = RelObjectNames() + data = RelObjectNames() [ LOOKAHEAD(2) timeTravelStr = TimeTravel() ] { table = new Table(data.getNames()); + table.setTimeTravel(timeTravelStr); } | fileNameToken = { - table = new Table(fileNameToken.image); + // don't split name parts + table = new Table(fileNameToken.image, false); } ) @@ -10371,3 +10380,125 @@ TrimFunction TrimFunction(): return new TrimFunction(trimSpecification, expression, fromExpression, usesFrom); } } + +void SnowflakeTimeTravelAt(StringBuilder builder): +{ + Expression expression; + Token tk; +} +{ + // AT( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) + + { builder.append("AT ("); } + ( + //@fixme: this should be TIMESTAMP only but JavaCC-8 has issues with compound tokens! + "=>" expression = Expression() + { builder.append( "TIMESTAMP => ").append(expression.toString()); } + | + "=>" expression = Expression() + { builder.append( "OFFSET => ").append(expression.toString()); } + | + "=>" ( tk=| tk= | tk= ) + { builder.append( "STATEMENT => ").append(tk.image); } + | + "=>" tk= + { builder.append( "STREAM => ").append(tk.image); } + ) + { builder.append(")"); } +} + + +void SnowflakeTimeTravelBefore(StringBuilder builder): +{ + Expression expression; + Token tk; +} +{ + // BEFORE( STATEMENT => ) + + { builder.append("BEFORE ("); } + "=>" ( tk=| tk= | tk= ) + { builder.append( "STATEMENT => ").append(tk.image); } + { builder.append(")"); } +} + +void SnowflakeTimeTravelChange(StringBuilder builder): +{ + Expression expression; + Token tk; +} +{ + /* + CHANGES ( INFORMATION => { DEFAULT | APPEND_ONLY } ) + AT ( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) + | + BEFORE ( STATEMENT => ) + [ END( { TIMESTAMP => | OFFSET => | STATEMENT => } ) ] + */ + + "=>" + { builder.append("CHANGES (INFORMATION => ");} + + ( tk = | tk=) + { builder.append(tk.image); } + + { builder.append(") "); } + + ( + SnowflakeTimeTravelAt(builder) + | + SnowflakeTimeTravelBefore(builder) + ) + + [ + LOOKAHEAD(2) + { builder.append(" END ("); } + + ( + //@fixme: this should be TIMESTAMP only but JavaCC-8 has issues with compound tokens! + "=>" expression = Expression() + { builder.append( "TIMESTAMP => ").append(expression.toString()); } + | + "=>" expression = Expression() + { builder.append( "OFFSET => ").append(expression.toString()); } + | + "=>" ( tk=| tk= | tk= ) + { builder.append( "STATEMENT => ").append(tk.image); } + ) + + { builder.append(")"); } + ] +} + +String TimeTravel(): +{ + StringBuilder builder = new StringBuilder(); +} +{ + + /* Snowflake + + AT( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) + | + BEFORE( STATEMENT => ) + + CHANGES ( INFORMATION => { DEFAULT | APPEND_ONLY } ) + AT ( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) + | + BEFORE ( STATEMENT => ) + [ END( { TIMESTAMP => | OFFSET => | STATEMENT => } ) ] + + */ + + ( + SnowflakeTimeTravelAt(builder) + | + SnowflakeTimeTravelBefore(builder) + | + SnowflakeTimeTravelChange(builder) + ) + + { + return builder.toString(); + } +} diff --git a/src/test/java/net/sf/jsqlparser/schema/TableTest.java b/src/test/java/net/sf/jsqlparser/schema/TableTest.java index 0f9ff2071..0f5a5bf98 100644 --- a/src/test/java/net/sf/jsqlparser/schema/TableTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/TableTest.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.util.deparser.ExpressionDeParser; import net.sf.jsqlparser.util.deparser.SelectDeParser; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.List; @@ -59,10 +60,8 @@ public void tableSetDatabaseIssue812() throws JSQLParserException { SelectDeParser deparser = new SelectDeParser(expressionDeParser, buffer) { @Override - public StringBuilder visit(Table tableName, S parameters) { - System.out.println(tableName); - tableName.setDatabase(database); // Exception - System.out.println(tableName.getDatabase()); + public StringBuilder visit(Table table, S parameters) { + table.setDatabase(database); // Exception return null; } }; @@ -112,4 +111,13 @@ void testBigQueryFullQuotedName() throws JSQLParserException { assertEquals("s", table.getUnquotedSchemaName()); assertEquals("t", table.getUnquotedName()); } + + @Test + void testClone() { + Table t = new Table("a.b.c"); + t.setResolvedTable(t); + + Assertions.assertNotSame(t.clone(), t); + Assertions.assertNotEquals(t.clone(), t); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java new file mode 100644 index 000000000..814885085 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java @@ -0,0 +1,56 @@ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class TimeTravelTest { + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM my_table AT(TIMESTAMP => 'Wed, 26 Jun 2024 09:20:00 -0700'::TIMESTAMP_LTZ);", + "SELECT * FROM my_table AT(OFFSET => -60*5) AS T WHERE T.flag = 'valid';", + "SELECT * FROM my_table AT(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');", + "SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');", + "SELECT oldt.* ,newt.*\n" + + " FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS oldt\n" + + " FULL OUTER JOIN my_table AT(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS newt\n" + + " ON oldt.id = newt.id\n" + + " WHERE oldt.id IS NULL OR newt.id IS NULL;" + }) + void testSnowflakeAtBefore(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT C1\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(TIMESTAMP => CURRENT_TIMESTAMP)\n" + + " END(TIMESTAMP => CURRENT_TIMESTAMP);", + "SELECT *\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(TIMESTAMP => $ts1);", + "CREATE OR REPLACE TABLE t2 (\n" + + " c1 varchar(255) default NULL\n" + + " )\n" + + "AS SELECT C1\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(TIMESTAMP => $ts1)\n" + + " END(TIMESTAMP => $ts2);\n", + "CREATE OR REPLACE TABLE t2 (\n" + + " c1 varchar(255) default NULL\n" + + " )\n" + + "AS SELECT C1\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(STREAM => 's1')\n" + + " END(TIMESTAMP => $ts2);\n" + }) + void testSnowflakeChange(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} From df5e6690ea24485827e8f9c529fb824385bedbe1 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 18 Jun 2025 20:26:22 +0700 Subject: [PATCH 063/123] feat: Databricks `Temporal spec` syntax Signed-off-by: Andreas Reichel --- .../jsqlparser/expression/UserVariable.java | 12 +++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 63 ++++++++++++++++--- .../statement/select/TimeTravelTest.java | 15 +++++ 3 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/UserVariable.java b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java index ece2bd13a..b0599a3c5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/UserVariable.java +++ b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java @@ -24,7 +24,7 @@ public UserVariable() { } public UserVariable(String name) { - this.name = name; + setName(name); } public String getName() { @@ -32,7 +32,15 @@ public String getName() { } public void setName(String name) { - this.name = name; + if (name.startsWith("@@")) { + this.name = name.substring(2); + doubleAdd = true; + } else if (name.startsWith("@")) { + this.name = name.substring(1); + doubleAdd = false; + } else { + this.name = name; + } } @Override diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 3eb0ff078..d386b253e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -231,7 +231,9 @@ SKIP: TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ { - + +| +| | | | @@ -610,6 +612,8 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| +| | | | @@ -661,6 +665,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -782,6 +787,7 @@ TOKEN: | | [ "$" , "#", "_" ] // Not SQL:2016 compliant! > | <#PART_LETTER: | | [ "$" , "#", "_" , "@" ] > +| ()? > // Unicode characters and categories are defined here: https://www.unicode.org/Public/UNIDATA/UnicodeData.txt // SQL:2016 states: @@ -3167,7 +3173,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | 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="UNLIMITED" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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; } } @@ -6568,16 +6574,13 @@ OracleNamedFunctionParameter OracleNamedFunctionParameter() : { } UserVariable UserVariable() : { - UserVariable var = new UserVariable(); + Token tk; String varName; - String var2; } { - ("@" | "@@" { var.setDoubleAdd(true);} ) - varName=IdentifierChain() + tk = varName=IdentifierChain2(tk.image) { - var.setName(varName); - return var; + return new UserVariable(varName); } } @@ -10283,6 +10286,17 @@ String IdentifierChain(): } } +String IdentifierChain2(String identifierChain): +{ + String part; +} +{ + ( LOOKAHEAD(2) "." part=RelObjectNameExt2() { identifierChain += "." + part; } )* + { + return identifierChain; + } +} + Expression CharacterPrimary(): { Expression expression; @@ -10470,6 +10484,37 @@ void SnowflakeTimeTravelChange(StringBuilder builder): ] } +void DataBricksTemporalSpec(StringBuilder builder): +{ + Token tk; + Expression expression; +} +{ + /* + temporal_spec https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-names#syntax-3 + { + @ timestamp_encoding | + @V version | + [ FOR ] { SYSTEM_TIMESTAMP | TIMESTAMP } AS OF timestamp_expression | + [ FOR ] { SYSTEM_VERSION | VERSION } AS OF version + } + */ + (tk= | tk=) { builder.append(tk.image).append(" "); } + (tk= | tk=) { builder.append(tk.image); } + | + [ { builder.append(" FOR"); } ] + + ( tk= | tk= ) + expression=Expression() + { builder.append(" ").append(tk.image).append(" AS OF ").append(expression.toString()); } + | + ( + ( tk= | tk= ) { builder.append(" ").append(tk.image); } + (tk= | tk= ) { builder.append(" AS OF ").append(tk.image); } + ) + +} + String TimeTravel(): { StringBuilder builder = new StringBuilder(); @@ -10496,6 +10541,8 @@ String TimeTravel(): SnowflakeTimeTravelBefore(builder) | SnowflakeTimeTravelChange(builder) + | + DataBricksTemporalSpec(builder) ) { diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java index 814885085..726e4ce49 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java @@ -53,4 +53,19 @@ void testSnowflakeAtBefore(String sqlStr) throws JSQLParserException { void testSnowflakeChange(String sqlStr) throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM delta.`/delta/events` @ 20240618093000000;\n", + "SELECT * FROM delta.`/delta/events` @V 5;\n", + "SELECT * FROM delta.`/delta/events` TIMESTAMP AS OF '2024-06-01T00:00:00';\n", + "SELECT * FROM delta.`/delta/events` VERSION AS OF 3;\n", + "MERGE INTO target_table AS t\n" + + "USING source_table VERSION AS OF 5 AS s\n" + + "ON t.id = s.id\n" + + "WHEN MATCHED THEN UPDATE SET t.value = s.value;\n" + }) + void testDataBricksTemporalSpec(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From 5fa071ef240a82b129d3fb911f7c458f85ae4d42 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 18 Jun 2025 21:05:18 +0700 Subject: [PATCH 064/123] feat: BigQuery `Historic Version` syntax - fixes #1960 - fixes #1640 Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/schema/Table.java | 16 ++++++ .../util/deparser/SelectDeParser.java | 3 ++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 51 ++++++++++++------- .../statement/select/TimeTravelTest.java | 21 ++++++++ 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 87f7d3cd6..784cae709 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -49,6 +49,9 @@ public class Table extends ASTNodeAccessImpl private Alias alias; + // thank you, Google! + private String timeTravelStrAfterAlias = null; + private SampleClause sampleClause; private Pivot pivot; @@ -248,6 +251,15 @@ public void setAlias(Alias alias) { this.alias = alias; } + public String getTimeTravelStrAfterAlias() { + return timeTravelStrAfterAlias; + } + + public Table setTimeTravelStrAfterAlias(String timeTravelStrAfterAlias) { + this.timeTravelStrAfterAlias = timeTravelStrAfterAlias; + return this; + } + private void setIndex(int idx, String value) { int size = partItems.size(); for (int i = 0; i < idx - size + 1; i++) { @@ -378,6 +390,10 @@ public StringBuilder appendTo(StringBuilder builder) { builder.append(alias); } + if (timeTravelStrAfterAlias != null) { + builder.append(" ").append(timeTravelStrAfterAlias); + } + if (sampleClause != null) { sampleClause.appendTo(builder); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index ba62f8476..d0c1040fe 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -458,6 +458,9 @@ public StringBuilder visit(Table table, S context) { if (alias != null) { builder.append(alias); } + if (table.getTimeTravelStrAfterAlias() != null) { + builder.append(" ").append(table.getTimeTravelStrAfterAlias()); + } Pivot pivot = table.getPivot(); if (pivot != null) { pivot.accept(this, context); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d386b253e..ced477308 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -612,6 +612,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -3173,7 +3174,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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; } } @@ -3250,7 +3251,7 @@ Table Table() #TableName : } { ( - data = RelObjectNames() [ LOOKAHEAD(2) timeTravelStr = TimeTravel() ] + data = RelObjectNames() [ LOOKAHEAD(2) timeTravelStr = TimeTravelBeforeAlias() ] { table = new Table(data.getNames()); table.setTimeTravel(timeTravelStr); @@ -4657,6 +4658,8 @@ FromItem FromItem() #FromItem: MySQLIndexHint indexHint = null; SQLServerHints sqlServerHints = null; Select select; + + String timeTravelStr = null; } { ( @@ -4682,6 +4685,10 @@ FromItem FromItem() #FromItem: ) [ LOOKAHEAD(2) alias=Alias() { fromItem.setAlias(alias); } ] + [ + LOOKAHEAD(2, {fromItem instanceof Table }) timeTravelStr = TimeTravelAfterAlias() + { ((Table) fromItem).setTimeTravelStrAfterAlias(timeTravelStr); } + ] [ LOOKAHEAD(2) sampleClause = SampleClause() { fromItem.setSampleClause(sampleClause); } ] [ LOOKAHEAD(2) unpivot=UnPivot() { fromItem.setUnPivot(unpivot); } ] [ LOOKAHEAD(2) ( LOOKAHEAD(2) pivot=PivotXml() | pivot=Pivot() ) { fromItem.setPivot(pivot); } ] @@ -10512,29 +10519,26 @@ void DataBricksTemporalSpec(StringBuilder builder): ( tk= | tk= ) { builder.append(" ").append(tk.image); } (tk= | tk= ) { builder.append(" AS OF ").append(tk.image); } ) - } -String TimeTravel(): +void BigQueryHistoricalVersion(StringBuilder builder): { - StringBuilder builder = new StringBuilder(); + Token tk; + Expression expression; } { - - /* Snowflake - - AT( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) - | - BEFORE( STATEMENT => ) - - CHANGES ( INFORMATION => { DEFAULT | APPEND_ONLY } ) - AT ( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) - | - BEFORE ( STATEMENT => ) - [ END( { TIMESTAMP => | OFFSET => | STATEMENT => } ) ] - + /* + FOR SYSTEM_TIME AS OF timestamp_expression */ + expression=Expression() + { builder.append(" FOR SYSTEM_TIME AS OF ").append(expression.toString()); } +} +String TimeTravelBeforeAlias(): +{ + StringBuilder builder = new StringBuilder(); +} +{ ( SnowflakeTimeTravelAt(builder) | @@ -10549,3 +10553,14 @@ String TimeTravel(): return builder.toString(); } } + +String TimeTravelAfterAlias(): +{ + StringBuilder builder = new StringBuilder(); +} +{ + BigQueryHistoricalVersion(builder) + { + return builder.toString(); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java index 726e4ce49..8f79d9b5d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java @@ -68,4 +68,25 @@ void testSnowflakeChange(String sqlStr) throws JSQLParserException { void testDataBricksTemporalSpec(String sqlStr) throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT *\n" + + "FROM t\n" + + " FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR);\n", + "SELECT *\n" + + "FROM t\n" + + " FOR SYSTEM_TIME AS OF '2017-01-01 10:00:00-07:00';\n", + "SELECT *\n" + + "FROM t1\n" + + "WHERE t1.a IN (SELECT t2.a\n" + + " FROM t2 FOR SYSTEM_TIME AS OF t1.timestamp_column);\n", + "SELECT * FROM books FOR SYSTEM_TIME AS OF before_replace_timestamp;", + "INSERT INTO t1\n" + + "SELECT * FROM t1\n" + + " FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY);\n" + }) + void testBigQueryHistoricVersion(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From 1364fdc6321104ac7b6e5505d5c4bebbbae0d96d Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Thu, 19 Jun 2025 17:12:24 +0700 Subject: [PATCH 065/123] style: generics Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/statement/SetStatementTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java index 3089d3ef1..d2619c50a 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java @@ -67,14 +67,14 @@ public void testValueOnIssue927() throws JSQLParserException { @Test public void testObject() { SetStatement setStatement = new SetStatement(); - setStatement.add("standard_conforming_strings", new ExpressionList(new StringValue("ON")), + setStatement.add("standard_conforming_strings", new ExpressionList<>(new StringValue("ON")), false); setStatement.withUseEqual(0, true).remove(0); assertEquals(0, setStatement.getCount()); setStatement.addKeyValuePairs( - new SetStatement.NameExpr("test", new ExpressionList(new StringValue("1")), false)); + new SetStatement.NameExpr("test", new ExpressionList<>(new StringValue("1")), false)); setStatement.getKeyValuePairs().get(0).setUseEqual(true); assertEquals("test", setStatement.getKeyValuePairs().get(0).getName()); From 12600fb419572050bdc0afba9c312ae4b4756d89 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sat, 21 Jun 2025 04:27:58 +0700 Subject: [PATCH 066/123] fix: avoid NPE Signed-off-by: Andreas Reichel --- src/main/java/net/sf/jsqlparser/schema/Column.java | 3 ++- src/main/java/net/sf/jsqlparser/schema/Table.java | 11 +++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index f0d5e0205..400d34c3a 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -244,7 +244,8 @@ public Table getResolvedTable() { */ public Column setResolvedTable(Table resolvedTable) { // clone, not reference - this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); + this.resolvedTable = + resolvedTable != null ? new Table(resolvedTable.getFullyQualifiedName()) : null; return this; } } diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 784cae709..cd0aa679d 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -514,13 +514,8 @@ public static Table[] setUnsetCatalogAndSchema(String currentCatalogName, @Override public Table clone() { - try { - Table clone = (Table) super.clone(); - clone.setName(this.getFullyQualifiedName()); - clone.setResolvedTable(this.resolvedTable); - return clone; - } catch (CloneNotSupportedException e) { - throw new AssertionError(); - } + Table clone = new Table(this.getFullyQualifiedName()); + clone.setResolvedTable(this.resolvedTable != null ? this.resolvedTable.clone() : null); + return clone; } } From 95ebda5a6112cd79811a63c69ae05be2a8aedc7a Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 9 Jul 2025 17:07:39 +0700 Subject: [PATCH 067/123] fix: return Dollar quoted text as `StringValue` - fixes #2267 Signed-off-by: Andreas Reichel --- .../sf/jsqlparser/expression/StringValue.java | 17 ++++++++++++++++- .../util/deparser/ExpressionDeParser.java | 3 ++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 4 ++-- .../jsqlparser/expression/StringValueTest.java | 10 ++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/StringValue.java b/src/main/java/net/sf/jsqlparser/expression/StringValue.java index ec77f54a9..a16536fab 100644 --- a/src/main/java/net/sf/jsqlparser/expression/StringValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/StringValue.java @@ -24,6 +24,7 @@ public final class StringValue extends ASTNodeAccessImpl implements Expression { Arrays.asList("N", "U", "E", "R", "B", "RB", "_utf8", "Q"); private String value = ""; private String prefix = null; + private String quoteStr = "'"; public StringValue() { // empty constructor @@ -35,6 +36,11 @@ public StringValue(String escapedValue) { && escapedValue.endsWith("'")) { value = escapedValue.substring(1, escapedValue.length() - 1); return; + } else if (escapedValue.length() >= 4 && escapedValue.startsWith("$$") + && escapedValue.endsWith("$$")) { + value = escapedValue.substring(2, escapedValue.length() - 2); + quoteStr = "$$"; + return; } if (escapedValue.length() > 2) { @@ -68,6 +74,15 @@ public void setPrefix(String prefix) { this.prefix = prefix; } + public String getQuoteStr() { + return quoteStr; + } + + public StringValue setQuoteStr(String quoteStr) { + this.quoteStr = quoteStr; + return this; + } + public String getNotExcapedValue() { StringBuilder buffer = new StringBuilder(value); int index = 0; @@ -87,7 +102,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { @Override public String toString() { - return (prefix != null ? prefix : "") + "'" + value + "'"; + return (prefix != null ? prefix : "") + quoteStr + value + quoteStr; } public StringValue withPrefix(String prefix) { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index c37f85688..d517c2303 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -642,7 +642,8 @@ public StringBuilder visit(StringValue stringValue, S context) { if (stringValue.getPrefix() != null) { builder.append(stringValue.getPrefix()); } - builder.append("'").append(stringValue.getValue()).append("'"); + builder.append(stringValue.getQuoteStr()).append(stringValue.getValue()) + .append(stringValue.getQuoteStr()); return builder; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index ced477308..35238b44e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -820,7 +820,7 @@ TOKEN: | < S_CHAR_LITERAL: ( (["U","E","N","R","B"]|"RB"|"_utf8")? ( - ("'" ( | | ~["'", "\\"] )* "'") | ("'" ("''" | ~["'"])* "'") + ("'" ( | | ~["'", "\\"] )* "'") | ("'" ("''" | ~["'"])* "'" | "$$" (~["$"])* "$$") // Alternative Oracle Escape Modes | ("q'{" (~[])* "}'") | ("q'(" (~[])* ")'") @@ -856,7 +856,7 @@ TOKEN: } } } -| < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > +| < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > { if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { diff --git a/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java b/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java index 062f131aa..75f30b365 100644 --- a/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java @@ -10,7 +10,9 @@ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -93,4 +95,12 @@ public void testParseInput_BYTEA() throws Exception { String sqlStr = "VALUES (X'', X'01FF', X'01 bc 2a', X'01' '02')"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDollarQuotesIssue2267() throws JSQLParserException { + String sqlStr = "SELECT $$this is a string$$, test, 'text' FROM tbl;"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(StringValue.class, select.getSelectItem(0).getExpression()); + } } From 173a25fa76db15eb7e795cc1b25c16d7ec3d3ec5 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 9 Jul 2025 17:08:03 +0700 Subject: [PATCH 068/123] test: add an issue related unit test Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/expression/FunctionTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java index 8f3daf474..f977d558d 100644 --- a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java @@ -119,4 +119,11 @@ void testListAggOnOverflow(String sqlStr) throws Exception { void testTrimFunctions(String sqlStr) throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void TestIntervalParameterIssue2272() throws JSQLParserException { + String sqlStr = + "SELECT DATE_SUB('2025-06-19', INTERVAL QUARTER(STR_TO_DATE('20250619', '%Y%m%d')) - 1 QUARTER) from dual"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From 81cdce1a8466a374ffefa6f180cd1aa6e82ff7f3 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 9 Jul 2025 17:08:22 +0700 Subject: [PATCH 069/123] build: try new Maven Central Signed-off-by: Andreas Reichel --- build.gradle | 6 +++--- pom.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 81e277034..682d08dd1 100644 --- a/build.gradle +++ b/build.gradle @@ -529,7 +529,7 @@ publish { publishing { publications { - create("mavenJava", MavenPublication) { + mavenJava(MavenPublication) { artifactId = 'jsqlparser' from components.java @@ -584,8 +584,8 @@ publishing { repositories { maven { name = "ossrh" - def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + def releasesRepoUrl = "https://central.sonatype.com/repository/maven-releases" + def snapshotsRepoUrl = "https://central.sonatype.com/repository/maven-snapshots/" url(version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl) credentials { diff --git a/pom.xml b/pom.xml index 66c619bb0..3ffa4e01b 100644 --- a/pom.xml +++ b/pom.xml @@ -135,11 +135,11 @@ sonatype-nexus-staging - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://central.sonatype.com/repository/maven-releases - sonatype-nexus-snapshots - https://oss.sonatype.org/content/repositories/snapshots/ + sonatype-nexus-snapshots + https://central.sonatype.com/repository/maven-snapshots/ false true From 8f4cdb3b0b665308516e88ac042fd7a2afb07f58 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 9 Jul 2025 17:12:12 +0700 Subject: [PATCH 070/123] test: Token message updates Signed-off-by: Andreas Reichel --- .../statement/select/oracle-tests/analytic_query07.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql | 3 ++- .../statement/select/oracle-tests/cast_multiset38.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/cluster_set01.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/condition11.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/function07.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/interval01.sql | 3 ++- .../jsqlparser/statement/select/oracle-tests/returning01.sql | 3 ++- .../sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql | 3 ++- 9 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql index 67faafd72..328f42a4e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql @@ -48,4 +48,5 @@ order by prob desc, cl_id asc, conf desc, attr asc, val asc --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 +--@FAILURE: Encountered: / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql index faad380c8..6821142a6 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql @@ -16,4 +16,5 @@ from ) --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 +--@FAILURE: Encountered: / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql index e9e74c79c..84086cffc 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql @@ -13,4 +13,5 @@ select * varchar2_ntt('b','c','d') ) --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 11, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 11, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 11, column 18, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql index d6257e880..d2ae24b1e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql @@ -43,4 +43,5 @@ select a.probability prob, a.cluster_id cl_id, order by prob desc, cl_id asc, conf desc, attr asc, val asc --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 31, column 36, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 31, column 36, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 31, column 36, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql index aae684904..2b4866121 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql @@ -16,4 +16,5 @@ and 0 = Lib.SKU(X.sid, nvl(Z.cid, '^')) --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 14, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 14, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 14, column 26, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql index 3035d0e63..aa451e33f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql @@ -16,4 +16,5 @@ select cust_gender, count(*) as cnt, round(avg(age)) as avg_age --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 12, column 20, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 12, column 20, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 12, column 20, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql index b6e4b79ba..df005b047 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql @@ -11,4 +11,5 @@ select (systimestamp - order_date) day(9) to second from orders where order_id = 2458 --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 10, column 39, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 10, column 39, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 10, column 39, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql index db5629134..9747a883c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql @@ -14,4 +14,5 @@ returning empno bulk collect into :empnos --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 12, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 12, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@FAILURE: Encountered: / "(", at line 12, column 18, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:18 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql index da48c0686..3c7e35f56 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql @@ -17,4 +17,5 @@ from warehouses, warehouse2 --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered: "(" / "(", at line 12, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file +--@FAILURE: Encountered: "(" / "(", at line 12, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@FAILURE: Encountered: / "(", at line 12, column 10, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:18 \ No newline at end of file From 6b35e375572c4405b7b56598c31cc5670f5189ae Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 9 Jul 2025 21:22:27 +0700 Subject: [PATCH 071/123] doc: show case how to manipulate select items Signed-off-by: Andreas Reichel --- .../jsqlparser/test/AssortedFeatureTests.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java index 07fdb858b..c0132155f 100644 --- a/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java +++ b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java @@ -10,10 +10,14 @@ package net.sf.jsqlparser.test; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.util.deparser.ExpressionDeParser; import net.sf.jsqlparser.util.deparser.SelectDeParser; import net.sf.jsqlparser.util.deparser.StatementDeParser; @@ -61,4 +65,54 @@ public void testIssue1608() throws JSQLParserException { "INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234')")); System.out.println(cleanStatement("DELETE FROM table1 where col=5 and col2=4")); } + + @Test + void addSelectItemTest() throws JSQLParserException { + String provided = "SELECT col1 FROM WHATEVER"; + String expected = "SELECT col1, Sum(1, 2) AS col2 FROM WHATEVER"; + + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(provided); + + Function f = new Function("Sum", new LongValue(1), new LongValue(2)); + SelectItem i = new SelectItem<>(f, new Alias("col2", true)); + + select + .getSelectItems() + .add(i); + + TestUtils.assertStatementCanBeDeparsedAs(select, expected); + } + + @Test + void removeSelectItemTest() throws JSQLParserException { + String provided = "SELECT col1, Sum(1, 2) AS col2 FROM WHATEVER"; + String expected = "SELECT col1 FROM WHATEVER"; + + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(provided); + + select + .getSelectItems() + .remove(1); + + TestUtils.assertStatementCanBeDeparsedAs(select, expected); + } + + @Test + void sweapSelectItemTest() throws JSQLParserException { + String provided = "SELECT col1 FROM WHATEVER"; + String expected = "SELECT Sum(1, 2) AS col1 FROM WHATEVER"; + + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(provided); + + Function f = new Function("Sum", new LongValue(1), new LongValue(2)); + SelectItem i = new SelectItem<>(f, new Alias("col1", true)); + select + .getSelectItems() + .remove(0); + select + .getSelectItems() + .add(0, i); + + TestUtils.assertStatementCanBeDeparsedAs(select, expected); + } } From afc7bdb26eb53e731f8317083a03a8d72e33a345 Mon Sep 17 00:00:00 2001 From: tw Date: Fri, 11 Jul 2025 01:04:43 +0200 Subject: [PATCH 072/123] added new maven central deployer --- pom.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aa18b41bc..204c95ce4 100644 --- a/pom.xml +++ b/pom.xml @@ -107,6 +107,7 @@ + scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git @@ -449,6 +450,15 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 + true + + sonatype-nexus + + From 50e75d6d64958b3fe48a5f635fbf69d2a585f8db Mon Sep 17 00:00:00 2001 From: tw Date: Fri, 11 Jul 2025 01:38:15 +0200 Subject: [PATCH 073/123] added new maven central deployer --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 653fc0a27..d4ac4e542 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ ossrh-snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots/ true false @@ -132,7 +132,6 @@ - + scm:git:https://github.com/JSQLParser/JSqlParser.git scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git From ce8997de36138002f77e7694315243e4353a2403 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 11 Jul 2025 16:07:25 +0700 Subject: [PATCH 074/123] doc: disable `sphinx-prompt` Signed-off-by: Andreas Reichel --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8201de9d4..a5c4e6d9d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,8 @@ jobs: - name: Install XSLT Processor run: sudo apt-get install xsltproc sphinx-common - name: Install Python dependencies - run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments + #run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments + run: pip install furo myst_parser sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments - name: Build Sphinx documentation with Gradle run: FLOATING_TOC=false ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx - name: Deploy Sphinx documentation From 766b44fd68ed2a1abf551dcc814f90db69a2d6cb Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Fri, 11 Jul 2025 16:13:17 +0700 Subject: [PATCH 075/123] doc: disable `sphinx-prompt` Signed-off-by: Andreas Reichel --- src/site/sphinx/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/sphinx/conf.py b/src/site/sphinx/conf.py index 29ab663cf..99e908d9e 100644 --- a/src/site/sphinx/conf.py +++ b/src/site/sphinx/conf.py @@ -4,7 +4,7 @@ needs_sphinx = '1.0' add_function_parentheses = True -extensions = ['myst_parser', 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'sphinx.ext.extlinks', 'sphinx-prompt', 'sphinx_substitution_extensions', 'sphinx_inline_tabs', 'pygments.sphinxext', ] +extensions = ['myst_parser', 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'sphinx.ext.extlinks', 'sphinx_substitution_extensions', 'sphinx_inline_tabs', 'pygments.sphinxext', ] issues_github_path = "JSQLParser/JSqlParser" From df859f943ef27cfb2b496d3229cbc3a61967bc7f Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 13 Jul 2025 21:01:13 +0700 Subject: [PATCH 076/123] doc: fix Java API site generation Signed-off-by: Andreas Reichel --- build.gradle | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 682d08dd1..427499c6c 100644 --- a/build.gradle +++ b/build.gradle @@ -43,7 +43,7 @@ def getVersion = { boolean considerSnapshot -> commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" }.standardOutput.asText.get().trim() - def pattern = /(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ + def pattern = /jsqlparser-(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ def matcher = versionStr =~ pattern if (matcher.find()) { @@ -110,7 +110,7 @@ dependencies { testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:+' // Java Doc in XML Format - xmlDoclet 'com.manticore-projects.tools:xml-doclet:2.+' + xmlDoclet ('com.manticore-projects.tools:xml-doclet:+'){ changing = true } // enforce latest version of JavaCC testImplementation('org.javacc:core:8.1.0-SNAPSHOT') { changing = true } @@ -174,7 +174,18 @@ jar { } } +sourceSets { + main { + java { + srcDir layout.getBuildDirectory().dir("generated/javacc").get().asFile + srcDir layout.getBuildDirectory().dir("generated/jjtree").get().asFile + } + } +} + tasks.register('xmldoc', Javadoc) { + dependsOn(compileJava) + def outFile = reporting.file( version.endsWith("-SNAPSHOT") ? "xmlDoclet/javadoc_snapshot.xml" @@ -188,23 +199,23 @@ tasks.register('xmldoc', Javadoc) { ) source = sourceSets.main.allJava - include("**/javacc/net/sf/jsqlparser/parser/*.java" ) + classpath = sourceSets.main.runtimeClasspath destinationDir = reporting.file("xmlDoclet") options.docletpath = configurations.xmlDoclet.files as List options.doclet = "com.manticore.tools.xmldoclet.XmlDoclet" title = "API $version" + options.addBooleanOption("rst", true) - options.addBooleanOption("withFloatingToc", Boolean.parseBoolean(System.getenv().getOrDefault("FLOATING_TOC", "true"))) + if (Boolean.parseBoolean(System.getenv().getOrDefault("FLOATING_TOC", "false"))) { + options.addBooleanOption("withFloatingToc","true") + } options.addStringOption("basePackage", "net.sf.jsqlparser") options.addStringOption("filename", outFile.getName()) - dependsOn(compileJava) - doLast { - copy { - from rstFile - into "${projectDir}/src/site/sphinx/" - } + copy { + from rstFile + into layout.projectDirectory.dir("src/site/sphinx/").asFile } } From 8bd86bcda4d59a64d6e40f5862bc364b49e77870 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 13 Jul 2025 21:53:23 +0700 Subject: [PATCH 077/123] doc: fix Java API site generation Signed-off-by: Andreas Reichel --- build.gradle | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 427499c6c..1787c7b60 100644 --- a/build.gradle +++ b/build.gradle @@ -174,17 +174,8 @@ jar { } } -sourceSets { - main { - java { - srcDir layout.getBuildDirectory().dir("generated/javacc").get().asFile - srcDir layout.getBuildDirectory().dir("generated/jjtree").get().asFile - } - } -} - tasks.register('xmldoc', Javadoc) { - dependsOn(compileJava) + dependsOn(compileJavacc) def outFile = reporting.file( version.endsWith("-SNAPSHOT") @@ -199,6 +190,14 @@ tasks.register('xmldoc', Javadoc) { ) source = sourceSets.main.allJava + // add any generated Java sources + source += fileTree(layout.buildDirectory.dir("generated/javacc").get().asFile) { + include '**/*.java' + } + source += fileTree(layout.buildDirectory.dir("generated/jjtree").get().asFile) { + include '**/*.java' + } + classpath = sourceSets.main.runtimeClasspath destinationDir = reporting.file("xmlDoclet") @@ -340,10 +339,15 @@ checkstyle { configFile = rootProject.file('config/checkstyle/checkstyle.xml') } -tasks.named('checkstyleMain') { - source = source.filter { - !it.absolutePath.contains('net/sf/jsqlparser/parser/SimpleCharStream.java') +tasks.withType(Checkstyle).configureEach { + reports { + xml.required = false + html.required = true } + excludes = [ + "**/module-info.java" + , "net/sf/jsqlparser/parser/SimpleCharStream.java" + ] } spotless { @@ -365,13 +369,6 @@ spotless { } } -tasks.withType(Checkstyle).configureEach { - reports { - xml.required = false - html.required = true - } - excludes = [ "**/module-info.java" ] -} tasks.register('renderRR') { dependsOn(compileJavacc) From 0faced63a5e009c66bafb3e77e27ba8ce82926b4 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 13 Jul 2025 22:21:58 +0700 Subject: [PATCH 078/123] doc: fix Java API site generation Signed-off-by: Andreas Reichel --- .github/workflows/ci.yml | 2 +- build.gradle | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5c4e6d9d..8cf7d4c46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: #run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments run: pip install furo myst_parser sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments - name: Build Sphinx documentation with Gradle - run: FLOATING_TOC=false ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx + run: ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx - name: Deploy Sphinx documentation uses: actions/configure-pages@main - name: Upload artifact diff --git a/build.gradle b/build.gradle index 1787c7b60..843119600 100644 --- a/build.gradle +++ b/build.gradle @@ -206,15 +206,17 @@ tasks.register('xmldoc', Javadoc) { title = "API $version" options.addBooleanOption("rst", true) - if (Boolean.parseBoolean(System.getenv().getOrDefault("FLOATING_TOC", "false"))) { - options.addBooleanOption("withFloatingToc","true") + if (Boolean.parseBoolean(System.getProperty("FLOATING_TOC", "true"))) { + options.addBooleanOption("withFloatingToc", true) } options.addStringOption("basePackage", "net.sf.jsqlparser") options.addStringOption("filename", outFile.getName()) - copy { - from rstFile - into layout.projectDirectory.dir("src/site/sphinx/").asFile + doLast { + copy { + from rstFile + into layout.projectDirectory.dir("src/site/sphinx/").asFile + } } } @@ -481,7 +483,7 @@ tasks.register('xslt', SaxonXsltTask) { stylesheet file('src/main/resources/rr/xhtml2rst.xsl') parameters( - "withFloatingToc": System.getenv().getOrDefault("FLOATING_TOC", "true"), + "withFloatingToc": System.getProperty("FLOATING_TOC", "true"), "isSnapshot": Boolean.toString(version.endsWith("-SNAPSHOT")) ) From 88d29b6a299f22f22656cb069d484ace1deed737 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Wed, 16 Jul 2025 16:01:03 +0700 Subject: [PATCH 079/123] chore: update commons-lang3 to address CVE-2025-48924 Signed-off-by: Andreas Reichel --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d4ac4e542..5cdaea540 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ org.apache.commons commons-lang3 - 3.17.0 + [3.18.0,) test From f10e5bdd4fdd31c35676c9600795ccdbf8e33667 Mon Sep 17 00:00:00 2001 From: David Hayes Date: Thu, 31 Jul 2025 14:16:04 +0100 Subject: [PATCH 080/123] Add pluginRepositories to pom.xml (#2284) Adds pluginRepositories to the pom.xml to allow the javacc plugin to not download from insecure repositories (https vs http). Also adds missing copyrights which were added by maven. Co-authored-by: David Hayes --- pom.xml | 16 ++++++++++++++++ .../statement/select/TimeTravelTest.java | 9 +++++++++ .../statement/select/WithItemTest.java | 9 +++++++++ 3 files changed, 34 insertions(+) diff --git a/pom.xml b/pom.xml index 5cdaea540..877cf0c32 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,22 @@ false + + + javacc8-snapshots + + true + + false + https://central.sonatype.com/repository/maven-snapshots/ + + + ossrh-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + true + false + + diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java index 8f79d9b5d..1c7f2eb23 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.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.statement.select; import net.sf.jsqlparser.JSQLParserException; diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java index 99eec0b19..7517b9a36 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.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.statement.select; import net.sf.jsqlparser.JSQLParserException; From 2ff7342dfe41435c9c41656e55b7e95eb97248db Mon Sep 17 00:00:00 2001 From: David Hayes Date: Fri, 1 Aug 2025 10:39:30 +0100 Subject: [PATCH 081/123] Fix[2283] - Fix broken ParserKeywordsUtilsTest (#2286) Javacc java generator was only being included as a pom artefact in test, but the jar is required for the ParserKeywordsUtilsTest to succeed. Co-authored-by: David Hayes --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 877cf0c32..ed03f5feb 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,6 @@ org.javacc.generator java 8.1.0-SNAPSHOT - pom test From f10b52eda68da22de1a72e71fc40d04eb51630cc Mon Sep 17 00:00:00 2001 From: David Hayes Date: Tue, 5 Aug 2025 15:57:46 +0100 Subject: [PATCH 082/123] Fix[2288] - Support parenthesed expressions within Between (#2289) Supports the SQL of the form: ```sql SELECT * FROM tbl WHERE day BETWEEN CAST(CAST((NOW() + INTERVAL '-30 day') AS date) AS timestamptz) AND CAST(CAST((NOW() + INTERVAL '-1 day') AS date) AS timestamptz); ``` Co-authored-by: David Hayes --- src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 8 ++++---- src/test/resources/simple_parsing.txt | 8 +++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 35238b44e..fb9e42c6a 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5746,18 +5746,18 @@ Expression Between(Expression leftExpression) : ) ] ( - LOOKAHEAD( 3 ) betweenExpressionStart = ParenthesedSelect() + LOOKAHEAD( ParenthesedSelect() ) betweenExpressionStart = ParenthesedSelect() | - LOOKAHEAD( 11 ) betweenExpressionStart = RegularCondition() + LOOKAHEAD( RegularCondition() ) betweenExpressionStart = RegularCondition() | betweenExpressionStart = SimpleExpression() ) ( - LOOKAHEAD( 3 ) betweenExpressionEnd = ParenthesedSelect() + LOOKAHEAD( ParenthesedSelect() ) betweenExpressionEnd = ParenthesedSelect() | - LOOKAHEAD( 11 ) betweenExpressionEnd = RegularCondition() + LOOKAHEAD( RegularCondition() ) betweenExpressionEnd = RegularCondition() | betweenExpressionEnd = SimpleExpression() ) diff --git a/src/test/resources/simple_parsing.txt b/src/test/resources/simple_parsing.txt index 40824e8f2..7ae242dfc 100644 --- a/src/test/resources/simple_parsing.txt +++ b/src/test/resources/simple_parsing.txt @@ -210,4 +210,10 @@ AND THIS_EMP.WORKDEPT = DINFO.DEPTNO select * from Person where deptname='it' AND NOT (age=24) -select * from unnest(array[4,5,6]) with ordinality; \ No newline at end of file +select * from unnest(array[4,5,6]) with ordinality; + +SELECT * FROM tbl WHERE +day BETWEEN + CAST(CAST((NOW() + INTERVAL '-30 day') AS date) AS timestamptz) +AND + CAST(CAST((NOW() + INTERVAL '-1 day') AS date) AS timestamptz); \ No newline at end of file From 0e1715e9b07f293dc16fbe6f6d0c7396764e0b87 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 10 Aug 2025 10:28:33 +0700 Subject: [PATCH 083/123] feat: add support for DuckDB `CREATE TABLE` with `STRUCT(..)` columns Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 13 +++++++++++++ .../sf/jsqlparser/statement/select/DuckDBTest.java | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 35238b44e..ea781002e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -8144,6 +8144,19 @@ ColDataType ColDataType(): } { ( + ( + + "(" + ( tk= | tk= ) + colDataType = ColDataType() { argumentsStringList.add( tk.image + " " + colDataType.toString()); } + [ + "," + ( tk= | tk= ) + colDataType = ColDataType() { argumentsStringList.add( tk.image + " " + colDataType.toString()); } + ] + ")" { colDataType = new ColDataType("STRUCT"); } + ) + | LOOKAHEAD(2) ( colDataType = DataType() ) diff --git a/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java b/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java index 2cb4b57fb..aad68683b 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java @@ -25,4 +25,15 @@ void testFileTable() throws JSQLParserException { Assertions.assertEquals("'/tmp/test.parquet'", table.getName()); } + + @Test + void testCreateWithStruct() throws JSQLParserException { + String sqlStr = + "CREATE TABLE starbake.array_test (\n" + + " keys VARCHAR[] NOT NULL,\n" + + " values1 struct( field1 varchar(255), field2 double) NOT NULL,\n" + + " values2 struct( field1 varchar(255), field2 double) NOT NULL\n" + + ");"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From 12489af67cb82dc6263f05c7f3e2759fb9742ecc Mon Sep 17 00:00:00 2001 From: David Hayes Date: Mon, 11 Aug 2025 23:49:52 +0100 Subject: [PATCH 084/123] Fix[2290] - Fix overeager lambda function parsing (#2293) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `SELECT DATE_TRUNC('week',("schema"."tbl"."column" + INTERVAL '1 day')) FROM "schema"."tbl";` is parsing the `("schema"."tbl"."column" + INTERVAL '1 day')` as a LambdaFunction incorrectly, and crashes out. Increasing the lookahead depth by 1 ensures it fails to match on the `->` keyword (I believe), and falls into a simple expression instead. JMH ``` jmh { includes = ['.*JSQLParserBenchmark.*'] warmupIterations = 2 fork = 5 iterations = 5 timeOnIteration = '5s' } ``` After: ``` 33.970 ±(99.9%) 1.773 ms/op [Average] (min, avg, max) = (31.405, 33.970, 37.302), stdev = 2.367 CI (99.9%): [32.197, 35.743] (assumes normal distribution) ``` Before: ``` 34.882 ±(99.9%) 1.923 ms/op [Average] (min, avg, max) = (31.191, 34.882, 37.406), stdev = 2.567 CI (99.9%): [32.959, 36.805] (assumes normal distribution) ``` Co-authored-by: David Hayes --- src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 4 ++-- src/test/resources/simple_parsing.txt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index cf9098a4e..6e2d06197 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5979,7 +5979,7 @@ ExpressionList SimpleExpressionList(): ( LOOKAHEAD(2, {!interrupted} ) "," ( - LOOKAHEAD( 6 ) expr=LambdaExpression() + LOOKAHEAD( 7 ) expr=LambdaExpression() | expr=SimpleExpression() ) @@ -6038,7 +6038,7 @@ ExpressionList ComplexExpressionList(): ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() | - LOOKAHEAD(6) expr=LambdaExpression() + LOOKAHEAD(7) expr=LambdaExpression() | expr=Expression() ) { expressions.add(expr); } diff --git a/src/test/resources/simple_parsing.txt b/src/test/resources/simple_parsing.txt index 7ae242dfc..94259f416 100644 --- a/src/test/resources/simple_parsing.txt +++ b/src/test/resources/simple_parsing.txt @@ -216,4 +216,6 @@ SELECT * FROM tbl WHERE day BETWEEN CAST(CAST((NOW() + INTERVAL '-30 day') AS date) AS timestamptz) AND - CAST(CAST((NOW() + INTERVAL '-1 day') AS date) AS timestamptz); \ No newline at end of file + CAST(CAST((NOW() + INTERVAL '-1 day') AS date) AS timestamptz); + +SELECT DATE_TRUNC('week',("schema"."tbl"."column" + INTERVAL '1 day')) FROM "schema"."tbl"; \ No newline at end of file From 5fe938bc369a83bb9ab1c82aa791f74d01b55a71 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Thu, 21 Aug 2025 08:32:16 +0700 Subject: [PATCH 085/123] feat: `CORRESPONDING` modifier for `SetOperator` Signed-off-by: Andreas Reichel --- .../jsqlparser/statement/select/ExceptOp.java | 38 +++---------- .../statement/select/IntersectOp.java | 37 +++---------- .../jsqlparser/statement/select/MinusOp.java | 37 +++---------- .../statement/select/SetOperation.java | 19 ++++++- .../jsqlparser/statement/select/UnionOp.java | 39 +++---------- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 55 ++++++++++++++----- .../statement/select/SelectTest.java | 11 ++++ .../statement/select/oracle-tests/union06.sql | 3 +- 8 files changed, 107 insertions(+), 132 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java b/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java index a16320822..c38dd140b 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java @@ -13,38 +13,13 @@ public class ExceptOp extends SetOperation { - private boolean distinct; - private boolean all; - public ExceptOp() { - super(SetOperationType.EXCEPT); - } - - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; - } - - public boolean isDistinct() { - return distinct; - } - - public void setDistinct(boolean distinct) { - this.distinct = distinct; + this(""); } - @Override - public String toString() { - String allDistinct = ""; - if (isAll()) { - allDistinct = " ALL"; - } else if (isDistinct()) { - allDistinct = " DISTINCT"; - } - return super.toString() + allDistinct; + public ExceptOp(String modifier) { + super(SetOperationType.EXCEPT); + this.modifier = modifier; } public ExceptOp withDistinct(boolean distinct) { @@ -56,4 +31,9 @@ public ExceptOp withAll(boolean all) { this.setAll(all); return this; } + + public ExceptOp withModifier(String modifier) { + this.modifier = modifier; + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java b/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java index 02233a694..dd027d5ff 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java @@ -13,37 +13,13 @@ public class IntersectOp extends SetOperation { - private boolean distinct; - private boolean all; - public IntersectOp() { - super(SetOperationType.INTERSECT); - } - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; - } - - public boolean isDistinct() { - return distinct; + this(""); } - public void setDistinct(boolean distinct) { - this.distinct = distinct; - } - - @Override - public String toString() { - String allDistinct = ""; - if (isAll()) { - allDistinct = " ALL"; - } else if (isDistinct()) { - allDistinct = " DISTINCT"; - } - return super.toString() + allDistinct; + public IntersectOp(String modifier) { + super(SetOperationType.INTERSECT); + this.modifier = modifier; } public IntersectOp withDistinct(boolean distinct) { @@ -55,4 +31,9 @@ public IntersectOp withAll(boolean all) { this.setAll(all); return this; } + + public IntersectOp withModifier(String modifier) { + this.modifier = modifier; + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java b/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java index e33ce1387..bcd3ff4c6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java @@ -12,37 +12,13 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public class MinusOp extends SetOperation { - private boolean distinct; - private boolean all; - public MinusOp() { - super(SetOperationType.MINUS); - } - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; - } - - public boolean isDistinct() { - return distinct; + this(""); } - public void setDistinct(boolean distinct) { - this.distinct = distinct; - } - - @Override - public String toString() { - String allDistinct = ""; - if (isAll()) { - allDistinct = " ALL"; - } else if (isDistinct()) { - allDistinct = " DISTINCT"; - } - return super.toString() + allDistinct; + public MinusOp(String modifier) { + super(SetOperationType.MINUS); + this.modifier = modifier; } public MinusOp withDistinct(boolean distinct) { @@ -54,4 +30,9 @@ public MinusOp withAll(boolean all) { this.setAll(all); return this; } + + public MinusOp withModifier(String modifier) { + this.modifier = modifier; + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java b/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java index 0600e5957..6c6a5d8d0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java @@ -13,6 +13,23 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public abstract class SetOperation extends ASTNodeAccessImpl { + String modifier = ""; + + public boolean isAll() { + return modifier.contains("ALL"); + } + + public void setAll(boolean all) { + this.modifier = "ALL"; + } + + public boolean isDistinct() { + return modifier.contains("DISTINCT"); + } + + public void setDistinct(boolean distinct) { + this.modifier = "DISTINCT"; + } private SetOperationType type; @@ -22,6 +39,6 @@ public SetOperation(SetOperationType type) { @Override public String toString() { - return type.name(); + return modifier == null || modifier.isEmpty() ? type.name() : type.name() + " " + modifier; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java b/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java index 68271bcd6..00941e14a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java @@ -12,39 +12,13 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public class UnionOp extends SetOperation { - - private boolean distinct; - private boolean all; - public UnionOp() { - super(SetOperationType.UNION); - } - - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; + this(""); } - public boolean isDistinct() { - return distinct; - } - - public void setDistinct(boolean distinct) { - this.distinct = distinct; - } - - @Override - public String toString() { - String allDistinct = ""; - if (isAll()) { - allDistinct = " ALL"; - } else if (isDistinct()) { - allDistinct = " DISTINCT"; - } - return super.toString() + allDistinct; + public UnionOp(String modifier) { + super(SetOperationType.UNION); + this.modifier = modifier; } public UnionOp withDistinct(boolean distinct) { @@ -56,4 +30,9 @@ public UnionOp withAll(boolean all) { this.setAll(all); return this; } + + public UnionOp withModifier(String modifier) { + this.modifier = modifier; + return this; + } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index cf9098a4e..9677b74ad 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -273,6 +273,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -2094,7 +2095,7 @@ SessionStatement SessionStatement(): Token idToken = null; } { - + ( | ) ( actionToken = | @@ -3174,7 +3175,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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; } } @@ -3662,15 +3663,42 @@ LimitPipeOperator LimitPipeOperator(): } } +// see https://manticore-projects.com/SQL2016Parser/syntax_snapshot.html#corresponding-spec String SetOperationModifier(): { - Token token = null; - String modifier = null; + Token tk; + String modifier = ""; + String identifier; } { - ( token= | token= ) { modifier = token.image; } - [ ( { modifier+= " BY NAME"; } ) | ( { modifier+= " STRICT CORRESPONDING"; }) ] - + ( + LOOKAHEAD(2) ( + [ ( tk= | tk="DISTINCT") { modifier+=tk.image; } ] + { modifier+= " BY NAME"; } + [ + "MATCHING" { modifier+= " MATCHING"; } + "(" + identifier = RelObjectNameExt() { modifier+="(" + identifier; } + ("," identifier = RelObjectNameExt() { modifier+=", " + identifier; })* + ")" { modifier+=")"; } + ] + ) + | + ( + [ { modifier+= " STRICT"; } ] + { modifier+= " CORRESPONDING"; } + [ (tk= | tk="DISTINCT") { modifier+=tk.image; } ] + [ + { modifier+= " BY"; }[ (tk= | tk="DISTINCT") { modifier+=tk.image; } ] + "(" + identifier = RelObjectNameExt() { modifier+="(" + identifier; } + ("," identifier = RelObjectNameExt() { modifier+=", " + identifier;})* + ")" { modifier+=")"; } + ] + ) + | + ( tk= | tk= ) { modifier+=tk.image; } + ) { return modifier; } @@ -4159,6 +4187,7 @@ Select SetOperationList(Select select) #SetOperationList: { WithIsolation withIsolation = null; List(); List operations = new ArrayList(); + String modifier = null; } { @@ -4168,24 +4197,20 @@ Select SetOperationList(Select select) #SetOperationList: { ( LOOKAHEAD(2) ( ( - { UnionOp union = new UnionOp(); linkAST(union,jjtThis); operations.add(union); } - [ { union.setAll(true); } | { union.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { UnionOp union = new UnionOp(modifier); linkAST(union,jjtThis); operations.add(union); } ) | ( - { IntersectOp intersect = new IntersectOp(); linkAST(intersect,jjtThis); operations.add(intersect); } - [ { intersect.setAll(true); } | { intersect.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { IntersectOp intersect = new IntersectOp(modifier); linkAST(intersect,jjtThis); operations.add(intersect); } ) | ( - { MinusOp minus = new MinusOp(); linkAST(minus,jjtThis); operations.add(minus); } - [ { minus.setAll(true); } | { minus.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { MinusOp minus = new MinusOp(); linkAST(minus,jjtThis); operations.add(minus); } ) | ( - { ExceptOp except = new ExceptOp(); linkAST(except,jjtThis); operations.add(except); } - [ { except.setAll(true); } | { except.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { ExceptOp except = new ExceptOp(); linkAST(except,jjtThis); operations.add(except); } ) ) 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 1ba1bb4a7..8744d0839 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6407,4 +6407,15 @@ public void testSelectWithSubImport(String sqlStr) throws JSQLParserException { parser -> parser.withDialect(Dialect.EXASOL)); } + @Test + void testSQL2016CorrespondingBy() throws JSQLParserException { + String sqlStr = + "SELECT id, name, dept, salary\n" + + "FROM Employees_US\n" + + "UNION CORRESPONDING BY (id, name, dept)\n" + + "SELECT dept, id, name, country\n" + + "FROM Employees_EU;"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql index c88c42aee..73c100f6d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql @@ -44,4 +44,5 @@ order by 4,3,1 --@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: ((select "x"."r_no","x"."i_id","x"."ind","x"."item",'0' "o" from "x" where("x"."r_no"=:a))union(select "y"."r_no","y"."i_id","y"."ind","y"."item",'0' "o" from "y" where("y"."r_no"=:a)))union((select "y"."r_no","y"."i_id","y"."ind","y"."item",'1' "o" from "y" where("y"."r_no"=:a))union(select "x"."r_no","x"."i_id","x"."ind","x"."item",'1' "o" from "x" where("x"."r_no"=:a)))order by 4,3,1 recorded first on Aug 21, 2025, 7:56:53 AM \ No newline at end of file From 624a768b2eeae67c2ce7fd2100dcfaee1d9dbd44 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 24 Aug 2025 07:40:11 +0700 Subject: [PATCH 086/123] feat: Oracle hierarchical queries to except `Expression` in the operator - fixes #2300 Signed-off-by: Andreas Reichel --- .../expression/ConnectByPriorOperator.java | 23 ++++++++++++++----- .../expression/ConnectByRootOperator.java | 21 +++++++++++++---- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 19 ++++++++++----- .../expression/ConnectByRootOperatorTest.java | 23 +++++++++++++++++++ 4 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java index 98421e2bb..45c2fde6a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java @@ -35,15 +35,26 @@ * @author are */ public class ConnectByPriorOperator extends ASTNodeAccessImpl implements Expression { - private final Column column; + private final Expression expression; + @Deprecated public ConnectByPriorOperator(Column column) { - this.column = Objects.requireNonNull(column, + this.expression = Objects.requireNonNull(column, "The COLUMN of the ConnectByPrior Operator must not be null"); } - public Column getColumn() { - return column; + public ConnectByPriorOperator(Expression column) { + this.expression = Objects.requireNonNull(column, + "The COLUMN of the ConnectByPrior Operator must not be null"); + } + + @Deprecated + public Expression getColumn() { + return getExpression(); + } + + public Expression getExpression() { + return expression; } @Override @@ -52,7 +63,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { } public StringBuilder appendTo(StringBuilder builder) { - builder.append("PRIOR ").append(column); + builder.append("PRIOR ").append(expression); return builder; } @@ -60,4 +71,4 @@ public StringBuilder appendTo(StringBuilder builder) { public String toString() { return appendTo(new StringBuilder()).toString(); } -} \ No newline at end of file +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java index 6942f0787..776dc031e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java @@ -34,15 +34,26 @@ * @author are */ public class ConnectByRootOperator extends ASTNodeAccessImpl implements Expression { - private final Column column; + private final Expression expression; + @Deprecated public ConnectByRootOperator(Column column) { - this.column = Objects.requireNonNull(column, + this.expression = Objects.requireNonNull(column, "The COLUMN of the ConnectByRoot Operator must not be null"); } - public Column getColumn() { - return column; + public ConnectByRootOperator(Expression column) { + this.expression = Objects.requireNonNull(column, + "The EXPRESSION of the ConnectByRoot Operator must not be null"); + } + + @Deprecated + public Expression getColumn() { + return expression; + } + + public Expression getExpression() { + return expression; } @Override @@ -51,7 +62,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { } public StringBuilder appendTo(StringBuilder builder) { - builder.append("CONNECT_BY_ROOT ").append(column); + builder.append("CONNECT_BY_ROOT ").append(expression); return builder; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 17fefe562..69b534654 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -6545,23 +6545,30 @@ Expression PrimaryExpression() #PrimaryExpression: } } +/* https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/hierarchical_query_clause.html + + { CONNECT BY [ NOCYCLE ] condition [ START WITH condition ] + | START WITH condition CONNECT BY [ NOCYCLE ] condition + } + */ + ConnectByRootOperator ConnectByRootOperator() #ConnectByRootOperator: { - Column column; + Expression expression; } { - column = Column() + expression = Expression() { - return new ConnectByRootOperator(column); + return new ConnectByRootOperator(expression); } } ConnectByPriorOperator ConnectByPriorOperator() #ConnectByPriorOperator: { - Column column; + Expression expression; } { - column = Column() + expression = Expression() { - return new ConnectByPriorOperator(column); + return new ConnectByPriorOperator(expression); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java b/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java new file mode 100644 index 000000000..f1c1daaad --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java @@ -0,0 +1,23 @@ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class ConnectByRootOperatorTest { + + @Test + void testCondition() throws JSQLParserException { + //@formatter:off + String sqlStr= + "SELECT EMP_ID, EMP_NAME,\n" + + " \t CONNECT_BY_ROOT (EMP_NAME || '_' || EMP_ID) AS ROOT_MANAGER,\n" + + " \t SYS_CONNECT_BY_PATH(EMP_NAME, ' -> ') AS PATH\n" + + " FROM EMPLOYEES\n" + + " START WITH MANAGER_ID IS NULL\n" + + " CONNECT BY PRIOR EMP_ID = MANAGER_ID"; + //@formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} From 90cc63ff7354261a27be97a776e2a46c36b2781d Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 24 Aug 2025 07:47:22 +0700 Subject: [PATCH 087/123] build: JMH scope `test` - fixes #2285 Signed-off-by: Andreas Reichel --- pom.xml | 1 + .../jsqlparser/expression/ConnectByRootOperatorTest.java | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index ed03f5feb..a9f412955 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,7 @@ org.openjdk.jmh jmh-core 1.37 + test diff --git a/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java b/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java index f1c1daaad..23f4f2d1b 100644 --- a/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.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; From 468aefae04b02043dbb44ad152090e4a73af9136 Mon Sep 17 00:00:00 2001 From: ConanZhang Date: Thu, 28 Aug 2025 20:15:36 +0800 Subject: [PATCH 088/123] support opengauss "on duplicate key update nothing" grammar (#2303) * support opengauss "on duplicate key nothing" grammar * use import single classes instead of wildcard imports in Insert class. * use import single classes instead of wildcard imports in Insert class. * use './gradlew :spotlessApply' adjust code format. --------- Co-authored-by: zhangkenan --- .../statement/insert/ConflictActionType.java | 2 +- .../jsqlparser/statement/insert/Insert.java | 27 +++- .../insert/InsertDuplicateAction.java | 120 ++++++++++++++++++ .../jsqlparser/statement/upsert/Upsert.java | 26 +++- .../util/deparser/InsertDeParser.java | 13 +- .../util/deparser/UpsertDeParser.java | 10 +- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 31 ++++- .../statement/insert/InsertTest.java | 5 + .../statement/upsert/UpsertTest.java | 7 + .../util/deparser/StatementDeParserTest.java | 2 +- 10 files changed, 226 insertions(+), 17 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java b/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java index 69d6532f0..8e82829b4 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java @@ -10,7 +10,7 @@ package net.sf.jsqlparser.statement.insert; public enum ConflictActionType { - DO_NOTHING, DO_UPDATE; + NOTHING, DO_NOTHING, DO_UPDATE; public static ConflictActionType from(String type) { return Enum.valueOf(ConflictActionType.class, type.toUpperCase()); diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java index c2f6faed0..1a750494c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java @@ -52,8 +52,12 @@ public class Insert implements Statement { private OutputClause outputClause; private InsertConflictTarget conflictTarget; private InsertConflictAction conflictAction; + private InsertDuplicateAction duplicateAction; public List getDuplicateUpdateSets() { + if (duplicateAction != null) { + return duplicateAction.getUpdateSets(); + } return duplicateUpdateSets; } @@ -62,7 +66,13 @@ public List getSetUpdateSets() { } public Insert withDuplicateUpdateSets(List duplicateUpdateSets) { - this.duplicateUpdateSets = duplicateUpdateSets; + if (duplicateAction != null) { + duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } else { + duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } return this; } @@ -157,7 +167,8 @@ public boolean isUseSelectBrackets() { @Deprecated public boolean isUseDuplicate() { - return duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty(); + return duplicateAction != null && duplicateAction.getUpdateSets() != null + && !duplicateAction.getUpdateSets().isEmpty(); } public InsertModifierPriority getModifierPriority() { @@ -331,9 +342,9 @@ public String toString() { sql = UpdateSet.appendUpdateSetsTo(sql, setUpdateSets); } - if (duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty()) { + if (duplicateAction != null) { sql.append(" ON DUPLICATE KEY UPDATE "); - sql = UpdateSet.appendUpdateSetsTo(sql, duplicateUpdateSets); + duplicateAction.appendTo(sql); } if (conflictAction != null) { @@ -392,4 +403,12 @@ public Insert addColumns(Collection columns) { collection.addAll(columns); return this.withColumns(collection); } + + public InsertDuplicateAction getDuplicateAction() { + return duplicateAction; + } + + public void setDuplicateAction(InsertDuplicateAction duplicateAction) { + this.duplicateAction = duplicateAction; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java b/src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java new file mode 100644 index 000000000..4a106a6f7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java @@ -0,0 +1,120 @@ +/*- + * #%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.statement.insert; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.update.UpdateSet; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * on duplicate key is one of: + * + * ON DUPLICATE KEY UPDATE NOTHING ON DUPLICATE KEY UPDATE { column_name = { expression | DEFAULT } + * | ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...] + * ) = ( sub-SELECT ) } [, ...] [ WHERE condition ] + * + * @author zhangconan + */ +public class InsertDuplicateAction implements Serializable { + + ConflictActionType conflictActionType; + Expression whereExpression; + private List updateSets; + + public InsertDuplicateAction(ConflictActionType conflictActionType) { + this.conflictActionType = Objects.requireNonNull(conflictActionType, + "The Conflict Action Type is mandatory and must not be Null."); + } + + public List getUpdateSets() { + return updateSets; + } + + public void setUpdateSets(List updateSets) { + this.updateSets = updateSets; + } + + public InsertDuplicateAction withUpdateSets(List updateSets) { + this.setUpdateSets(updateSets); + return this; + } + + public ConflictActionType getConflictActionType() { + return conflictActionType; + } + + public void setConflictActionType(ConflictActionType conflictActionType) { + this.conflictActionType = Objects.requireNonNull(conflictActionType, + "The Conflict Action Type is mandatory and must not be Null."); + } + + public InsertDuplicateAction withConflictActionType(ConflictActionType conflictActionType) { + setConflictActionType(conflictActionType); + return this; + } + + public InsertDuplicateAction addUpdateSet(Column column, Expression expression) { + return this.addUpdateSet(new UpdateSet()); + } + + public InsertDuplicateAction addUpdateSet(UpdateSet updateSet) { + if (updateSets == null) { + updateSets = new ArrayList<>(); + } + this.updateSets.add(updateSet); + return this; + } + + public InsertDuplicateAction withUpdateSets(Collection updateSets) { + this.setUpdateSets(new ArrayList<>(updateSets)); + return this; + } + + public Expression getWhereExpression() { + return whereExpression; + } + + public void setWhereExpression(Expression whereExpression) { + this.whereExpression = whereExpression; + } + + public InsertDuplicateAction withWhereExpression(Expression whereExpression) { + setWhereExpression(whereExpression); + return this; + } + + @SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault") + public StringBuilder appendTo(StringBuilder builder) { + switch (conflictActionType) { + case NOTHING: + builder.append(" NOTHING "); + break; + default: + UpdateSet.appendUpdateSetsTo(builder, updateSets); + + if (whereExpression != null) { + builder.append(" WHERE ").append(whereExpression); + } + break; + } + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java b/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java index 6bb0376b9..c13397569 100644 --- a/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java +++ b/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java @@ -14,6 +14,8 @@ import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.insert.ConflictActionType; +import net.sf.jsqlparser.statement.insert.InsertDuplicateAction; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SetOperationList; @@ -35,6 +37,7 @@ public class Upsert implements Statement { private List duplicateUpdateSets; private UpsertType upsertType = UpsertType.UPSERT; private boolean isUsingInto; + private InsertDuplicateAction duplicateAction; public List getUpdateSets() { return updateSets; @@ -46,11 +49,20 @@ public Upsert setUpdateSets(List updateSets) { } public List getDuplicateUpdateSets() { + if (duplicateAction != null) { + return duplicateAction.getUpdateSets(); + } return duplicateUpdateSets; } public Upsert setDuplicateUpdateSets(List duplicateUpdateSets) { - this.duplicateUpdateSets = duplicateUpdateSets; + if (duplicateAction != null) { + duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } else { + duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } return this; } @@ -181,9 +193,9 @@ public String toString() { } } - if (duplicateUpdateSets != null) { + if (duplicateAction != null) { sb.append(" ON DUPLICATE KEY UPDATE "); - UpdateSet.appendUpdateSetsTo(sb, duplicateUpdateSets); + duplicateAction.appendTo(sb); } return sb.toString(); @@ -219,4 +231,12 @@ public Upsert addColumns(Collection columns) { collection.addAll(columns); return this.withColumns(collection); } + + public InsertDuplicateAction getDuplicateAction() { + return duplicateAction; + } + + public void setDuplicateAction(InsertDuplicateAction duplicateAction) { + this.duplicateAction = duplicateAction; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java index a555f2ba7..58a3018c5 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java @@ -12,6 +12,7 @@ import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Partition; +import net.sf.jsqlparser.statement.insert.ConflictActionType; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectVisitor; @@ -29,8 +30,7 @@ public InsertDeParser() { } public InsertDeParser(ExpressionVisitor expressionVisitor, - SelectVisitor selectVisitor, - StringBuilder buffer) { + SelectVisitor selectVisitor, StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; this.selectVisitor = selectVisitor; @@ -115,9 +115,14 @@ public void deParse(Insert insert) { deparseUpdateSets(insert.getSetUpdateSets(), builder, expressionVisitor); } - if (insert.getDuplicateUpdateSets() != null) { + if (insert.getDuplicateAction() != null) { builder.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor); + if (ConflictActionType.DO_UPDATE + .equals(insert.getDuplicateAction().getConflictActionType())) { + deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor); + } else { + insert.getDuplicateAction().appendTo(builder); + } } // @todo: Accept some Visitors for the involved Expressions diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java index 0835284a4..218ca1db3 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.deparser; import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.statement.insert.ConflictActionType; import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.upsert.Upsert; @@ -78,9 +79,14 @@ public void deParse(Upsert upsert) { upsert.getSelect().accept((SelectVisitor) selectVisitor, null); } - if (upsert.getDuplicateUpdateSets() != null) { + if (upsert.getDuplicateAction() != null) { builder.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor); + if (ConflictActionType.DO_UPDATE + .equals(upsert.getDuplicateAction().getConflictActionType())) { + deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor); + } else { + upsert.getDuplicateAction().appendTo(builder); + } } } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 69b534654..03a86ac56 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2742,6 +2742,8 @@ Insert Insert(): InsertConflictTarget conflictTarget = null; InsertConflictAction conflictAction = null; + + InsertDuplicateAction duplicateAction = null; } { { insert.setOracleHint(getOracleHint()); } @@ -2780,7 +2782,7 @@ Insert Insert(): ) [ LOOKAHEAD(2) - duplicateUpdateSets = UpdateSets() { insert.withDuplicateUpdateSets(duplicateUpdateSets); } + duplicateAction = InsertDuplicateAction() { insert.setDuplicateAction(duplicateAction); } ] [ @@ -2860,6 +2862,30 @@ InsertConflictAction InsertConflictAction(): .withWhereExpression(whereExpression); } } +InsertDuplicateAction InsertDuplicateAction(): +{ + InsertDuplicateAction duplicateAction; + Expression whereExpression = null; + List updateSets; +} +{ + ( + LOOKAHEAD(2) ( + { duplicateAction = new InsertDuplicateAction( ConflictActionType.NOTHING ); } + ) + | + ( + { duplicateAction = new InsertDuplicateAction( ConflictActionType.DO_UPDATE ); } + updateSets = UpdateSets() { duplicateAction.setUpdateSets(updateSets); } + [ whereExpression = WhereClause() ] + ) + ) + + { return duplicateAction + .withWhereExpression(whereExpression); } +} + + OutputClause OutputClause(): { List> selectItemList = null; @@ -2895,6 +2921,7 @@ Upsert Upsert(): Select select = null; List duplicateUpdateSets; + InsertDuplicateAction duplicateAction = null; Token tk = null; } { @@ -2925,7 +2952,7 @@ Upsert Upsert(): [ - duplicateUpdateSets = UpdateSets() { upsert.setDuplicateUpdateSets(duplicateUpdateSets); } + duplicateAction = InsertDuplicateAction() { upsert.setDuplicateAction(duplicateAction); } ] { 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 850fedfd9..95e1d069b 100644 --- a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java @@ -917,4 +917,9 @@ void insertDemo() { insert, "INSERT INTO test VALUES ('A', 'B')"); } + @Test + public void testSimpleDuplicateInsert() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234') ON DUPLICATE KEY update NOTHING"); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java b/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java index 508a2da03..3a01b890d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java @@ -108,6 +108,13 @@ public void testUpsertMultiRowValue() throws JSQLParserException { true); } + @Test + public void testUpsertMultiRowValueDoNothing() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "UPSERT INTO mytable (col1, col2) VALUES (a, b) ON DUPLICATE KEY UPDATE nothing", + true); + } + @Test @Disabled /* not the job of the parser to validate this, it even may be valid eventually */ diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java index 1b129e6a2..23b3927e6 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java @@ -129,7 +129,7 @@ public void shouldUseProvidedDeparsersWhenDeParsingInsert() { then(withItem2).should().accept((SelectVisitor) selectDeParser, null); then(select).should().accept((SelectVisitor) selectDeParser, null); then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); - then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); + then(duplicateUpdateExpression2).should().accept(expressionDeParser, null); } // @Test From 8810c016c3c83ea81aaa4108887570e18a904fa5 Mon Sep 17 00:00:00 2001 From: Sam Sovereign <5209310+ldaIas@users.noreply.github.com> Date: Tue, 2 Sep 2025 18:43:33 -0600 Subject: [PATCH 089/123] feat(parser): allow COLLATE in ORDER BY clauses (issue #2245) (#2277) * add collate parsing and tests for order by * rm unnecessary test * add quoted identifier for "und-x-icu" --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 4 ++- .../statement/select/OrderByCollateTest.java | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 03a86ac56..4bafd388e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5204,9 +5204,11 @@ OrderByElement OrderByElement(): { OrderByElement orderByElement = new OrderByElement(); Expression columnReference = null; + Token collateToken = null; } { columnReference = Expression() + [ LOOKAHEAD() (collateToken= | collateToken=) { columnReference = new CollateExpression(columnReference, collateToken.image); } ] [ LOOKAHEAD(2) ( | ( { orderByElement.setAsc(false); } )) { orderByElement.setAscDescPresent(true); } ] [ LOOKAHEAD(2) [ LOOKAHEAD(2) ( @@ -6503,7 +6505,7 @@ Expression PrimaryExpression() #PrimaryExpression: ) [ - LOOKAHEAD(2) token= { retval = new CollateExpression(retval, token.image); } + LOOKAHEAD(2) (token= | token= | token=) { retval = new CollateExpression(retval, token.image); } ] [ diff --git a/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java b/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java new file mode 100644 index 000000000..6615ce5cc --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java @@ -0,0 +1,33 @@ +package net.sf.jsqlparser.statement.select; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; + +import net.sf.jsqlparser.JSQLParserException; +import org.junit.jupiter.api.Test; + +public class OrderByCollateTest { + + @Test + public void testOrderByWithCollate() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY CAST(a.xyz AS TEXT) COLLATE \"und-x-icu\" ASC NULLS FIRST"; + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testOrderByWithCollateSimple() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY col COLLATE \"C\" ASC"; + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testOrderByWithCollateMultiple() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY col1 COLLATE \"C\" ASC, col2 COLLATE \"POSIX\" DESC"; + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testOrderByWithCollateAndNulls() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY col COLLATE \"C\" DESC NULLS LAST"; + assertSqlCanBeParsedAndDeparsed(sql); + } +} \ No newline at end of file From eeb04004da797c6a0ae93570dd83210cdb0b94b0 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 5 Sep 2025 10:56:21 +0700 Subject: [PATCH 090/123] fix: avoid NPE and expose `modifier` Signed-off-by: Andreas Reichel --- .../sf/jsqlparser/statement/select/SetOperation.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java b/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java index 6c6a5d8d0..4438d7537 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java @@ -13,10 +13,14 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public abstract class SetOperation extends ASTNodeAccessImpl { - String modifier = ""; + String modifier; + + public String getModifier() { + return modifier != null ? modifier : ""; + } public boolean isAll() { - return modifier.contains("ALL"); + return modifier != null && modifier.contains("ALL"); } public void setAll(boolean all) { @@ -24,14 +28,14 @@ public void setAll(boolean all) { } public boolean isDistinct() { - return modifier.contains("DISTINCT"); + return modifier != null && modifier.contains("DISTINCT"); } public void setDistinct(boolean distinct) { this.modifier = "DISTINCT"; } - private SetOperationType type; + private final SetOperationType type; public SetOperation(SetOperationType type) { this.type = type; From 30144e72ab38ccdedf1bd883396adbe1f960aa09 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sat, 6 Sep 2025 07:17:19 +0700 Subject: [PATCH 091/123] feat: enable session with catalog Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 20 ++++++++++++++++--- .../statement/SessionStatementTest.java | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 4bafd388e..afefda2e3 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2093,6 +2093,7 @@ SessionStatement SessionStatement(): { Token actionToken; Token idToken = null; + String id = null; } { ( | ) @@ -2117,12 +2118,25 @@ SessionStatement SessionStatement(): idToken = | idToken = - ) + ) { id = idToken.image; } + + ( + "." + ( + idToken = + | + idToken = + | + idToken = + | + idToken = + ) { id += "." + idToken.image; } + )? ] { - SessionStatement sessionsStatement = idToken!=null - ? new SessionStatement(actionToken.image, idToken.image) + SessionStatement sessionsStatement = id!=null + ? new SessionStatement(actionToken.image, id) : new SessionStatement(actionToken.image); //linkAST(sessionsStatement,jjtThis); diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java index 48c679bb3..7609bfd22 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java @@ -21,7 +21,7 @@ class SessionStatementTest { @ValueSource(strings = { "SESSION START 1234", "SESSION START", "SESSION APPLY 'test'", "SESSION APPLY", "SESSION DROP \"test\"", "SESSION DROP", "SESSION SHOW test", "SESSION SHOW", - "SESSION DESCRIBE 1234", "SESSION DESCRIBE" + "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION APPLY unnamed.session1" }) void testStartSession(String sqlStr) throws JSQLParserException { SessionStatement sessionStatement = From ac46c4346eafcf882517d7cecf747bec9a1c346a Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sat, 6 Sep 2025 07:54:10 +0700 Subject: [PATCH 092/123] feat: `CREATE SCHEMA` with catalog Signed-off-by: Andreas Reichel --- .../statement/create/schema/CreateSchema.java | 17 ++++++++++++++++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 12 +++++++++--- .../statement/SessionStatementTest.java | 2 +- .../create/schema/CreateSchemaTest.java | 6 ++++++ .../sf/jsqlparser/statement/drop/DropTest.java | 1 + .../statement/select/OrderByCollateTest.java | 11 ++++++++++- 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java b/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java index ea4cdc64d..e972c9c30 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java @@ -21,6 +21,7 @@ public class CreateSchema implements Statement { private String authorization; + private String catalogName = null; private String schemaName; private List schemaPath; private List statements = new ArrayList<>(); @@ -59,6 +60,15 @@ public void setAuthorization(String authorization) { this.authorization = authorization; } + public String getCatalogName() { + return catalogName; + } + + public CreateSchema setCatalogName(String catalogName) { + this.catalogName = catalogName; + return this; + } + /** * The name of the schema * @@ -119,7 +129,12 @@ public String toString() { sql += " IF NOT EXISTS"; } if (schemaName != null) { - sql += " " + schemaName; + sql += " "; + + if (catalogName!=null) { + sql += catalogName + "."; + } + sql += schemaName; } if (authorization != null) { sql += " AUTHORIZATION " + authorization; diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index afefda2e3..efd76ea53 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -7866,15 +7866,21 @@ CreateSchema CreateSchema(): CreateTable table = null; CreateView view = null; CreateSchema schema = new CreateSchema(); - //schema.setSchemaName(System.getProperty("user.name")); - //schema.setAuthorization(System.getProperty("user.name")); List schemaPath = null; List statements = new ArrayList(); } { [ LOOKAHEAD(2) { schema.setIfNotExists(true); } ] - [ ( tk= | tk=) { schema.setSchemaName(tk.image); } ] + [ + ( tk= | tk=) { schema.setSchemaName(tk.image); } + + ( + "." { schema.setCatalogName(tk.image); } + ( tk= | tk=) { schema.setSchemaName(tk.image); } + )? + ] + [ (tk= | tk=) { schema.setAuthorization(tk.image); } ] diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java index 7609bfd22..0906924a9 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java @@ -21,7 +21,7 @@ class SessionStatementTest { @ValueSource(strings = { "SESSION START 1234", "SESSION START", "SESSION APPLY 'test'", "SESSION APPLY", "SESSION DROP \"test\"", "SESSION DROP", "SESSION SHOW test", "SESSION SHOW", - "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION APPLY unnamed.session1" + "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION START unnamed.session1" }) void testStartSession(String sqlStr) throws JSQLParserException { SessionStatement sessionStatement = diff --git a/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java b/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java index 5e100d125..0656f015c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java @@ -27,6 +27,12 @@ public void testSimpleCreateSchema() throws JSQLParserException { assertDeparse(new CreateSchema().withSchemaName("myschema"), statement); } + @Test + public void testCreateSchemaWithcatalog() throws JSQLParserException { + String statement = "CREATE SCHEMA unnamed.myschema"; + assertSqlCanBeParsedAndDeparsed(statement); + } + @Test public void testSimpleCreateWithAuth() throws JSQLParserException { String statement = "CREATE SCHEMA myschema AUTHORIZATION myauth"; diff --git a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java index a97eed829..75d4524c7 100644 --- a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java @@ -98,6 +98,7 @@ public void testDropMaterializedView() throws JSQLParserException { @Test public void testDropSchemaIssue855() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("DROP SCHEMA myschema"); + assertSqlCanBeParsedAndDeparsed("DROP SCHEMA unnamed.myschema"); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java b/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java index 6615ce5cc..a599d85f4 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.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.statement.select; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; @@ -30,4 +39,4 @@ public void testOrderByWithCollateAndNulls() throws JSQLParserException { String sql = "SELECT * FROM a ORDER BY col COLLATE \"C\" DESC NULLS LAST"; assertSqlCanBeParsedAndDeparsed(sql); } -} \ No newline at end of file +} From 552019a56e306903003b924a7210ffb9a5d4a18d Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 7 Sep 2025 15:36:18 +0700 Subject: [PATCH 093/123] feat: split catalog and schema Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/schema/Table.java | 39 ++++++++++++++++++- .../net/sf/jsqlparser/schema/TableTest.java | 9 +++++ .../statement/create/CreateTableTest.java | 11 ++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index cd0aa679d..80c0fc3bb 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -170,7 +170,44 @@ public String getUnquotedSchemaName() { } public Table setSchemaName(String schemaName) { - this.setIndex(SCHEMA_IDX, schemaName); + + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + if (MultiPartName.isQuoted(schemaName) && schemaName.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(schemaName).split("\\."); + switch (parts.length) { + case 2: + setIndex(DATABASE_IDX, "\"" + parts[0] + "\""); + setIndex(SCHEMA_IDX, "\"" + parts[1] + "\""); + break; + case 1: + setIndex(SCHEMA_IDX, "\"" + parts[0] + "\""); + break; + default: + throw new RuntimeException("Invalid schema name: " + schemaName); + } + } else if (schemaName.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(schemaName).split("\\."); + switch (parts.length) { + case 2: + setIndex(DATABASE_IDX, parts[0]); + setIndex(SCHEMA_IDX, parts[1]); + break; + case 1: + setIndex(SCHEMA_IDX, parts[0]); + break; + default: + throw new RuntimeException("Invalid schema name: " + schemaName); + } + } else { + this.setIndex(SCHEMA_IDX, schemaName); + } return this; } diff --git a/src/test/java/net/sf/jsqlparser/schema/TableTest.java b/src/test/java/net/sf/jsqlparser/schema/TableTest.java index 0f5a5bf98..fe9cfd7bd 100644 --- a/src/test/java/net/sf/jsqlparser/schema/TableTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/TableTest.java @@ -120,4 +120,13 @@ void testClone() { Assertions.assertNotSame(t.clone(), t); Assertions.assertNotEquals(t.clone(), t); } + + @Test + void testWithSchema() { + Table t = new Table("a"); + t.setSchemaName("UNNAMED.session1"); + + Assertions.assertEquals("UNNAMED", t.getDatabaseName()); + Assertions.assertEquals("session1", t.getSchemaName()); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java index 6b2e67507..b4836c0b6 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java @@ -1073,4 +1073,15 @@ void testUniqueAfterForeignKeyIssue2082() throws JSQLParserException { ", UNIQUE (employee_name));"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testWithCatalog() throws JSQLParserException { + String sqlStr="CREATE TABLE UNNAMED.session1.a (b VARCHAR (1))"; + CreateTable st = (CreateTable) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Table t = st.getTable(); + assertEquals("UNNAMED", t.getCatalogName()); + assertEquals("session1", t.getSchemaName()); + assertEquals("a", t.getUnquotedName()); + } } From 4ff5cc9830ef2e37d0c59c87317f57b95cc97872 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 7 Sep 2025 17:45:59 +0700 Subject: [PATCH 094/123] feat: split catalog and schema Signed-off-by: Andreas Reichel --- src/main/java/net/sf/jsqlparser/schema/Table.java | 7 ++++++- .../statement/create/schema/CreateSchemaTest.java | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 80c0fc3bb..784493283 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -170,6 +170,10 @@ public String getUnquotedSchemaName() { } public Table setSchemaName(String schemaName) { + if (schemaName == null) { + setIndex(SCHEMA_IDX, null); + return this; + } // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair // of quotes @@ -179,7 +183,8 @@ public Table setSchemaName(String schemaName) { .of("0", "N", "n", "FALSE", "false", "OFF", "off") .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); - if (MultiPartName.isQuoted(schemaName) && schemaName.contains(".") && splitNamesOnDelimiter) { + if (MultiPartName.isQuoted(schemaName) && schemaName.contains(".") + && splitNamesOnDelimiter) { String[] parts = MultiPartName.unquote(schemaName).split("\\."); switch (parts.length) { case 2: diff --git a/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java b/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java index 0656f015c..51aec7a84 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java @@ -31,6 +31,9 @@ public void testSimpleCreateSchema() throws JSQLParserException { public void testCreateSchemaWithcatalog() throws JSQLParserException { String statement = "CREATE SCHEMA unnamed.myschema"; assertSqlCanBeParsedAndDeparsed(statement); + + statement = "CREATE SCHEMA unnamed.session1"; + assertSqlCanBeParsedAndDeparsed(statement); } @Test From 55a6c465e49aeb2216262e2b0020cb02f65dd5e6 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Mon, 8 Sep 2025 06:01:24 +0700 Subject: [PATCH 095/123] feat: `SessionStatement` with options Signed-off-by: Andreas Reichel --- .../statement/SessionStatement.java | 69 ++++++++++++++++++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 23 ++++++- .../statement/SessionStatementTest.java | 3 +- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java index 873c18245..a41098b77 100644 --- a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java @@ -9,6 +9,10 @@ */ package net.sf.jsqlparser.statement; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + public class SessionStatement implements Statement { public enum Action { START, APPLY, DROP, SHOW, DESCRIBE; @@ -20,6 +24,7 @@ public static Action from(String flag) { final private Action action; final private String id; + final private LinkedHashMap options = new LinkedHashMap<>(); public SessionStatement(Action action, String id) { this.action = action; @@ -43,6 +48,54 @@ public String getId() { return id; } + public int size() { + return options.size(); + } + + public String putOption(String key, String value) { + return options.put(key.replaceAll("[\"']", "").toLowerCase(), value.toLowerCase()); + } + + public boolean hasOptions() { + return !options.isEmpty(); + } + + public void clearOptions() { + options.clear(); + } + + public boolean removeOption(String key, String value) { + return options.remove(key, value); + } + + public boolean containsOption(String value) { + return options.containsValue(value); + } + + public String removeOption(String key) { + return options.remove(key); + } + + public String getOption(String key) { + return options.get(key); + } + + public Set getOptionKeySet() { + return options.keySet(); + } + + public Set> getOptions() { + return options.entrySet(); + } + + public boolean hasOption(String key) { + return options.containsKey(key); + } + + public String getOptionOrDefault(String key, String defaultValue) { + return options.getOrDefault(key, defaultValue); + } + @Override public T accept(StatementVisitor statementVisitor, S context) { return statementVisitor.visit(this, context); @@ -55,6 +108,20 @@ public void accept(StatementVisitor statementVisitor) { @Override public String toString() { - return "SESSION " + action + " " + (id != null ? id : "") + ";"; + StringBuilder builder = + new StringBuilder("SESSION " + action + " " + (id != null ? id : "")); + if (!options.isEmpty()) { + builder.append(" WITH "); + int i = 0; + for (Map.Entry e : options.entrySet()) { + if (i++ > 0) { + builder.append(", "); + } + builder.append(e.getKey()).append("=").append(e.getValue()); + } + } + builder.append(";"); + + return builder.toString(); } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index efd76ea53..9f691a7a2 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2091,6 +2091,7 @@ DeclareStatement Declare(): { SessionStatement SessionStatement(): { + SessionStatement sessionsStatement; Token actionToken; Token idToken = null; String id = null; @@ -2133,12 +2134,30 @@ SessionStatement SessionStatement(): ) { id += "." + idToken.image; } )? ] - { - SessionStatement sessionsStatement = id!=null + sessionsStatement = id!=null ? new SessionStatement(actionToken.image, id) : new SessionStatement(actionToken.image); + } + + // options + [ + LOOKAHEAD(2) + idToken = + "=" + ( actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = ) + { sessionsStatement.putOption(idToken.image, actionToken.image ); } + + ( + "," + idToken = + "=" + ( actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = ) + { sessionsStatement.putOption(idToken.image, actionToken.image ); } + )* + ] + { //linkAST(sessionsStatement,jjtThis); return sessionsStatement; } diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java index 0906924a9..ebdf9ba88 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java @@ -21,7 +21,8 @@ class SessionStatementTest { @ValueSource(strings = { "SESSION START 1234", "SESSION START", "SESSION APPLY 'test'", "SESSION APPLY", "SESSION DROP \"test\"", "SESSION DROP", "SESSION SHOW test", "SESSION SHOW", - "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION START unnamed.session1" + "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION START unnamed.session1", + "SESSION START unnamed.session1 WITH persist=false,cleanup=on" }) void testStartSession(String sqlStr) throws JSQLParserException { SessionStatement sessionStatement = From 595d4efa32f73b786477e716045c1210b27b0c36 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Mon, 8 Sep 2025 06:07:49 +0700 Subject: [PATCH 096/123] feat: `SessionStatement` with options Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/statement/SessionStatement.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java index a41098b77..161054397 100644 --- a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java @@ -84,7 +84,11 @@ public Set getOptionKeySet() { return options.keySet(); } - public Set> getOptions() { + public Map getOptions() { + return options; + } + + public Set> getOptionEntrySet() { return options.entrySet(); } From 6c98f10f2d83342a00871844bb27361137a94f54 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Mon, 8 Sep 2025 09:21:48 +0700 Subject: [PATCH 097/123] feat: `SessionStatement` with options - allow `KEEP` Signed-off-by: Andreas Reichel --- src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 4 ++-- .../net/sf/jsqlparser/statement/SessionStatementTest.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 9f691a7a2..4a0529f97 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2143,14 +2143,14 @@ SessionStatement SessionStatement(): // options [ LOOKAHEAD(2) - idToken = + ( idToken = | idToken = ) "=" ( actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = ) { sessionsStatement.putOption(idToken.image, actionToken.image ); } ( "," - idToken = + ( idToken = | idToken = ) "=" ( actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = ) { sessionsStatement.putOption(idToken.image, actionToken.image ); } diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java index ebdf9ba88..aabc40745 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java @@ -22,7 +22,8 @@ class SessionStatementTest { "SESSION START 1234", "SESSION START", "SESSION APPLY 'test'", "SESSION APPLY", "SESSION DROP \"test\"", "SESSION DROP", "SESSION SHOW test", "SESSION SHOW", "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION START unnamed.session1", - "SESSION START unnamed.session1 WITH persist=false,cleanup=on" + "SESSION START unnamed.session1 WITH persist=false,cleanup=on", + "SESSION APPLY unnamed.session1 WITH persist=false,keep=true" }) void testStartSession(String sqlStr) throws JSQLParserException { SessionStatement sessionStatement = From 49958b6ba96898f9ffbf20fe4c81642f575ebd6f Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 12 Sep 2025 09:54:07 +0700 Subject: [PATCH 098/123] fix: avoid visiting twice Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/statement/StatementVisitorAdapter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 012abff28..f034c1cbb 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -183,7 +183,6 @@ public T visit(Insert insert, S context) { visitWithItems(insert.getWithItemsList(), context); insert.getTable().accept(fromItemVisitor, context); - fromItemVisitor.visitFromItem(insert.getTable(), context); if (insert.getColumns() != null) { for (Column column : insert.getColumns()) { @@ -221,7 +220,7 @@ public T visit(Insert insert, S context) { } private T visitReturningClause(ReturningClause returningClause, S context) { - if (returningClause!=null) { + if (returningClause != null) { returningClause.forEach(selectItem -> selectItem.accept(selectItemVisitor, context)); // @todo: verify why this is a list of strings and not columns } From 6ce95d54378a2f6017ae746a11031934983bb459 Mon Sep 17 00:00:00 2001 From: David Hayes Date: Sun, 14 Sep 2025 00:29:04 +0100 Subject: [PATCH 099/123] Fix[2306] - Adds support for Trino UDF (#2307) * Fix[2306] - Adds support for Trino UDF Trino SQL allows you to specify User Defined functions in the WITH clause ahead of a statement. This adds support for this type of statement. * Fix[2306] - Adds support for Trino UDF Trino SQL allows you to specify User Defined functions in the WITH clause ahead of a statement. This adds support for this type of statement. --------- Co-authored-by: David Hayes --- .../parser/ParserKeywordsUtils.java | 1 + .../select/WithFunctionDeclaration.java | 107 ++++++++++++++++++ .../select/WithFunctionParameter.java | 59 ++++++++++ .../jsqlparser/statement/select/WithItem.java | 53 ++++++--- .../util/deparser/SelectDeParser.java | 38 ++++--- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 85 +++++++++++--- .../select/WithFunctionDeclarationTest.java | 96 ++++++++++++++++ .../select/WithFunctionParameterTest.java | 43 +++++++ .../statement/select/WithItemTest.java | 21 ++++ src/test/resources/simple_parsing.txt | 26 ++++- 10 files changed, 476 insertions(+), 53 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index bfaa4a647..c9e91b18c 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -124,6 +124,7 @@ public class ParserKeywordsUtils { {"PRIOR", RESTRICTED_ALIAS}, {"PROCEDURE", RESTRICTED_ALIAS}, {"PUBLIC", RESTRICTED_ALIAS}, + {"RETURNS", RESTRICTED_JSQLPARSER}, {"RETURNING", RESTRICTED_JSQLPARSER}, {"RIGHT", RESTRICTED_SQL2016}, {"SAMPLE", RESTRICTED_ALIAS}, diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java new file mode 100644 index 000000000..f842e8282 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java @@ -0,0 +1,107 @@ +/*- + * #%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.statement.select; + +import net.sf.jsqlparser.expression.Expression; + +import java.io.Serializable; +import java.util.List; + +public class WithFunctionDeclaration implements Serializable { + private String functionName; + private List parameters; + private String returnType; + private Expression returnExpression; + + public WithFunctionDeclaration() {} + + public WithFunctionDeclaration(String functionName, List parameters, + String returnType, Expression returnExpression) { + this.functionName = functionName; + this.parameters = parameters; + this.returnType = returnType; + this.returnExpression = returnExpression; + } + + public String getFunctionName() { + return functionName; + } + + public void setFunctionName(String functionName) { + this.functionName = functionName; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public Expression getReturnExpression() { + return returnExpression; + } + + public void setReturnExpression(Expression returnExpression) { + this.returnExpression = returnExpression; + } + + public WithFunctionDeclaration withFunctionName(String functionName) { + this.setFunctionName(functionName); + return this; + } + + public WithFunctionDeclaration withParameters(List parameters) { + this.setParameters(parameters); + return this; + } + + public WithFunctionDeclaration withReturnType(String returnType) { + this.setReturnType(returnType); + return this; + } + + public WithFunctionDeclaration withReturnExpression(Expression returnExpression) { + this.setReturnExpression(returnExpression); + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder + .append("FUNCTION ") + .append(functionName) + .append("("); + for (int i = 0; parameters != null && i < parameters.size(); i++) { + if (i > 0) { + builder.append(", "); + } + parameters.get(i).appendTo(builder); + } + return builder + .append(") RETURNS ") + .append(returnType) + .append(" RETURN ") + .append(returnExpression); + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java new file mode 100644 index 000000000..aeef044f5 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java @@ -0,0 +1,59 @@ +/*- + * #%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.statement.select; + +import java.io.Serializable; + +public class WithFunctionParameter implements Serializable { + private String name; + private String type; // e.g., INT + + public WithFunctionParameter() {} + + public WithFunctionParameter(String name, String type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public WithFunctionParameter withName(String name) { + this.name = name; + return this; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public WithFunctionParameter withType(String type) { + this.type = type; + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + return builder.append(name).append(" ").append(type); + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java index d40264815..db633b2d2 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java @@ -27,6 +27,7 @@ public class WithItem implements Serializable { private K statement; private Alias alias; private List> withItemList; + private WithFunctionDeclaration withFunctionDeclaration; private boolean recursive = false; private boolean usingNot = false; private boolean materialized = false; @@ -121,28 +122,46 @@ public void setWithItemList(List> withItemList) { this.withItemList = withItemList; } + public WithFunctionDeclaration getWithFunctionDeclaration() { + return withFunctionDeclaration; + } + + public void setWithFunctionDeclaration(WithFunctionDeclaration withFunctionDeclaration) { + this.withFunctionDeclaration = withFunctionDeclaration; + } + + public WithItem withWithFunctionDeclaration( + WithFunctionDeclaration withFunctionDeclaration) { + this.setWithFunctionDeclaration(withFunctionDeclaration); + return this; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append(recursive ? "RECURSIVE " : ""); - if (alias != null) { - builder.append(alias.getName()); - } - if (withItemList != null) { - builder.append("("); - int size = withItemList.size(); - for (int i = 0; i < size; i++) { - builder.append(withItemList.get(i)).append(i < size - 1 ? "," : ""); + if (withFunctionDeclaration != null) { + builder.append(withFunctionDeclaration); + } else { + builder.append(recursive ? "RECURSIVE " : ""); + if (alias != null) { + builder.append(alias.getName()); } - builder.append(")"); - } - builder.append(" AS "); - if (materialized) { - builder.append(usingNot - ? "NOT MATERIALIZED " - : "MATERIALIZED "); + if (withItemList != null) { + builder.append("("); + int size = withItemList.size(); + for (int i = 0; i < size; i++) { + builder.append(withItemList.get(i)).append(i < size - 1 ? "," : ""); + } + builder.append(")"); + } + builder.append(" AS "); + if (materialized) { + builder.append(usingNot + ? "NOT MATERIALIZED " + : "MATERIALIZED "); + } + builder.append(statement); } - builder.append(statement); return builder.toString(); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index d0c1040fe..e36e1038a 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -717,23 +717,27 @@ public StringBuilder visit(SetOperationList list, S context) { @Override public StringBuilder visit(WithItem withItem, S context) { - if (withItem.isRecursive()) { - builder.append("RECURSIVE "); - } - builder.append(withItem.getAlias().getName()); - if (withItem.getWithItemList() != null) { - builder.append(" ") - .append(PlainSelect.getStringList(withItem.getWithItemList(), true, true)); - } - builder.append(" AS "); - if (withItem.isMaterialized()) { - builder.append(withItem.isUsingNot() - ? "NOT MATERIALIZED " - : "MATERIALIZED "); - } - StatementDeParser statementDeParser = - new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder); - statementDeParser.deParse(withItem.getParenthesedStatement()); + if (withItem.getWithFunctionDeclaration() == null) { + if (withItem.isRecursive()) { + builder.append("RECURSIVE "); + } + builder.append(withItem.getAlias().getName()); + if (withItem.getWithItemList() != null) { + builder.append(" ") + .append(PlainSelect.getStringList(withItem.getWithItemList(), true, true)); + } + builder.append(" AS "); + if (withItem.isMaterialized()) { + builder.append(withItem.isUsingNot() + ? "NOT MATERIALIZED " + : "MATERIALIZED "); + } + StatementDeParser statementDeParser = + new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder); + statementDeParser.deParse(withItem.getParenthesedStatement()); + } else { + builder.append(withItem.getWithFunctionDeclaration().toString()); + } return builder; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 4a0529f97..ed708ea99 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -570,6 +570,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -4336,33 +4337,81 @@ WithItem WithItem() #WithItem: boolean recursive = false; boolean materialized = false; boolean usingNot = false; - String name; + String name = null; List> selectItems = null; - ParenthesedStatement statement; + WithFunctionDeclaration withFunctionDeclaration = null; + ParenthesedStatement statement = null; + WithItem withItem; } { - [ LOOKAHEAD(2) { recursive = true; } ] - name=RelObjectName() - [ "(" selectItems=SelectItemsList() ")" ] - - [ LOOKAHEAD(2) [ { usingNot = true; } ] { materialized = true; } ] - ( - LOOKAHEAD(2) statement = ParenthesedSelect() - | - LOOKAHEAD(2) statement = ParenthesedInsert() - | - LOOKAHEAD(2) statement = ParenthesedUpdate() + ( + LOOKAHEAD(2) + withFunctionDeclaration = WithFunctionDeclaration() + { + withItem = new WithItem().withWithFunctionDeclaration(withFunctionDeclaration); + } | - LOOKAHEAD(2) statement = ParenthesedDelete() + ( + [ LOOKAHEAD(2) { recursive = true; } ] + name=RelObjectName() + [ "(" selectItems=SelectItemsList() ")" ] + + [ LOOKAHEAD(2) [ { usingNot = true; } ] { materialized = true; } ] + ( + LOOKAHEAD(2) statement = ParenthesedSelect() + | + LOOKAHEAD(2) statement = ParenthesedInsert() + | + LOOKAHEAD(2) statement = ParenthesedUpdate() + | + LOOKAHEAD(2) statement = ParenthesedDelete() + ) + { + withItem = new WithItem(statement, new Alias(name, false)) + .withRecursive(recursive, usingNot, materialized) + .withWithItemList(selectItems); + } + ) ) { - WithItem withItem = new WithItem(statement, new Alias(name, false)); - return withItem - .withRecursive(recursive, usingNot, materialized) - .withWithItemList(selectItems); + return withItem; } } +WithFunctionDeclaration WithFunctionDeclaration() #WithFunctionDeclaration: +{ + String functionName; + List parameters = new ArrayList(); + String returnType; + Expression returnExpression; + WithFunctionParameter parameter; +} +{ + functionName = RelObjectName() + "(" + [ parameter=WithFunctionParameter() { parameters.add(parameter); } + ( "," parameter=WithFunctionParameter() { parameters.add(parameter); } )* + ] + ")" + returnType = RelObjectName() + returnExpression = Expression() + { + return new WithFunctionDeclaration(functionName, parameters, returnType, returnExpression); + } +} + +WithFunctionParameter WithFunctionParameter() #WithFunctionParameter: +{ + String name; + String type; +} +{ + name = RelObjectName() type = RelObjectName() + { + return new WithFunctionParameter(name, type); + } +} + List> ColumnSelectItemsList(): { List> selectItemsList = null; diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java new file mode 100644 index 000000000..81e4c16fb --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java @@ -0,0 +1,96 @@ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.expression.Expression; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class WithFunctionDeclarationTest { + static final String FUNCTION_NAME = "func1"; + static final String RETURN_TYPE = "integer"; + + @Mock + Expression expression; + @Mock + WithFunctionParameter withFunctionParameter1; + @Mock + WithFunctionParameter withFunctionParameter2; + + WithFunctionDeclaration withFunctionDeclaration; + + @Test + void fullConstructorAndGetters() { + withFunctionDeclaration = new WithFunctionDeclaration(FUNCTION_NAME, + List.of(withFunctionParameter1, withFunctionParameter2), RETURN_TYPE, expression); + assertThat(withFunctionDeclaration.getFunctionName()).isEqualTo(FUNCTION_NAME); + assertThat(withFunctionDeclaration.getParameters()) + .isEqualTo(List.of(withFunctionParameter1, withFunctionParameter2)); + assertThat(withFunctionDeclaration.getReturnType()).isEqualTo(RETURN_TYPE); + assertThat(withFunctionDeclaration.getReturnExpression()).isEqualTo(expression); + } + + @Test + void defaultConstructorAndSetters() { + withFunctionDeclaration = new WithFunctionDeclaration(); + withFunctionDeclaration.setFunctionName(FUNCTION_NAME); + withFunctionDeclaration + .setParameters(List.of(withFunctionParameter1, withFunctionParameter2)); + withFunctionDeclaration.setReturnType(RETURN_TYPE); + withFunctionDeclaration.setReturnExpression(expression); + assertThat(withFunctionDeclaration.getFunctionName()).isEqualTo(FUNCTION_NAME); + assertThat(withFunctionDeclaration.getParameters()) + .isEqualTo(List.of(withFunctionParameter1, withFunctionParameter2)); + assertThat(withFunctionDeclaration.getReturnType()).isEqualTo(RETURN_TYPE); + assertThat(withFunctionDeclaration.getReturnExpression()).isEqualTo(expression); + } + + @Test + void defaultConstructorAndWithers() { + withFunctionDeclaration = new WithFunctionDeclaration() + .withFunctionName(FUNCTION_NAME) + .withParameters(List.of(withFunctionParameter1, withFunctionParameter2)) + .withReturnType(RETURN_TYPE) + .withReturnExpression(expression); + assertThat(withFunctionDeclaration.getFunctionName()).isEqualTo(FUNCTION_NAME); + assertThat(withFunctionDeclaration.getParameters()) + .isEqualTo(List.of(withFunctionParameter1, withFunctionParameter2)); + assertThat(withFunctionDeclaration.getReturnType()).isEqualTo(RETURN_TYPE); + assertThat(withFunctionDeclaration.getReturnExpression()).isEqualTo(expression); + } + + @Test + void toStringTestWithParameters() { + when(withFunctionParameter1.appendTo(any(StringBuilder.class))).thenAnswer(invocation -> { + StringBuilder builder = invocation.getArgument(0); + return builder.append("param1 bigint"); + }); + when(withFunctionParameter2.appendTo(any(StringBuilder.class))).thenAnswer(invocation -> { + StringBuilder builder = invocation.getArgument(0); + return builder.append("param2 double"); + }); + when(expression.toString()).thenReturn("1 + 1"); + withFunctionDeclaration = new WithFunctionDeclaration(FUNCTION_NAME, + List.of(withFunctionParameter1, withFunctionParameter2), RETURN_TYPE, expression); + + assertThat(withFunctionDeclaration.toString()).isEqualTo( + "FUNCTION func1(param1 bigint, param2 double) RETURNS integer RETURN 1 + 1"); + } + + @Test + void toStringTestWithNoParameters() { + when(expression.toString()).thenReturn("1 + 1"); + withFunctionDeclaration = + new WithFunctionDeclaration(FUNCTION_NAME, List.of(), RETURN_TYPE, expression); + + assertThat(withFunctionDeclaration.toString()) + .isEqualTo("FUNCTION func1() RETURNS integer RETURN 1 + 1"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java new file mode 100644 index 000000000..bd632ed1d --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java @@ -0,0 +1,43 @@ +package net.sf.jsqlparser.statement.select; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class WithFunctionParameterTest { + static final String PARAMETER_NAME = "param1"; + static final String PARAMETER_TYPE = "integer"; + + WithFunctionParameter withFunctionParameter; + + @Test + void fullConstructorAndGetters() { + withFunctionParameter = new WithFunctionParameter(PARAMETER_NAME, PARAMETER_TYPE); + assertThat(withFunctionParameter.getName()).isEqualTo(PARAMETER_NAME); + assertThat(withFunctionParameter.getType()).isEqualTo(PARAMETER_TYPE); + } + + @Test + void defaultConstructorAndSetters() { + withFunctionParameter = new WithFunctionParameter(); + withFunctionParameter.setName(PARAMETER_NAME); + withFunctionParameter.setType(PARAMETER_TYPE); + assertThat(withFunctionParameter.getName()).isEqualTo(PARAMETER_NAME); + assertThat(withFunctionParameter.getType()).isEqualTo(PARAMETER_TYPE); + } + + @Test + void defaultConstructorAndWithers() { + withFunctionParameter = new WithFunctionParameter() + .withName(PARAMETER_NAME) + .withType(PARAMETER_TYPE); + assertThat(withFunctionParameter.getName()).isEqualTo(PARAMETER_NAME); + assertThat(withFunctionParameter.getType()).isEqualTo(PARAMETER_TYPE); + } + + @Test + void testToString() { + withFunctionParameter = new WithFunctionParameter(PARAMETER_NAME, PARAMETER_TYPE); + assertThat(withFunctionParameter.toString()).isEqualTo("param1 integer"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java index 7517b9a36..0e8f9e546 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java @@ -12,6 +12,8 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class WithItemTest { @@ -26,4 +28,23 @@ void testNotMaterializedIssue2251() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @ParameterizedTest + @ValueSource(strings = { + "WITH\n" + + " FUNCTION doubleup(x integer)\n" + + " RETURNS integer\n" + + " RETURN x * 2\n" + + "SELECT doubleup(21);\n", + "WITH\n" + + " FUNCTION doubleup(x integer)\n" + + " RETURNS integer\n" + + " RETURN x * 2,\n" + + " FUNCTION doubleupplusone(x integer)\n" + + " RETURNS integer\n" + + " RETURN doubleup(x) + 1\n" + + "SELECT doubleupplusone(21);" + }) + void testWithFunction(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/resources/simple_parsing.txt b/src/test/resources/simple_parsing.txt index 94259f416..657d43789 100644 --- a/src/test/resources/simple_parsing.txt +++ b/src/test/resources/simple_parsing.txt @@ -218,4 +218,28 @@ day BETWEEN AND CAST(CAST((NOW() + INTERVAL '-1 day') AS date) AS timestamptz); -SELECT DATE_TRUNC('week',("schema"."tbl"."column" + INTERVAL '1 day')) FROM "schema"."tbl"; \ No newline at end of file +SELECT DATE_TRUNC('week',("schema"."tbl"."column" + INTERVAL '1 day')) FROM "schema"."tbl"; + +WITH + FUNCTION doubleup(x integer) + RETURNS integer + RETURN x * 2 +SELECT doubleup(21); + +WITH + FUNCTION doubleup(x integer) + RETURNS integer + RETURN x * 2, + FUNCTION doubleupplusone(x integer) + RETURNS integer + RETURN doubleup(x) + 1 +SELECT doubleupplusone(21); + +WITH + FUNCTION hello(name varchar) + RETURNS varchar + RETURN format('Hello %s!', 'name'), + FUNCTION bye(name varchar) + RETURNS varchar + RETURN format('Bye %s!', 'name') +SELECT hello('Finn') || ' and ' || bye('Joe'); \ No newline at end of file From 9dfa0d68af7abd34771292f2fb7aaca96d8254fd Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 14 Sep 2025 07:48:20 +0700 Subject: [PATCH 100/123] feat: `TRY_CONVERT` and `SAFE_CONVERT` support - fixes #2304 Signed-off-by: Andreas Reichel --- .../expression/TranscodingFunction.java | 33 +++++++++++++++++-- .../util/deparser/ExpressionDeParser.java | 6 ++-- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 10 ++++-- src/site/sphinx/keywords.rst | 2 ++ .../expression/TranscodingFunctionTest.java | 6 ++++ .../util/TablesNamesFinderTest.java | 16 +++++++++ 6 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java index 343579e29..b68f1dfb7 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java @@ -12,17 +12,35 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.create.table.ColDataType; +import java.util.Objects; + public class TranscodingFunction extends ASTNodeAccessImpl implements Expression { + private String keyword = "CONVERT"; private boolean isTranscodeStyle = true; private ColDataType colDataType; private Expression expression; private String transcodingName; + public TranscodingFunction(String keyword, Expression expression, String transcodingName) { + this.keyword = Objects.requireNonNullElse(keyword, "CONVERT").toUpperCase(); + this.expression = expression; + this.transcodingName = transcodingName; + } + public TranscodingFunction(Expression expression, String transcodingName) { this.expression = expression; this.transcodingName = transcodingName; } + public TranscodingFunction(String keyword, ColDataType colDataType, Expression expression, + String transcodingName) { + this.keyword = Objects.requireNonNullElse(keyword, "CONVERT").toUpperCase(); + this.colDataType = colDataType; + this.expression = expression; + this.transcodingName = transcodingName; + this.isTranscodeStyle = false; + } + public TranscodingFunction(ColDataType colDataType, Expression expression, String transcodingName) { this.colDataType = colDataType; @@ -35,6 +53,15 @@ public TranscodingFunction() { this(null, null); } + public String getKeyword() { + return keyword; + } + + public TranscodingFunction setKeyword(String keyword) { + this.keyword = Objects.requireNonNullElse(keyword, "CONVERT").toUpperCase(); + return this; + } + public Expression getExpression() { return expression; } @@ -87,14 +114,16 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { public StringBuilder appendTo(StringBuilder builder) { if (isTranscodeStyle) { return builder - .append("CONVERT( ") + .append(keyword) + .append("( ") .append(expression) .append(" USING ") .append(transcodingName) .append(" )"); } else { return builder - .append("CONVERT( ") + .append(keyword) + .append("( ") .append(colDataType) .append(", ") .append(expression) diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index d517c2303..27176d625 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -693,14 +693,16 @@ public StringBuilder visit(Select select, S context) { @Override public StringBuilder visit(TranscodingFunction transcodingFunction, S context) { if (transcodingFunction.isTranscodeStyle()) { - builder.append("CONVERT( "); + builder.append(transcodingFunction.getKeyword()); + builder.append("( "); transcodingFunction.getExpression().accept(this, context); builder.append(" USING ") .append(transcodingFunction.getTranscodingName()) .append(" )"); } else { builder - .append("CONVERT( ") + .append(transcodingFunction.getKeyword()) + .append("( ") .append(transcodingFunction.getColDataType()) .append(", "); transcodingFunction.getExpression().accept(this, context); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index ed708ea99..af765b3ca 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -580,6 +580,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -641,6 +642,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -3236,7 +3238,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | tk="SAFE_CAST" | tk="SAFE_CONVERT" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="TRY_CONVERT" | tk="TUMBLING" | tk="TYPE" | tk="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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; } } @@ -10495,6 +10497,7 @@ Expression CharacterPrimary(): TranscodingFunction TranscodingFunction() #TranscodingFunction : { + Token keywordToken; TranscodingFunction transcodingFunction; ColDataType colDataType; Expression expression; @@ -10502,14 +10505,15 @@ TranscodingFunction TranscodingFunction() #TranscodingFunction : Token style; } { - "(" + ( keywordToken= | keywordToken= | keywordToken= ) + "(" ( LOOKAHEAD(4) colDataType = ColDataType() "," expression = Expression() [ "," style = { transcodingName = style.image; } ] { - transcodingFunction = new TranscodingFunction(colDataType, expression, transcodingName); + transcodingFunction = new TranscodingFunction(keywordToken.image, colDataType, expression, transcodingName); } | ( diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 933cba664..d80a92fb8 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -165,6 +165,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | PUBLIC | Yes | | +----------------------+-------------+-----------+ +| RETURNS | Yes | Yes | ++----------------------+-------------+-----------+ | RETURNING | Yes | Yes | +----------------------+-------------+-----------+ | RIGHT | Yes | Yes | diff --git a/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java index 090317ff0..ea48d62db 100644 --- a/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java @@ -60,4 +60,10 @@ public void testUnPivotWithAlias() throws JSQLParserException { Statement st = assertSqlCanBeParsedAndDeparsed( "SELECT Convert( Decimal(18,2) , 1 )", true); } + + @Test + void testIssue2304() throws JSQLParserException { + String sqlStr = "SELECT TRY_CONVERT(NUMERIC(8,6), '1234') AS LATITUDE_NBR;"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index 19a619c88..a3da6cb85 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -681,5 +681,21 @@ void testIssue2183() throws JSQLParserException { Set tables = TablesNamesFinder.findTables(sqlStr); assertThat(tables).containsExactlyInAnyOrder("location_subscriber"); } + + @Test + void testIssue2305() throws JSQLParserException { + String sqlStr = "SELECT tbl.fk_id\n" + + " , tbl.etape\n" + + "FROM ( tbl\n" + + " JOIN ( SELECT tbl_1.fk_id\n" + + " , Max( tbl_1.date1 ) AS max_1\n" + + " FROM tbl tbl_1\n" + + " GROUP BY tbl_1.fk_id ) sub2\n" + + " ON ( ( ( sub2.fk_id = tbl.fk_id )\n" + + " AND ( sub2.max_1 = tbl.date1 ) ) ) )\n" + + ";"; + Set tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("tbl"); + } } From 528dd7227401d0762e3cf77a4ad1ac9c78e4f8ce Mon Sep 17 00:00:00 2001 From: David Hayes Date: Wed, 17 Sep 2025 02:20:36 +0100 Subject: [PATCH 101/123] Fix[2312] - Fixes issue with array in function declaration (#2313) * Fix[2312] - Fixes issue with array in function declaration ```sql WITH FUNCTION takesArray(x array) RETURNS double RETURN x[1] + x[2] + x[3] SELECT takesArray(array[1.0, 2.0, 3.0]); ``` Is unable to be parsed as we're not able to capture the array correctly. This PR fixes that, as well as some missing visitor changes from my previous PR. * Fix spotlessJavaCheck --------- Co-authored-by: David Hayes --- .../select/WithFunctionDeclaration.java | 8 +++++ .../jsqlparser/statement/select/WithItem.java | 5 ++- .../sf/jsqlparser/util/TablesNamesFinder.java | 8 +++-- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 13 +++++-- .../select/WithFunctionDeclarationTest.java | 34 +++++++++++++++++++ .../select/WithFunctionParameterTest.java | 9 +++++ .../statement/select/WithItemTest.java | 8 ++++- .../util/TablesNamesFinderTest.java | 16 +++++++++ src/test/resources/simple_parsing.txt | 8 ++++- 9 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java index f842e8282..c24d8a37f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; import java.io.Serializable; import java.util.List; @@ -100,6 +101,13 @@ public StringBuilder appendTo(StringBuilder builder) { .append(returnExpression); } + public T accept(ExpressionVisitor expressionVisitor, S context) { + if (returnExpression != null) { + return returnExpression.accept(expressionVisitor, context); + } + return null; + } + @Override public String toString() { return appendTo(new StringBuilder()).toString(); diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java index db633b2d2..8789a6875 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java @@ -171,7 +171,10 @@ public T accept(SelectVisitor selectVisitor, S context) { } public T accept(StatementVisitor statementVisitor, S context) { - return statement.accept(statementVisitor, context); + if (statement != null) { + return statement.accept(statementVisitor, context); + } + return null; } public WithItem withWithItemList(List> withItemList) { diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 1c3b9bf9e..bbb1b40f5 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -318,8 +318,12 @@ public Set getTables(Expression expr) { @Override public Void visit(WithItem withItem, S context) { - otherItemNames.add(withItem.getAlias().getName()); - withItem.getSelect().accept((SelectVisitor) this, context); + if (withItem.getAlias() != null) { + otherItemNames.add(withItem.getAlias().getName()); + } + if (withItem.getSelect() != null) { + withItem.getSelect().accept((SelectVisitor) this, context); + } return null; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index af765b3ca..f44a57dda 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -4405,11 +4405,20 @@ WithFunctionDeclaration WithFunctionDeclaration() #WithFunctionDeclaration: WithFunctionParameter WithFunctionParameter() #WithFunctionParameter: { String name; - String type; + String type = null; + String arrayType = null; } { - name = RelObjectName() type = RelObjectName() + name = RelObjectName() + ( + LOOKAHEAD(2) "<" arrayType = RelObjectName() ">" + | + type = RelObjectName() + ) { + if (arrayType != null) { + type = "ARRAY<" + arrayType + ">"; + } return new WithFunctionParameter(name, type); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java index 81e4c16fb..ed84b4aa7 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java @@ -1,6 +1,16 @@ +/*- + * #%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.statement.select; import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -10,6 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -93,4 +105,26 @@ void toStringTestWithNoParameters() { assertThat(withFunctionDeclaration.toString()) .isEqualTo("FUNCTION func1() RETURNS integer RETURN 1 + 1"); } + + @Test + void expressionVisitorIsNotCalledWhenNoReturnExpressionDeclared( + @Mock ExpressionVisitor expressionVisitor) { + withFunctionDeclaration = new WithFunctionDeclaration(); + + withFunctionDeclaration.accept(expressionVisitor, "RANDOM_CONTEXT"); + + verifyNoInteractions(expressionVisitor); + } + + @Test + void expressionVisitorCalledWhenReturnExpressionDeclared( + @Mock ExpressionVisitor expressionVisitor) { + String context = "RANDOM_CONTEXT"; + withFunctionDeclaration = new WithFunctionDeclaration() + .withReturnExpression(expression); + + withFunctionDeclaration.accept(expressionVisitor, context); + + verify(expression).accept(expressionVisitor, context); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java index bd632ed1d..9e29552ad 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.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.statement.select; import org.junit.jupiter.api.Test; diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java index 0e8f9e546..00224497f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java @@ -42,7 +42,13 @@ void testNotMaterializedIssue2251() throws JSQLParserException { " FUNCTION doubleupplusone(x integer)\n" + " RETURNS integer\n" + " RETURN doubleup(x) + 1\n" + - "SELECT doubleupplusone(21);" + "SELECT doubleupplusone(21);", + "WITH\n" + + " FUNCTION takesArray(x array)\n" + + " RETURNS double\n" + + " RETURN x[1] + x[2] + x[3]\n" + + "SELECT takesArray(ARRAY[1.0, 2.0, 3.0]);" + }) void testWithFunction(String sqlStr) throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index a3da6cb85..a40d52509 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -26,6 +26,7 @@ import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -697,5 +698,20 @@ void testIssue2305() throws JSQLParserException { Set tables = TablesNamesFinder.findTables(sqlStr); assertThat(tables).containsExactlyInAnyOrder("tbl"); } + + @Test + void assertWithItemWithFunctionDeclarationDoesNotThrowException() throws JSQLParserException { + String sqlStr = + "WITH FUNCTION my_with_item(param1 INT) RETURNS INT RETURN param1 + 1 SELECT * FROM my_table;"; + assertThatCode(() -> TablesNamesFinder.findTables(sqlStr)) + .doesNotThrowAnyException(); + } + + @Test + void assertWithItemWithFunctionDeclarationReturnsTableInSelect() throws JSQLParserException { + String sqlStr = + "WITH FUNCTION my_with_item(param1 INT) RETURNS INT RETURN param1 + 1 SELECT * FROM my_table;"; + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactly("my_table"); + } } diff --git a/src/test/resources/simple_parsing.txt b/src/test/resources/simple_parsing.txt index 657d43789..7fc390fab 100644 --- a/src/test/resources/simple_parsing.txt +++ b/src/test/resources/simple_parsing.txt @@ -242,4 +242,10 @@ WITH FUNCTION bye(name varchar) RETURNS varchar RETURN format('Bye %s!', 'name') -SELECT hello('Finn') || ' and ' || bye('Joe'); \ No newline at end of file +SELECT hello('Finn') || ' and ' || bye('Joe'); + +WITH + FUNCTION takesArray(x array) + RETURNS double + RETURN x[1] + x[2] + x[3] +SELECT takesArray(array[1.0, 2.0, 3.0]); \ No newline at end of file From 157988d1c5f68164c71e4adf3e62d1a8e73b7381 Mon Sep 17 00:00:00 2001 From: ConanZhang Date: Wed, 24 Sep 2025 10:06:46 +0800 Subject: [PATCH 102/123] Added new features to support the complete delete using syntax of pg database, such as subqueries, etc. (#2316) Co-authored-by: zhangkenan --- .../jsqlparser/statement/delete/Delete.java | 111 +++++++++++++++++- .../sf/jsqlparser/util/TablesNamesFinder.java | 7 +- .../util/deparser/DeleteDeParser.java | 4 +- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 10 +- .../statement/delete/DeleteTest.java | 17 +++ 5 files changed, 133 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java index 3072d9872..4e0f45ffe 100644 --- a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java +++ b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java @@ -17,6 +17,7 @@ import net.sf.jsqlparser.statement.ReturningClause; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.Join; import net.sf.jsqlparser.statement.select.Limit; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -29,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static java.util.stream.Collectors.joining; @@ -38,7 +40,7 @@ public class Delete implements Statement { private Table table; private OracleHint oracleHint = null; private List
tables; - private List
usingList; + private List usingFromItemList; private List joins; private Expression where; private PreferringClause preferringClause; @@ -157,12 +159,29 @@ public void setTables(List
tables) { this.tables = tables; } + /** + * This is compatible with the old logic. When calling this method, you need to ensure that the + * specific table is used after using. + * + * @return Table collection used in using. + */ + @Deprecated public List
getUsingList() { - return usingList; + if (usingFromItemList == null || usingFromItemList.isEmpty()) { + return new ArrayList<>(); + } + return usingFromItemList.stream().map(ele -> (Table) ele).collect(Collectors.toList()); } + /** + * This is compatible with the old logic. When calling this method, you need to ensure that the + * specific table is used after using. + * + * @param usingList Table collection used in using. + */ + @Deprecated public void setUsingList(List
usingList) { - this.usingList = usingList; + this.usingFromItemList = new ArrayList<>(usingList); } public List getJoins() { @@ -228,10 +247,10 @@ public String toString() { } b.append(" ").append(table); - if (usingList != null && usingList.size() > 0) { + if (usingFromItemList != null && !usingFromItemList.isEmpty()) { b.append(" USING "); - b.append(usingList.stream() - .map(Table::toString) + b.append(usingFromItemList.stream() + .map(Object::toString) .collect(joining(", "))); } @@ -273,11 +292,30 @@ public Delete withTables(List
tables) { return this; } + /** + * The old method has been replaced by withUsingFromItemList. + * + * @param usingList + * @return + * @see Delete#withUsingFromItemList + */ + @Deprecated public Delete withUsingList(List
usingList) { this.setUsingList(usingList); return this; } + /** + * New using syntax method.Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList + * @return + */ + public Delete withUsingFromItemList(List usingFromItemList) { + this.setUsingFromItemList(usingFromItemList); + return this; + } + public Delete withJoins(List joins) { this.setJoins(joins); return this; @@ -364,18 +402,60 @@ public Delete addTables(Collection tables) { return this.withTables(collection); } + /** + * The old method has been replaced by addUsingFromItemList. + * + * @param usingList + * @return + * @see Delete#addUsingFromItemList + */ + @Deprecated public Delete addUsingList(Table... usingList) { List
collection = Optional.ofNullable(getUsingList()).orElseGet(ArrayList::new); Collections.addAll(collection, usingList); return this.withUsingList(collection); } + /** + * New using syntax method.Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList + * @return + */ + public Delete addUsingFromItemList(FromItem... usingFromItemList) { + List collection = + Optional.ofNullable(getUsingFromItemList()).orElseGet(ArrayList::new); + Collections.addAll(collection, usingFromItemList); + return this.withUsingFromItemList(collection); + } + + /** + * The old method has been replaced by addUsingFromItemList. + * + * @param usingList + * @return + * @see Delete#addUsingFromItemList + */ + @Deprecated public Delete addUsingList(Collection usingList) { List
collection = Optional.ofNullable(getUsingList()).orElseGet(ArrayList::new); collection.addAll(usingList); return this.withUsingList(collection); } + /** + * New using syntax method. Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList + * @return + */ + public Delete addUsingFromItemList(Collection usingFromItemList) { + List collection = + Optional.ofNullable(getUsingFromItemList()).orElseGet(ArrayList::new); + collection.addAll(usingFromItemList); + return this.withUsingFromItemList(collection); + } + public Delete addJoins(Join... joins) { List collection = Optional.ofNullable(getJoins()).orElseGet(ArrayList::new); Collections.addAll(collection, joins); @@ -405,4 +485,23 @@ public Delete addOrderByElements(Collection orderByEle public E getWhere(Class type) { return type.cast(getWhere()); } + + /** + * Return the content after using. Supports the complete using syntax of pg, such as subqueries, + * etc. + * + * @return + */ + public List getUsingFromItemList() { + return usingFromItemList; + } + + /** + * Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList The content after using. + */ + public void setUsingFromItemList(List usingFromItemList) { + this.usingFromItemList = usingFromItemList; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index bbb1b40f5..26568d644 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -167,6 +167,7 @@ import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.FromItemVisitor; import net.sf.jsqlparser.statement.select.FunctionAllColumns; import net.sf.jsqlparser.statement.select.Join; @@ -1014,9 +1015,9 @@ public Void visit(MySQLGroupConcat groupConcat, S context) { public Void visit(Delete delete, S context) { visit(delete.getTable(), context); - if (delete.getUsingList() != null) { - for (Table using : delete.getUsingList()) { - visit(using, context); + if (delete.getUsingFromItemList() != null) { + for (FromItem usingFromItem : delete.getUsingFromItemList()) { + usingFromItem.accept(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java index 23b5eb32b..2ab59ea14 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java @@ -78,9 +78,9 @@ public void deParse(Delete delete) { } builder.append(" ").append(delete.getTable().toString()); - if (delete.getUsingList() != null && !delete.getUsingList().isEmpty()) { + if (delete.getUsingFromItemList() != null && !delete.getUsingFromItemList().isEmpty()) { builder.append(" USING").append( - delete.getUsingList().stream().map(Table::toString) + delete.getUsingFromItemList().stream().map(Object::toString) .collect(joining(", ", " ", ""))); } if (delete.getJoins() != null) { diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index f44a57dda..9998043a7 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -3012,8 +3012,8 @@ Delete Delete(): Table table = null; List
tables = new ArrayList
(); List> with = null; - Table usingTable = null; - List
usingList = new ArrayList
(); + FromItem usingFromItem = null; + List usingFromItemList = new ArrayList(); List joins = null; Expression where = null; PreferringClause preferringClause = null; @@ -3039,8 +3039,8 @@ Delete Delete(): | ) { hasFrom = true; }] [ LOOKAHEAD(3) table=TableWithAlias() [ LOOKAHEAD(2) joins=JoinsList() ] ] - [ usingTable=TableWithAlias() { usingList.add(usingTable); } - ("," usingTable=TableWithAlias() { usingList.add(usingTable); } )*] + [ usingFromItem=FromItem() { usingFromItemList.add(usingFromItem); } + ("," usingFromItem=FromItem() { usingFromItemList.add(usingFromItem); } )*] [where=WhereClause() { delete.setWhere(where); } ] [preferringClause=PreferringClause() { delete.setPreferringClause(preferringClause);} ] [orderByElements = OrderByElements() { delete.setOrderByElements(orderByElements); } ] @@ -3055,7 +3055,7 @@ Delete Delete(): .withTables(tables) .withTable(table) .withHasFrom(hasFrom) - .withUsingList(usingList) + .withUsingFromItemList(usingFromItemList) .withModifierPriority(modifierPriority) .withModifierIgnore(modifierIgnore) .withModifierQuick(modifierQuick); diff --git a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java index 7981cc819..2b7bab5e9 100644 --- a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java @@ -25,7 +25,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.statement.select.WithItem; @@ -397,4 +399,19 @@ public void testDeleteWithSkylineKeywords() throws JSQLParserException { delete.getWhere().toString()); } + @Test + public void testDeleteUsingFromItem() throws JSQLParserException { + String statement = + "DELETE A USING B.C D,(SELECT id FROM producers WHERE active = false) p WHERE D.Z = 1 and p.id = D.id"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(statement); + assertEquals("B.C", + ((Table) delete.getUsingFromItemList().get(0)).getFullyQualifiedName()); + assertEquals("D", + ((Table) delete.getUsingFromItemList().get(0)).getAlias().getName()); + assertEquals("producers", + ((Table) ((ParenthesedSelect) delete.getUsingFromItemList().get(1)).getPlainSelect() + .getFromItem()).getFullyQualifiedName()); + assertEquals("p", + delete.getUsingFromItemList().get(1).getAlias().getName()); + } } From 6697c063493cac278375e8b92f228216b107aa5b Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Wed, 8 Oct 2025 01:32:53 +0200 Subject: [PATCH 103/123] [feat] Support for LOCK-Statements (#2321) * Add support for LOCK-Statements * Fixed comments * ran updateKeywords * Added test * Checkstyle & Spotless * Adjusted NOWAIT and WAIT-Setter --- src/main/java/module-info.java | 1 + .../statement/StatementVisitor.java | 8 ++ .../statement/StatementVisitorAdapter.java | 7 ++ .../jsqlparser/statement/lock/LockMode.java | 24 ++++ .../statement/lock/LockStatement.java | 114 +++++++++++++++++ .../sf/jsqlparser/util/TablesNamesFinder.java | 12 ++ .../util/deparser/StatementDeParser.java | 7 ++ .../validator/StatementValidator.java | 7 ++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 31 ++++- .../jsqlparser/statement/lock/LockTest.java | 117 ++++++++++++++++++ .../util/TablesNamesFinderTest.java | 7 ++ 11 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 6765fe187..6487a6b97 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -40,6 +40,7 @@ exports net.sf.jsqlparser.statement.grant; exports net.sf.jsqlparser.statement.imprt; exports net.sf.jsqlparser.statement.insert; + exports net.sf.jsqlparser.statement.lock; exports net.sf.jsqlparser.statement.merge; exports net.sf.jsqlparser.statement.piped; exports net.sf.jsqlparser.statement.refresh; diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index 0068e0cf6..4636cbc8e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -32,6 +32,7 @@ import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; @@ -343,4 +344,11 @@ default void visit(Import imprt) { default void visit(Export export) { this.visit(export, null); } + + T visit(LockStatement lock, S context); + + default void visit(LockStatement lock) { + this.visit(lock, null); + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index f034c1cbb..ce0f5c82c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -37,6 +37,7 @@ import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.InsertConflictAction; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.merge.MergeOperationVisitor; import net.sf.jsqlparser.statement.merge.MergeOperationVisitorAdapter; @@ -289,6 +290,12 @@ public T visit(Execute execute, S context) { return null; } + @Override + public T visit(LockStatement lock, S context) { + + return null; + } + @Override public T visit(SetStatement set, S context) { diff --git a/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java b/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java new file mode 100644 index 000000000..552da946e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java @@ -0,0 +1,24 @@ +package net.sf.jsqlparser.statement.lock; + +/** + * Describes the LockMode of a LOCK TABLE-Statement. + */ +public enum LockMode { + // These two modes are more common + Share("SHARE"), Exclusive("EXCLUSIVE"), + + // These are Oracle specific, as far as I know + RowShare("ROW SHARE"), RowExclusive("ROW EXCLUSIVE"), ShareUpdate( + "SHARE UPDATE"), ShareRowExclusive("SHARE ROW EXCLUSIVE"); + + private final String value; + + LockMode(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java b/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java new file mode 100644 index 000000000..3e88c6065 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java @@ -0,0 +1,114 @@ +package net.sf.jsqlparser.statement.lock; + +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +/** + * Statement to Lock a specific table.
+ * Example:
+ * LOCK TABLE t IN EXCLUSIVE MODE
+ *
+ */ +public class LockStatement implements Statement { + + private Table table; + private LockMode lockMode; + private boolean noWait; + private Long waitSeconds; + + /** + * Creates a new LockStatement + * + * @param table The table to lock + * @param lockMode The lock mode + */ + public LockStatement(Table table, LockMode lockMode) { + this.table = table; + this.lockMode = lockMode; + } + + public LockStatement(Table table, LockMode lockMode, boolean noWait, Long waitSeconds) { + this(table, lockMode); + this.table = table; + this.lockMode = lockMode; + this.noWait = noWait; + this.waitSeconds = waitSeconds; + } + + private void checkValidState() { + if (noWait && waitSeconds != null) { + throw new IllegalStateException( + "A LOCK statement cannot have NOWAIT and WAIT at the same time"); + } + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public LockMode getLockMode() { + return lockMode; + } + + public void setLockMode(LockMode lockMode) { + this.lockMode = lockMode; + } + + /** + * @return True if the statement has a NOWAIT clause + */ + public boolean isNoWait() { + return noWait; + } + + /** + * Sets the NOWAIT-Flag. + * + * @param noWait True if the statement should have the NOWAIT clause + */ + public void setNoWait(boolean noWait) { + this.noWait = noWait; + checkValidState(); + } + + /** + * Sets the WAIT-Timeout. If this value is set, the Statement is rendered with WAIT + * <timeoutSeconds>
+ * If the value is set to NULL, the WAIT-clause is skipped + * + * @param waitSeconds The number of seconds for the WAIT timeout or NULL to skip the WAIT clause + */ + public void setWaitSeconds(Long waitSeconds) { + this.waitSeconds = waitSeconds; + checkValidState(); + } + + /** + * @return The number of seconds in the WAIT clause, or NULL if the statement has no WAIT clause + */ + public Long getWaitSeconds() { + return waitSeconds; + } + + @Override + public String toString() { + return "LOCK TABLE " + + table.getFullyQualifiedName() + + " IN " + + lockMode.getValue() + + " MODE" + + (noWait ? " NOWAIT" : "") + + (waitSeconds != null ? " WAIT " + waitSeconds : ""); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + +} diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 26568d644..0f2414dba 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -162,6 +162,7 @@ import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; @@ -1874,4 +1875,15 @@ public Void visit(Export export, S context) { public void visit(Export export) { StatementVisitor.super.visit(export); } + + @Override + public Void visit(LockStatement lock, S context) { + lock.getTable().accept(this); + return null; + } + + @Override + public void visit(LockStatement lock) { + StatementVisitor.super.visit(lock); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index ccfc0a92b..a27aee7af 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -57,6 +57,7 @@ import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; @@ -513,4 +514,10 @@ public StringBuilder visit(Export export, S context) { builder.append(export.toString()); return builder; } + + @Override + public StringBuilder visit(LockStatement lock, S context) { + builder.append(lock.toString()); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index af4ec9256..e6c42ab48 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -55,6 +55,7 @@ import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; @@ -399,6 +400,12 @@ public Void visit(Export export, S context) { return null; } + @Override + public Void visit(LockStatement lock, S context) { + // TODO: not yet implemented + return null; + } + public void visit(CreateIndex createIndex) { visit(createIndex, null); } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 9998043a7..83bcacaa8 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -70,6 +70,7 @@ import net.sf.jsqlparser.statement.merge.*; import net.sf.jsqlparser.statement.grant.*; import net.sf.jsqlparser.statement.imprt.*; import net.sf.jsqlparser.statement.export.*; +import net.sf.jsqlparser.statement.lock.*; import java.util.*; import java.util.AbstractMap.SimpleEntry; import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; @@ -364,6 +365,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | /* Salesforce SOQL */ | +| | | | @@ -476,6 +478,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -1031,6 +1034,8 @@ Statement SingleStatement() : | stm = SessionStatement() | + stm = LockStatement() + | LOOKAHEAD({ Dialect.EXASOL.name().equals(getAsString(Feature.dialect)) }) ( stm = Import() | stm = Export() ) ) { return stm; } @@ -1208,6 +1213,30 @@ List error_skipto(int kind) { return tokenImages; } +LockStatement LockStatement(): { + Table table; + boolean noWait = false; + LockMode lockMode; + Token waitSecondsToken = null; + Long waitSeconds = null; +} { + table = Table() + ( + LOOKAHEAD(2) ( { lockMode = LockMode.RowShare; } ) | + ( { lockMode = LockMode.RowExclusive; } ) | + LOOKAHEAD(2) ( { lockMode = LockMode.ShareRowExclusive; } ) | + LOOKAHEAD(2) ( { lockMode = LockMode.ShareUpdate; } ) | + ( { lockMode = LockMode.Share; } ) | + ( { lockMode = LockMode.Exclusive; } ) + ) + + [ { noWait = true; } | waitSecondsToken = { waitSeconds = Long.valueOf(waitSecondsToken.image); } ] + + { + return new LockStatement(table, lockMode, noWait, waitSeconds); + } +} + LikeClause LikeClause(): { LikeClause likeClause = new LikeClause(); Table table; @@ -3238,7 +3267,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | tk="SAFE_CAST" | tk="SAFE_CONVERT" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="TRY_CONVERT" | tk="TUMBLING" | tk="TYPE" | tk="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXCLUSIVE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="MODE" | tk="MODIFY" | tk="MOVEMENT" | tk="NAME" | tk="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | tk="SAFE_CAST" | tk="SAFE_CONVERT" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="TRY_CONVERT" | tk="TUMBLING" | tk="TYPE" | tk="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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; } } diff --git a/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java b/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java new file mode 100644 index 000000000..0e71c0107 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java @@ -0,0 +1,117 @@ +package net.sf.jsqlparser.statement.lock; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +@Execution(ExecutionMode.CONCURRENT) +public class LockTest { + + @ParameterizedTest + @ValueSource(strings = { + "LOCK TABLE a IN EXCLUSIVE MODE", + "LOCK TABLE a IN ROW EXCLUSIVE MODE", + "LOCK TABLE a IN ROW SHARE MODE", + "LOCK TABLE a IN SHARE MODE", + "LOCK TABLE a IN SHARE UPDATE MODE", + "LOCK TABLE a IN SHARE ROW EXCLUSIVE MODE", + "LOCK TABLE a IN EXCLUSIVE MODE NOWAIT", + "LOCK TABLE a IN SHARE ROW EXCLUSIVE MODE NOWAIT", + "LOCK TABLE a IN SHARE ROW EXCLUSIVE MODE WAIT 10", + "LOCK TABLE a IN EXCLUSIVE MODE WAIT 23", + }) + void testLockStatementsParseDeparse(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr); + } + + @Test + void testLockExclusiveMode() throws JSQLParserException { + String sqlStr = "LOCK TABLE a IN EXCLUSIVE MODE"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + assertInstanceOf(LockStatement.class, statement); + + LockStatement ls = (LockStatement) statement; + assertEquals(LockMode.Exclusive, ls.getLockMode()); + assertFalse(ls.isNoWait()); + } + + @Test + void testNoWait() throws JSQLParserException { + String sqlStr = "LOCK TABLE a IN SHARE MODE NOWAIT"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + assertInstanceOf(LockStatement.class, statement); + + LockStatement ls = (LockStatement) statement; + assertEquals(LockMode.Share, ls.getLockMode()); + assertTrue(ls.isNoWait()); + } + + @Test + void testWaitTimeout() throws JSQLParserException { + String sqlStr = "LOCK TABLE a IN SHARE MODE WAIT 300"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + assertInstanceOf(LockStatement.class, statement); + + LockStatement ls = (LockStatement) statement; + assertEquals(LockMode.Share, ls.getLockMode()); + assertNotNull(ls.getWaitSeconds()); + assertEquals(300, ls.getWaitSeconds()); + } + + @Test + void testCreateLockStatement() { + Table t = new Table("a"); + + LockStatement ls = new LockStatement(t, LockMode.Exclusive); + assertEquals("LOCK TABLE a IN EXCLUSIVE MODE", ls.toString()); + + ls.setLockMode(LockMode.Share); + assertEquals("LOCK TABLE a IN SHARE MODE", ls.toString()); + + ls.setNoWait(true); + assertEquals("LOCK TABLE a IN SHARE MODE NOWAIT", ls.toString()); + + ls.setNoWait(false); + ls.setWaitSeconds(60L); + assertEquals("LOCK TABLE a IN SHARE MODE WAIT 60", ls.toString()); + + ls.setWaitSeconds(null); + assertEquals("LOCK TABLE a IN SHARE MODE", ls.toString()); + + ls.setTable(new Table("b")); + assertEquals("LOCK TABLE b IN SHARE MODE", ls.toString()); + } + + @Test + void testIllegalStateWaitSeconds() { + Table t = new Table("a"); + LockStatement ls = new LockStatement(t, LockMode.Exclusive); + + assertThrows(IllegalStateException.class, () -> { + ls.setNoWait(true); + ls.setWaitSeconds(60L); + }); + } + + @Test + void testIllegalStateNoWait() { + Table t = new Table("a"); + LockStatement ls = new LockStatement(t, LockMode.Exclusive); + + assertThrows(IllegalStateException.class, () -> { + ls.setWaitSeconds(60L); + ls.setNoWait(true); + }); + } + + +} diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index a40d52509..c67cc240f 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -481,6 +481,13 @@ void testOtherSources() throws JSQLParserException { assertThat(tables).containsExactly("Datetimes"); } + @Test + void testLockStatement() throws JSQLParserException { + String sqlStr = "LOCK TABLE A IN EXCLUSIVE MODE"; + Set tables = TablesNamesFinder.findTablesOrOtherSources(sqlStr); + assertThat(tables).containsExactly("A"); + } + @Test void testSubqueryAliasesIssue1987() throws JSQLParserException { String sqlStr = "select * from (select * from a) as a1, b;"; From 619f8dadb6ce94236a30746781c4e7f0a0ce0183 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Thu, 9 Oct 2025 12:46:31 +0700 Subject: [PATCH 104/123] feat: normalised backtick quotes Signed-off-by: Andreas Reichel --- .../sf/jsqlparser/schema/MultiPartName.java | 21 +++++++++++++++++++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 1 + 2 files changed, 22 insertions(+) diff --git a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java index e2d985bc1..d9f8d84f9 100644 --- a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java +++ b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java @@ -9,10 +9,12 @@ */ package net.sf.jsqlparser.schema; +import java.util.regex.Matcher; import java.util.regex.Pattern; public interface MultiPartName { Pattern LEADING_TRAILING_QUOTES_PATTERN = Pattern.compile("^[\"\\[`]+|[\"\\]`]+$"); + Pattern BACKTICK_PATTERN = Pattern.compile("`([^`]*)`"); /** * Removes leading and trailing quotes from a SQL quoted identifier @@ -33,4 +35,23 @@ static boolean isQuoted(String identifier) { String getFullyQualifiedName(); String getUnquotedName(); + + static String replaceBackticksWithDoubleQuotes(String input) { + if (input == null || input.isEmpty()) { + return input; + } + + Matcher matcher = BACKTICK_PATTERN.matcher(input); + StringBuilder sb = new StringBuilder(); + + while (matcher.find()) { + // Replace each backtick-quoted part with double-quoted equivalent + String content = matcher.group(1); + matcher.appendReplacement(sb, "\"" + Matcher.quoteReplacement(content) + "\""); + } + matcher.appendTail(sb); + + return sb.toString(); + } + } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 9998043a7..9a8d136ad 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -15,6 +15,7 @@ options { DEBUG_LOOKAHEAD = false; DEBUG_TOKEN_MANAGER = false; CACHE_TOKENS = false; + SINGLE_TREE_FILE = false; // FORCE_LA_CHECK = true; UNICODE_INPUT = true; JAVA_TEMPLATE_TYPE = "modern"; From c60ff73909717bec063f3aac7a07d6ca3d8c7a2d Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Thu, 9 Oct 2025 13:48:15 +0700 Subject: [PATCH 105/123] feat: normalised backtick quotes Signed-off-by: Andreas Reichel --- .../java/net/sf/jsqlparser/schema/Column.java | 55 ++++++++++++++++++- .../sf/jsqlparser/schema/MultiPartName.java | 13 +++-- .../java/net/sf/jsqlparser/schema/Table.java | 4 ++ .../jsqlparser/schema/MultiPartNameTest.java | 15 +++++ .../statement/select/SelectTest.java | 8 ++- 5 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index 400d34c3a..ff13ef085 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -53,7 +53,8 @@ public Column(List nameParts, List delimiters) { } public Column(String columnName) { - this(null, columnName); + this(); + setColumnName(columnName); } public ArrayConstructor getArrayConstructor() { @@ -131,8 +132,56 @@ public String getUnquotedColumnName() { return MultiPartName.unquote(columnName); } - public void setColumnName(String string) { - columnName = string; + public void setColumnName(String name) { + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + setName(name, splitNamesOnDelimiter); + } + + public void setName(String name, boolean splitNamesOnDelimiter) { + if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(name).split("\\."); + switch (parts.length) { + case 3: + this.table = new Table("\"" + parts[0] + "\".\"" + parts[1] + "\""); + this.columnName = "\"" + parts[2] + "\""; + break; + case 2: + this.table = new Table("\"" + parts[0] + "\""); + this.columnName = "\"" + parts[1] + "\""; + break; + case 1: + this.columnName = "\"" + parts[0] + "\""; + break; + default: + throw new RuntimeException("Invalid column name: " + name); + } + } else if (name.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(name).split("\\."); + switch (parts.length) { + case 3: + this.table = new Table(parts[0] + "." + parts[1]); + this.columnName = parts[2]; + break; + case 2: + this.table = new Table(parts[0]); + this.columnName = parts[1]; + break; + case 1: + this.columnName = parts[0]; + break; + default: + throw new RuntimeException("Invalid column name: " + name); + } + } else { + this.columnName = name; + } } public String getTableDelimiter() { diff --git a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java index d9f8d84f9..ce954780d 100644 --- a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java +++ b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java @@ -29,13 +29,14 @@ static String unquote(String quotedIdentifier) { } static boolean isQuoted(String identifier) { - return identifier!=null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find(); + return identifier != null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find(); } String getFullyQualifiedName(); String getUnquotedName(); + static String replaceBackticksWithDoubleQuotes(String input) { if (input == null || input.isEmpty()) { return input; @@ -43,15 +44,17 @@ static String replaceBackticksWithDoubleQuotes(String input) { Matcher matcher = BACKTICK_PATTERN.matcher(input); StringBuilder sb = new StringBuilder(); + int lastEnd = 0; while (matcher.find()) { - // Replace each backtick-quoted part with double-quoted equivalent - String content = matcher.group(1); - matcher.appendReplacement(sb, "\"" + Matcher.quoteReplacement(content) + "\""); + sb.append(input, lastEnd, matcher.start()); // text before match + sb.append('"').append(matcher.group(1)).append('"'); // replace with double quotes + lastEnd = matcher.end(); } - matcher.appendTail(sb); + sb.append(input.substring(lastEnd)); // append remaining text return sb.toString(); } + } diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 784493283..1de14a8a5 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -302,6 +302,10 @@ public Table setTimeTravelStrAfterAlias(String timeTravelStrAfterAlias) { return this; } + public void setNameParts(List nameParts) { + this.partItems = nameParts; + } + private void setIndex(int idx, String value) { int size = partItems.size(); for (int i = 0; i < idx - size + 1; i++) { diff --git a/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java b/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java new file mode 100644 index 000000000..e554e49eb --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java @@ -0,0 +1,15 @@ +package net.sf.jsqlparser.schema; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class MultiPartNameTest { + + @Test + void replaceBackticksWithDoubleQuotes() { + Assertions.assertThat("\"starbake\".\"customers\"").isEqualToIgnoringCase( + MultiPartName.replaceBackticksWithDoubleQuotes("`starbake`.`customers`")); + } +} 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 8744d0839..260d1a330 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -1798,10 +1798,14 @@ public void testCount3() throws JSQLParserException { @Test public void testMysqlQuote() throws JSQLParserException { - String statement = "SELECT `a.OWNERLASTNAME`, `OWNERFIRSTNAME` " + String sqlStr = "SELECT `a.OWNERLASTNAME`, `OWNERFIRSTNAME` " + "FROM `ANTIQUEOWNERS` AS a, ANTIQUES AS b " + "WHERE b.BUYERID = a.OWNERID AND b.ITEM = 'Chair'"; - assertSqlCanBeParsedAndDeparsed(statement); + + String expected = + "SELECT \"a\".\"OWNERLASTNAME\", `OWNERFIRSTNAME` FROM `ANTIQUEOWNERS` AS a, ANTIQUES AS b WHERE b.BUYERID = a.OWNERID AND b.ITEM = 'Chair'"; + + assertStatementCanBeDeparsedAs(CCJSqlParserUtil.parse(sqlStr), expected); } @Test From e400444402c7a6eff694ac2dadd852a6632cf546 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Fri, 10 Oct 2025 13:01:28 +0200 Subject: [PATCH 106/123] [feat] Support for FOR READ ONLY/FOR FETCH ONLY (#2325) * [feat] Support for FOR READ ONLY/FOR FETCH ONLY * [chore] Spotless --- .../sf/jsqlparser/statement/select/ForMode.java | 5 ++++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 2 ++ .../sf/jsqlparser/statement/select/DB2Test.java | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java b/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java index 846faf9ed..3ca0b61d0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java @@ -20,7 +20,10 @@ public enum ForMode { NO_KEY_UPDATE("NO KEY UPDATE"), - KEY_SHARE("KEY SHARE"); + KEY_SHARE("KEY SHARE"), + + // https://www.ibm.com/docs/en/db2-for-zos/13.0.0?topic=statement-read-only-clause + READ_ONLY("READ ONLY"), FETCH_ONLY("FETCH ONLY"); private final String value; diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 1d85e86b7..c655c1ed1 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -4248,6 +4248,8 @@ PlainSelect PlainSelect() #PlainSelect: | { plainSelect.setForMode(ForMode.SHARE); } | ( { plainSelect.setForMode(ForMode.NO_KEY_UPDATE); }) | ( { plainSelect.setForMode(ForMode.KEY_SHARE); }) + | ( { plainSelect.setForMode(ForMode.READ_ONLY); }) + | ( { plainSelect.setForMode(ForMode.FETCH_ONLY); }) ) [ LOOKAHEAD(2) updateTable = Table() { plainSelect.setForUpdateTable(updateTable); } ] [ LOOKAHEAD() wait = Wait() { plainSelect.setWait(wait); } ] diff --git a/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java b/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java index 296aab55d..4b71a4830 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java @@ -12,6 +12,8 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class DB2Test { @Test @@ -20,4 +22,16 @@ void testDB2SpecialRegister() throws JSQLParserException { "SELECT * FROM TABLE1 where COL_WITH_TIMESTAMP <= CURRENT TIMESTAMP - CURRENT TIMEZONE"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM table WITH UR", + "SELECT * FROM table WITH UR FOR READ ONLY", + "SELECT * FROM table FOR READ ONLY", + "SELECT * FROM table FOR FETCH ONLY", + "SELECT * FROM table FETCH FIRST 100 ROWS ONLY FOR READ ONLY" + }) + void testWithIsolationLevelAndReadOnlyModes(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From e8d605854ae91487883c6dae53c20de7e8959c8a Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Sun, 12 Oct 2025 13:06:19 +0200 Subject: [PATCH 107/123] [feat/refactor] AllColumns and AllTableColumns-Support for JSON_OBJECT (#2323) * [feat] JSON_OBJECT support for AllColumns and AllTableColumns * [feat] JSON_OBJECT support for AllColumns and AllTableColumns * [feat] JSON_OBJECT support for AllColumns and AllTableColumns * [feat] Split the parser syntax for JsonFunction, added more Tests, added Feature to disable Commas as key value separators * [feat] Disable Expression as JSON_OBJECT key value via feature flag * [chore] spotlessApply * [feat] Use append method from JsonKeyValuePair --- build.gradle | 9 +- .../jsqlparser/expression/JsonFunction.java | 126 +++++----- .../expression/JsonFunctionType.java | 14 +- .../expression/JsonKeyValuePair.java | 62 ++++- .../expression/JsonKeyValuePairSeparator.java | 24 ++ .../sf/jsqlparser/parser/feature/Feature.java | 13 + .../sf/jsqlparser/util/TablesNamesFinder.java | 70 +----- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 230 ++++++++++-------- .../expression/JsonExpressionTest.java | 2 + .../expression/JsonFunctionTest.java | 183 +++++++++++++- .../util/TablesNamesFinderTest.java | 13 + 11 files changed, 497 insertions(+), 249 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java diff --git a/build.gradle b/build.gradle index 843119600..e566a0a10 100644 --- a/build.gradle +++ b/build.gradle @@ -131,7 +131,14 @@ configurations.configureEach { } compileJavacc { - arguments = [grammar_encoding: 'UTF-8', static: 'false', java_template_type: 'modern'] + arguments = [ + grammar_encoding: 'UTF-8', + static: 'false', + java_template_type: 'modern', + // Comment this in to build the parser with tracing. + DEBUG_PARSER: 'false', + DEBUG_LOOKAHEAD: 'false' + ] } java { diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java index 4422c1beb..176759c6d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java @@ -15,9 +15,15 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; /** + * Represents a JSON-Function.
+ * Currently supported are the types in {@link JsonFunctionType}.
+ *
+ * For JSON_OBJECT the parameters are available from {@link #getKeyValuePairs()}
+ *
+ * For JSON_ARRAY the parameters are availble from {@link #getExpressions()}.
+ * * @author Andreas Reichel */ - public class JsonFunction extends ASTNodeAccessImpl implements Expression { private final ArrayList keyValuePairs = new ArrayList<>(); private final ArrayList expressions = new ArrayList<>(); @@ -25,10 +31,31 @@ public class JsonFunction extends ASTNodeAccessImpl implements Expression { private JsonAggregateOnNullType onNullType; private JsonAggregateUniqueKeysType uniqueKeysType; + private boolean isStrict = false; + + public JsonFunction() {} + + public JsonFunction(JsonFunctionType functionType) { + this.functionType = functionType; + } + + /** + * Returns the Parameters of an JSON_OBJECT
+ * The KeyValuePairs may not have both key and value set, in some cases only the Key is set. + * + * @see net.sf.jsqlparser.parser.feature.Feature#allowCommaAsKeyValueSeparator + * + * @return A List of KeyValuePairs, never NULL + */ public ArrayList getKeyValuePairs() { return keyValuePairs; } + /** + * Returns the parameters of JSON_ARRAY
+ * + * @return A List of {@link JsonFunctionExpression}s, never NULL + */ public ArrayList getExpressions() { return expressions; } @@ -114,6 +141,19 @@ public JsonFunction withType(String typeName) { return this; } + public boolean isStrict() { + return isStrict; + } + + public void setStrict(boolean strict) { + isStrict = strict; + } + + public JsonFunction withStrict(boolean strict) { + this.setStrict(strict); + return this; + } + @Override public T accept(ExpressionVisitor expressionVisitor, S context) { return expressionVisitor.visit(this, context); @@ -123,13 +163,9 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { public StringBuilder append(StringBuilder builder) { switch (functionType) { case OBJECT: - appendObject(builder); - break; case POSTGRES_OBJECT: - appendPostgresObject(builder); - break; case MYSQL_OBJECT: - appendMySqlObject(builder); + appendObject(builder); break; case ARRAY: appendArray(builder); @@ -148,35 +184,37 @@ public StringBuilder appendObject(StringBuilder builder) { if (i > 0) { builder.append(", "); } - if (keyValuePair.isUsingValueKeyword()) { - if (keyValuePair.isUsingKeyKeyword()) { - builder.append("KEY "); - } - builder.append(keyValuePair.getKey()).append(" VALUE ") - .append(keyValuePair.getValue()); - } else { - builder.append(keyValuePair.getKey()).append(":").append(keyValuePair.getValue()); - } - - if (keyValuePair.isUsingFormatJson()) { - builder.append(" FORMAT JSON"); - } + keyValuePair.append(builder); i++; } + appendOnNullType(builder); + if (isStrict) { + builder.append(" STRICT"); + } + appendUniqueKeys(builder); + + builder.append(" ) "); + + return builder; + } + + private void appendOnNullType(StringBuilder builder) { if (onNullType != null) { switch (onNullType) { case NULL: builder.append(" NULL ON NULL"); break; case ABSENT: - builder.append(" ABSENT On NULL"); + builder.append(" ABSENT ON NULL"); break; default: // this should never happen } } + } + private void appendUniqueKeys(StringBuilder builder) { if (uniqueKeysType != null) { switch (uniqueKeysType) { case WITH: @@ -189,41 +227,6 @@ public StringBuilder appendObject(StringBuilder builder) { // this should never happen } } - - builder.append(" ) "); - - return builder; - } - - - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) - public StringBuilder appendPostgresObject(StringBuilder builder) { - builder.append("JSON_OBJECT( "); - for (JsonKeyValuePair keyValuePair : keyValuePairs) { - builder.append(keyValuePair.getKey()); - if (keyValuePair.getValue() != null) { - builder.append(", ").append(keyValuePair.getValue()); - } - } - builder.append(" ) "); - - return builder; - } - - public StringBuilder appendMySqlObject(StringBuilder builder) { - builder.append("JSON_OBJECT( "); - int i = 0; - for (JsonKeyValuePair keyValuePair : keyValuePairs) { - if (i > 0) { - builder.append(", "); - } - builder.append(keyValuePair.getKey()); - builder.append(", ").append(keyValuePair.getValue()); - i++; - } - builder.append(" ) "); - - return builder; } @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) @@ -239,18 +242,7 @@ public StringBuilder appendArray(StringBuilder builder) { i++; } - if (onNullType != null) { - switch (onNullType) { - case NULL: - builder.append(" NULL ON NULL "); - break; - case ABSENT: - builder.append(" ABSENT ON NULL "); - break; - default: - // "ON NULL" was omitted - } - } + appendOnNullType(builder); builder.append(") "); return builder; diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java index 43a33aab6..821416c9c 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java @@ -14,7 +14,19 @@ * @author Andreas Reichel */ public enum JsonFunctionType { - OBJECT, ARRAY, POSTGRES_OBJECT, MYSQL_OBJECT; + OBJECT, ARRAY, + + /** + * Not used anymore + */ + @Deprecated + POSTGRES_OBJECT, + + /** + * Not used anymore + */ + @Deprecated + MYSQL_OBJECT; public static JsonFunctionType from(String type) { return Enum.valueOf(JsonFunctionType.class, type.toUpperCase()); diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java index 82c8a355a..f8d43aa97 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java @@ -20,16 +20,27 @@ public class JsonKeyValuePair implements Serializable { private final Object key; private final Object value; - private boolean usingKeyKeyword = false; - private boolean usingValueKeyword = false; + private boolean usingKeyKeyword; + private JsonKeyValuePairSeparator separator; private boolean usingFormatJson = false; + /** + * Please use the Constructor with {@link JsonKeyValuePairSeparator} parameter. + */ + @Deprecated public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, boolean usingValueKeyword) { + this(key, value, usingKeyKeyword, usingValueKeyword ? JsonKeyValuePairSeparator.VALUE + : JsonKeyValuePairSeparator.COLON); + } + + public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, + JsonKeyValuePairSeparator separator) { this.key = Objects.requireNonNull(key, "The KEY of the Pair must not be null"); this.value = value; this.usingKeyKeyword = usingKeyKeyword; - this.usingValueKeyword = usingValueKeyword; + this.separator = + Objects.requireNonNull(separator, "The KeyValuePairSeparator must not be NULL"); } public boolean isUsingKeyKeyword() { @@ -45,19 +56,45 @@ public JsonKeyValuePair withUsingKeyKeyword(boolean usingKeyKeyword) { return this; } + /** + * Use {@link #getSeparator()} + */ + @Deprecated public boolean isUsingValueKeyword() { - return usingValueKeyword; + return separator == JsonKeyValuePairSeparator.VALUE; } + /** + * Use {@link #setSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated public void setUsingValueKeyword(boolean usingValueKeyword) { - this.usingValueKeyword = usingValueKeyword; + separator = usingValueKeyword ? JsonKeyValuePairSeparator.VALUE + : JsonKeyValuePairSeparator.COLON; } + /** + * Use {@link #withSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated public JsonKeyValuePair withUsingValueKeyword(boolean usingValueKeyword) { this.setUsingValueKeyword(usingValueKeyword); return this; } + public JsonKeyValuePairSeparator getSeparator() { + return separator; + } + + public void setSeparator(JsonKeyValuePairSeparator separator) { + this.separator = separator; + } + + public JsonKeyValuePair withSeparator(JsonKeyValuePairSeparator separator) { + this.setSeparator(separator); + return this; + } + public boolean isUsingFormatJson() { return usingFormatJson; } @@ -102,13 +139,14 @@ public Object getValue() { } public StringBuilder append(StringBuilder builder) { - if (isUsingValueKeyword()) { - if (isUsingKeyKeyword()) { - builder.append("KEY "); - } - builder.append(getKey()).append(" VALUE ").append(getValue()); - } else { - builder.append(getKey()).append(":").append(getValue()); + if (isUsingKeyKeyword() && getSeparator() == JsonKeyValuePairSeparator.VALUE) { + builder.append("KEY "); + } + builder.append(getKey()); + + if (getValue() != null) { + builder.append(getSeparator().getSeparatorString()); + builder.append(getValue()); } if (isUsingFormatJson()) { diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java new file mode 100644 index 000000000..aa0e599a4 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java @@ -0,0 +1,24 @@ +package net.sf.jsqlparser.expression; + +/** + * Describes the string used to separate the key from the value. + */ +public enum JsonKeyValuePairSeparator { + VALUE(" VALUE "), COLON(":"), + + // Used in MySQL dialect + COMMA(","), + + // Is used in case they KeyValuePair has only a key and no value + NOT_USED(""); + + private final String separator; + + JsonKeyValuePairSeparator(String separator) { + this.separator = separator; + } + + public String getSeparatorString() { + return separator; + } +} diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index 7f4cf2af0..d786f5170 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -809,6 +809,19 @@ public enum Feature { * "EXPORT" */ export, + + /** + * MySQL allows a ',' as a separator between key and value entries. We allow that by default, + * but it can be disabled here + */ + allowCommaAsKeyValueSeparator(true), + + /** + * DB2 and Oracle allow Expressions as JSON_OBJECT key values. This clashes with Informix and + * Snowflake Json-Extraction syntax + */ + allowExpressionAsJsonObjectKey(false) + ; private final Object value; diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 0f2414dba..9c33c4f27 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -10,64 +10,7 @@ package net.sf.jsqlparser.util; import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.AllValue; -import net.sf.jsqlparser.expression.AnalyticExpression; -import net.sf.jsqlparser.expression.AnyComparisonExpression; -import net.sf.jsqlparser.expression.ArrayConstructor; -import net.sf.jsqlparser.expression.ArrayExpression; -import net.sf.jsqlparser.expression.BinaryExpression; -import net.sf.jsqlparser.expression.BooleanValue; -import net.sf.jsqlparser.expression.CaseExpression; -import net.sf.jsqlparser.expression.CastExpression; -import net.sf.jsqlparser.expression.CollateExpression; -import net.sf.jsqlparser.expression.ConnectByRootOperator; -import net.sf.jsqlparser.expression.ConnectByPriorOperator; -import net.sf.jsqlparser.expression.DateTimeLiteralExpression; -import net.sf.jsqlparser.expression.DateValue; -import net.sf.jsqlparser.expression.DoubleValue; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.expression.ExtractExpression; -import net.sf.jsqlparser.expression.Function; -import net.sf.jsqlparser.expression.HexValue; -import net.sf.jsqlparser.expression.HighExpression; -import net.sf.jsqlparser.expression.IntervalExpression; -import net.sf.jsqlparser.expression.Inverse; -import net.sf.jsqlparser.expression.JdbcNamedParameter; -import net.sf.jsqlparser.expression.JdbcParameter; -import net.sf.jsqlparser.expression.JsonAggregateFunction; -import net.sf.jsqlparser.expression.JsonExpression; -import net.sf.jsqlparser.expression.JsonFunction; -import net.sf.jsqlparser.expression.JsonFunctionExpression; -import net.sf.jsqlparser.expression.KeepExpression; -import net.sf.jsqlparser.expression.LambdaExpression; -import net.sf.jsqlparser.expression.LongValue; -import net.sf.jsqlparser.expression.LowExpression; -import net.sf.jsqlparser.expression.MySQLGroupConcat; -import net.sf.jsqlparser.expression.NextValExpression; -import net.sf.jsqlparser.expression.NotExpression; -import net.sf.jsqlparser.expression.NullValue; -import net.sf.jsqlparser.expression.NumericBind; -import net.sf.jsqlparser.expression.OracleHierarchicalExpression; -import net.sf.jsqlparser.expression.OracleHint; -import net.sf.jsqlparser.expression.OracleNamedFunctionParameter; -import net.sf.jsqlparser.expression.OverlapsCondition; -import net.sf.jsqlparser.expression.RangeExpression; -import net.sf.jsqlparser.expression.RowConstructor; -import net.sf.jsqlparser.expression.RowGetExpression; -import net.sf.jsqlparser.expression.SignedExpression; -import net.sf.jsqlparser.expression.StringValue; -import net.sf.jsqlparser.expression.StructType; -import net.sf.jsqlparser.expression.TimeKeyExpression; -import net.sf.jsqlparser.expression.TimeValue; -import net.sf.jsqlparser.expression.TimestampValue; -import net.sf.jsqlparser.expression.TimezoneExpression; -import net.sf.jsqlparser.expression.TranscodingFunction; -import net.sf.jsqlparser.expression.TrimFunction; -import net.sf.jsqlparser.expression.UserVariable; -import net.sf.jsqlparser.expression.VariableAssignment; -import net.sf.jsqlparser.expression.WhenClause; -import net.sf.jsqlparser.expression.XMLSerializeExpr; +import net.sf.jsqlparser.expression.*; import net.sf.jsqlparser.expression.operators.arithmetic.Addition; import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift; @@ -1761,6 +1704,17 @@ public Void visit(JsonAggregateFunction expression, S context) { @Override public Void visit(JsonFunction expression, S context) { + for (JsonKeyValuePair keyValuePair : expression.getKeyValuePairs()) { + Object key = keyValuePair.getKey(); + Object value = keyValuePair.getValue(); + if (key instanceof Expression) { + ((Expression) key).accept(this, context); + } + if (value instanceof Expression) { + ((Expression) value).accept(this, context); + } + } + for (JsonFunctionExpression expr : expression.getExpressions()) { expr.getExpression().accept(this, context); } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index c655c1ed1..0da7f8cd3 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -4525,7 +4525,12 @@ SelectItem SelectItem() #SelectItem: } } -AllColumns AllColumns(): +/** + * Parses the AllColumns-Pattern '*'. + * + * If the allowAdditions is true, it parses additional Keywords. + */ +AllColumns AllColumns(boolean allowAdditions): { ParenthesedExpressionList exceptColumns = null; List> replaceExpressions = null; @@ -4534,21 +4539,28 @@ AllColumns AllColumns(): } { "*" - [ LOOKAHEAD(2) ( tk= | tk= ) exceptColumns = ParenthesedColumnList() { exceptKeyword=tk.image; } ] - [ LOOKAHEAD(2) "(" replaceExpressions = SelectItemsList() ")" ] + // BigData allows EXCEPT, DuckDB allows EXCLUDE + [ LOOKAHEAD(2, { allowAdditions }) ( tk= | tk= ) exceptColumns = ParenthesedColumnList() { exceptKeyword=tk.image; } ] + // BigData allows REPLACE + [ LOOKAHEAD(2, { allowAdditions }) "(" replaceExpressions = SelectItemsList() ")" ] { return new AllColumns(exceptColumns, replaceExpressions, exceptKeyword); } } -AllTableColumns AllTableColumns(): +/** + * Parses the AllTableColumns-Pattern 'table.*' + * + * If the allowAdditions is true, it parses additional Keywords. + */ +AllTableColumns AllTableColumns(boolean allowAdditions): { Table table = null; AllColumns allColumns; } { - table=Table() "." allColumns=AllColumns() + table=Table() "." allColumns=AllColumns(allowAdditions) { return new AllTableColumns(table, allColumns); } @@ -6559,9 +6571,9 @@ Expression PrimaryExpression() #PrimaryExpression: | token= { retval = new HexValue(token.image); } - | LOOKAHEAD(3) retval=AllColumns() + | LOOKAHEAD(3) retval=AllColumns(true) - | LOOKAHEAD(16) retval=AllTableColumns() + | LOOKAHEAD(16) retval=AllTableColumns(true) // See issue #2207 // there is a huge! performance deterioration from this production @@ -6973,121 +6985,139 @@ JsonExpression JsonExpression(Expression expr, List - "(" { result.setType( JsonFunctionType.OBJECT ); } - ( - // SQL2016 compliant Syntax - LOOKAHEAD(2) ( - LOOKAHEAD(2) ( - "KEY" { usingKeyKeyword = true; } ( keyToken = { key = keyToken.image; } | key = Column() ) - ) - | - keyToken = { key = keyToken.image; } - | + // Key part + ( + // lookahead because key is a valid column name + LOOKAHEAD(2) ( + { usingKeyKeyword = true; } + ( + keyToken = { key = keyToken.image; } | key = Column() - ) + ) + ) + | + LOOKAHEAD(16) ( key = AllTableColumns(false) { isWildcard = true; } ) + | + key = AllColumns(false) { isWildcard = true; } + | + key = Column() + | + LOOKAHEAD({getAsBoolean(Feature.allowExpressionAsJsonObjectKey)}) key = Expression() + | + keyToken = { key = keyToken.image; } + ) - ( LOOKAHEAD(2) - ( ":" | "," { result.setType( JsonFunctionType.POSTGRES_OBJECT ); } | "VALUE" { usingValueKeyword = true; } ) - ( - expression = Expression() - ) - [ { usingFormatJason = true; } ] - )? - { - if (expression !=null) { - keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, usingValueKeyword ); - keyValuePair.setUsingFormatJson( usingFormatJason ); - result.add(keyValuePair); - } else { - result.setType( JsonFunctionType.POSTGRES_OBJECT ); - keyValuePair = new JsonKeyValuePair( key, null, false, false ); - result.add(keyValuePair); - } - } + // Optional Separator + Value - Is not allowed with * or t1.* + [ LOOKAHEAD(1, { !isWildcard } ) + ( + { kvSeparator = JsonKeyValuePairSeparator.VALUE; } + | + { kvSeparator = JsonKeyValuePairSeparator.COLON; } + | + LOOKAHEAD({getAsBoolean(Feature.allowCommaAsKeyValueSeparator)}) { kvSeparator = JsonKeyValuePairSeparator.COMMA; } + ) + expression = Expression() + ] - // --- Next Elements - ( "," { usingKeyKeyword = false; usingValueKeyword = false; } - ( - LOOKAHEAD(2) ( - "KEY" { usingKeyKeyword = true; } ( keyToken = { key = keyToken.image; } | key = Column() ) - ) - | - keyToken = { key = keyToken.image; } - | - key = Column() - ) - ( ":" | "," { result.setType( JsonFunctionType.MYSQL_OBJECT ); } | "VALUE" { usingValueKeyword = true; } ) - expression = Expression() { keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, usingValueKeyword ); result.add(keyValuePair); } - [ { keyValuePair.setUsingFormatJson( true ); } ] - )* - )? + // Optional: FORMAT JSON - Is not allowed with * or t1.* + [ LOOKAHEAD(1, { !isWildcard } ) { usingFormatJason = true; } ] + ) + { + final JsonKeyValuePair keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, kvSeparator ); + keyValuePair.setUsingFormatJson( usingFormatJason ); + return keyValuePair; + } +} - [ - ( - { result.setOnNullType( JsonAggregateOnNullType.NULL ); } - ) - | - ( - { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } - ) - ] +JsonFunction JsonObjectBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.OBJECT); - [ - ( - { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITH ); } - ) - | - ( - { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITHOUT ); } - ) - ] - ")" - ) - | - ( - { result.setType( JsonFunctionType.ARRAY ); } - "(" + JsonKeyValuePair keyValuePair; +} +{ + ( "(" + ( + // First Element + LOOKAHEAD(2) keyValuePair = JsonKeyValuePair(true) { result.add(keyValuePair);} + + // Next Elements ( - LOOKAHEAD(2) ( - { result.setOnNullType( JsonAggregateOnNullType.NULL ); } - ) - | - expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } + keyValuePair = JsonKeyValuePair(false) { result.add(keyValuePair); } + )* + )? + [ + ( { result.setOnNullType( JsonAggregateOnNullType.NULL ); } ) + | + ( { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } ) + ] + [ { result.setStrict(true); } ] + [ + ( { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITH ); } ) + | + ( { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITHOUT ); } ) + ] + ")" ) + { + return result; + } +} + +JsonFunction JsonArrayBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.ARRAY); + + Expression expression = null; + JsonFunctionExpression functionExpression; +} +{ + ( "(" + ( + LOOKAHEAD(2) ( + { result.setOnNullType( JsonAggregateOnNullType.NULL ); } + ) + | + expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } + [ LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } ] + ( + "," + expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } [ LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } ] - ( - "," - expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } - [ LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } ] - )* )* + )* - [ - { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } - ] + [ + { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } + ] + ")" ) + { + return result; + } +} - ")" - ) +JsonFunction JsonFunction() : { + JsonFunction result; +} +{ + ( + ( result = JsonObjectBody() ) + | + ( result = JsonArrayBody() ) ) - { return result; } diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java index c29af21f9..5fc72bea8 100644 --- a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java @@ -41,6 +41,7 @@ void testIssue1792() throws JSQLParserException { @Test void testSnowflakeGetOperator() throws JSQLParserException { + // https://docs.snowflake.com/en/user-guide/querying-semistructured String sqlStr = "SELECT v:'attr[0].name' FROM vartab;"; PlainSelect st = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); Assertions.assertInstanceOf(JsonExpression.class, st.getSelectItem(0).getExpression()); @@ -48,6 +49,7 @@ void testSnowflakeGetOperator() throws JSQLParserException { @Test void testDataBricksExtractPathOperator() throws JSQLParserException { + // https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-json-path-expression String sqlStr = "SELECT C1:PRICE J FROM VALUES('{\"price\":5}')AS T(C1)"; PlainSelect st = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); Assertions.assertInstanceOf(JsonExpression.class, st.getSelectItem(0).getExpression()); diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java index ef1335e6c..5475f8ec7 100644 --- a/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java @@ -11,9 +11,17 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.parser.feature.FeatureConfiguration; +import net.sf.jsqlparser.statement.select.AllColumns; +import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; /** * @@ -66,15 +74,15 @@ public void testObjectBuilder() throws JSQLParserException { .withUsingKeyKeyword(true).withUsingValueKeyword(true).withUsingFormatJson(false); // this should work because we compare based on KEY only - Assertions.assertEquals(keyValuePair1, keyValuePair2); + assertEquals(keyValuePair1, keyValuePair2); // this must fail because all the properties are considered Assertions.assertNotEquals(keyValuePair1.toString(), keyValuePair2.toString()); JsonKeyValuePair keyValuePair3 = new JsonKeyValuePair("foo", "bar", false, false) .withUsingKeyKeyword(false).withUsingValueKeyword(false).withUsingFormatJson(false); - Assertions.assertNotNull(keyValuePair3); - Assertions.assertEquals(keyValuePair3, keyValuePair3); + assertNotNull(keyValuePair3); + assertEquals(keyValuePair3, keyValuePair3); Assertions.assertNotEquals(keyValuePair3, f); Assertions.assertTrue(keyValuePair3.hashCode() != 0); @@ -94,7 +102,7 @@ public void testArrayBuilder() throws JSQLParserException { new JsonFunctionExpression(new NullValue()).withUsingFormatJson( true); - Assertions.assertEquals(expression1.toString(), expression2.toString()); + assertEquals(expression1.toString(), expression2.toString()); f.add(expression1); f.add(expression2); @@ -164,6 +172,62 @@ public void testObject() throws JSQLParserException { TestUtils.assertExpressionCanBeParsedAndDeparsed("json_object()", true); } + @Test + public void nestedObjects() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "WITH Items AS (SELECT 'hello' AS key, 'world' AS value), \n" + + " SubItems AS (SELECT 'nestedValue' AS 'nestedKey', 'nestedWorld' AS nestedValue)\n" + + + "SELECT JSON_OBJECT(key: value, nested : (SELECT JSON_OBJECT(nestedKey, nestedValue) FROM SubItems)) AS json_data FROM Items", + true); + } + + @ParameterizedTest + @ValueSource(strings = { + // AllColumns + "SELECT JSON_OBJECT(*) FROM employees", + "SELECT JSON_OBJECT(* ABSENT ON NULL) FROM employees", + + // AllTableColumns + "SELECT JSON_OBJECT(e.*) FROM employees e", + "SELECT JSON_OBJECT(e.*, d.* NULL ON NULL) FROM employees e, departments d", + "SELECT JSON_OBJECT(e.* WITH UNIQUE KEYS) FROM employees e", + + // Single Column as entry + "SELECT JSON_OBJECT(first_name, last_name, address) FROM employees t1", + "SELECT JSON_OBJECT(t1.first_name, t1.last_name, t1.address) FROM employees t1", + "SELECT JSON_OBJECT(first_name, last_name FORMAT JSON, address) FROM employees t1", + "SELECT JSON_OBJECT(t1.first_name, t1.last_name FORMAT JSON, t1.address FORMAT JSON) FROM employees t1", + + // STRICT Keyword + "SELECT JSON_OBJECT( 'foo':bar, 'fob':baz FORMAT JSON STRICT ) FROM dual", + "SELECT JSON_OBJECT( 'foo':bar FORMAT JSON, 'fob':baz STRICT ) FROM dual", + "SELECT JSON_OBJECT( 'foo':bar, 'fob':baz NULL ON NULL STRICT WITH UNIQUE KEYS) FROM dual" + }) + void testObjectOracle(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + // BigQuery EXCEPT/REPLACE are not allowed here + "SELECT JSON_OBJECT(* EXCEPT(first_name)) FROM employees", + "SELECT JSON_OBJECT(* EXCLUDE(first_name)) FROM employees", + "SELECT JSON_OBJECT(* REPLACE(\"first_name\" AS first_name)) FROM employees", + + // FORMAT JSON is not allowed on wildcards + "SELECT JSON_OBJECT(* FORMAT JSON) FROM employees", + "SELECT JSON_OBJECT(e.* FORMAT JSON) FROM employees e", + + // Value is not allowed on wildcards + "SELECT JSON_OBJECT(* : bar) FROM employees", + "SELECT JSON_OBJECT(e.* VALUE bar) FROM employees e", + "SELECT JSON_OBJECT(KEY e.* VALUE bar) FROM employees e", + }) + void testInvalidObjectOracle(String sqlStr) { + assertThrows(JSQLParserException.class, () -> CCJSqlParserUtil.parse(sqlStr)); + } + @Test public void testObjectWithExpression() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed( @@ -262,29 +326,128 @@ public void testIssue1371() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT json_object('{a, b}', '{1,2 }')", true); } + @ParameterizedTest + @ValueSource(strings = { + "JSON_OBJECT( KEY 'foo' VALUE bar, 'fob' : baz)", + + "JSON_OBJECT( t1.*, t2.* )", + "JSON_OBJECT( 'foo' VALUE bar, t1.*)", + "JSON_OBJECT( t1.*, 'foo' VALUE bar)", + + // The FORMAT JSON forces the parser to correctly identify the entries as single entries + "JSON_OBJECT(first_name FORMAT JSON, last_name)", + "JSON_OBJECT(t1.first_name FORMAT JSON, t1.last_name FORMAT JSON)", + + // MySQL syntax + "JSON_OBJECT( 'foo', bar, 'fob', baz)", + }) + void testEntriesAreParsedCorrectly(String expressionStr) throws JSQLParserException { + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + assertEquals(2, jsonFunction.getKeyValuePairs().size()); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_OBJECT( t1.*, t2.*, t3.* )", + "JSON_OBJECT( 'foo' VALUE bar, t1.*, t2.single_column)", + "JSON_OBJECT( t1.*, 'foo' VALUE bar, KEY fob : baz)", + + // MySQL syntax + "JSON_OBJECT( 'foo', bar, 'fob', baz, 'for', buz)", + }) + void testEntriesAreParsedCorrectly3Entries(String expressionStr) throws JSQLParserException { + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_OBJECT(first_name, last_name, address)", + "JSON_OBJECT(t1.first_name, t1.last_name, t1.address)", + "JSON_OBJECT(first_name, last_name FORMAT JSON, address)", + "JSON_OBJECT(first_name FORMAT JSON, last_name FORMAT JSON, address)", + "JSON_OBJECT(t1.first_name, t1.last_name FORMAT JSON, t1.address FORMAT JSON)", + }) + void testSingleEntriesAreParsedCorrectlyWithouCommaAsKeyValueSeparator(String expressionStr) + throws JSQLParserException { + FeatureConfiguration fc = + new FeatureConfiguration().setValue(Feature.allowCommaAsKeyValueSeparator, false); + + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr, + true, parser -> parser.withConfiguration(fc)); + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + } + @Test public void testJavaMethods() throws JSQLParserException { String expressionStr = - "JSON_OBJECT( KEY 'foo' VALUE bar FORMAT JSON, 'foo':bar, 'foo':bar ABSENT ON NULL WITHOUT UNIQUE KEYS)"; + "JSON_OBJECT( KEY 'foo' VALUE bar FORMAT JSON, 'fob':baz, 'fod':bag ABSENT ON NULL WITHOUT UNIQUE KEYS)"; JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); - Assertions.assertEquals(JsonFunctionType.OBJECT, jsonFunction.getType()); + assertEquals(JsonFunctionType.OBJECT, jsonFunction.getType()); Assertions.assertNotEquals(jsonFunction.withType(JsonFunctionType.POSTGRES_OBJECT), jsonFunction.getType()); - Assertions.assertEquals(3, jsonFunction.getKeyValuePairs().size()); - Assertions.assertEquals(new JsonKeyValuePair("'foo'", "bar", true, true), + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + assertEquals(new JsonKeyValuePair("'foo'", "bar", true, true), jsonFunction.getKeyValuePair(0)); jsonFunction.setOnNullType(JsonAggregateOnNullType.NULL); - Assertions.assertEquals(JsonAggregateOnNullType.ABSENT, + assertEquals(JsonAggregateOnNullType.ABSENT, jsonFunction.withOnNullType(JsonAggregateOnNullType.ABSENT).getOnNullType()); jsonFunction.setUniqueKeysType(JsonAggregateUniqueKeysType.WITH); - Assertions.assertEquals(JsonAggregateUniqueKeysType.WITH, jsonFunction + assertEquals(JsonAggregateUniqueKeysType.WITH, jsonFunction .withUniqueKeysType(JsonAggregateUniqueKeysType.WITH).getUniqueKeysType()); } + @Test + void testJavaMethodsStrict() throws JSQLParserException { + String expressionStr = "JSON_OBJECT( 'foo':bar, 'fob':baz FORMAT JSON STRICT )"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertTrue(jsonFunction.isStrict()); + + jsonFunction.withStrict(false); + + assertEquals( + TestUtils.buildSqlString("JSON_OBJECT( 'foo':bar, 'fob':baz FORMAT JSON ) ", true), + TestUtils.buildSqlString(jsonFunction.toString(), true)); + + } + + @Test + void testJavaMethodsAllColumns() throws JSQLParserException { + String expressionStr = "JSON_OBJECT(* NULL ON NULL)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(1, jsonFunction.getKeyValuePairs().size()); + JsonKeyValuePair kv = jsonFunction.getKeyValuePair(0); + assertNotNull(kv); + + assertNull(kv.getValue()); + assertInstanceOf(AllColumns.class, kv.getKey()); + } + + @Test + void testJavaMethodsAllTableColumns() throws JSQLParserException { + String expressionStr = "JSON_OBJECT(a.*, b.* NULL ON NULL)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(2, jsonFunction.getKeyValuePairs().size()); + + JsonKeyValuePair kv1 = jsonFunction.getKeyValuePair(0); + assertNotNull(kv1); + assertInstanceOf(AllTableColumns.class, kv1.getKey()); + assertNull(kv1.getValue()); + + JsonKeyValuePair kv2 = jsonFunction.getKeyValuePair(1); + assertNotNull(kv2); + assertInstanceOf(AllTableColumns.class, kv2.getKey()); + assertNull(kv2.getValue()); + + } + @Test void testIssue1753JSonObjectAggWithColumns() throws JSQLParserException { String sqlStr = "SELECT JSON_OBJECTAGG( KEY q.foo VALUE q.bar) FROM dual"; diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index c67cc240f..dd7b93c7f 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -720,5 +720,18 @@ void assertWithItemWithFunctionDeclarationReturnsTableInSelect() throws JSQLPars "WITH FUNCTION my_with_item(param1 INT) RETURNS INT RETURN param1 + 1 SELECT * FROM my_table;"; assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactly("my_table"); } + + @Test + void testNestedTablesInJsonObject() throws JSQLParserException { + String sqlStr = "select JSON_OBJECT(\n" + + " t1.*, \n" + + " nested1 : (SELECT JSON_OBJECT(tn2.*) FROM table2 tn2 WHERE tn2.fk = t1.pk), \n" + + " nested2 : (SELECT JSON_OBJECT(tn3.*) FROM table3 tn3 WHERE tn3.fk = t1.pk)\n" + + " )\n" + + "FROM table1 t1;"; + + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("table1", + "table2", "table3"); + } } From 2d7393499e4d98761f8a81248d6510b33c09cf31 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 12 Oct 2025 18:20:01 +0700 Subject: [PATCH 108/123] fix: add some LOOKAHEAD Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 65 +++++++++---------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 0da7f8cd3..a22565f6e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -7000,43 +7000,40 @@ JsonKeyValuePair JsonKeyValuePair(boolean isFirstEntry) : { } { ( - // Key part - ( - // lookahead because key is a valid column name - LOOKAHEAD(2) ( - { usingKeyKeyword = true; } - ( - keyToken = { key = keyToken.image; } | - key = Column() - ) - ) - | - LOOKAHEAD(16) ( key = AllTableColumns(false) { isWildcard = true; } ) - | - key = AllColumns(false) { isWildcard = true; } - | - key = Column() - | - LOOKAHEAD({getAsBoolean(Feature.allowExpressionAsJsonObjectKey)}) key = Expression() - | - keyToken = { key = keyToken.image; } - ) - - // Optional Separator + Value - Is not allowed with * or t1.* - [ LOOKAHEAD(1, { !isWildcard } ) + // lookahead because key is a valid column name + LOOKAHEAD(2) ( + { usingKeyKeyword = true; } ( - { kvSeparator = JsonKeyValuePairSeparator.VALUE; } - | - { kvSeparator = JsonKeyValuePairSeparator.COLON; } - | - LOOKAHEAD({getAsBoolean(Feature.allowCommaAsKeyValueSeparator)}) { kvSeparator = JsonKeyValuePairSeparator.COMMA; } + keyToken = { key = keyToken.image; } | + key = Column() ) - expression = Expression() - ] - - // Optional: FORMAT JSON - Is not allowed with * or t1.* - [ LOOKAHEAD(1, { !isWildcard } ) { usingFormatJason = true; } ] + ) + | + LOOKAHEAD(16) key = AllTableColumns(false) { isWildcard = true; } + | + LOOKAHEAD(2) key = AllColumns(false) { isWildcard = true; } + | + LOOKAHEAD(2) key = Column() + | + LOOKAHEAD({getAsBoolean(Feature.allowExpressionAsJsonObjectKey)}) key = Expression() + | + keyToken = { key = keyToken.image; } ) + + // Optional Separator + Value - Is not allowed with * or t1.* + [ LOOKAHEAD(1, { !isWildcard } ) + ( + { kvSeparator = JsonKeyValuePairSeparator.VALUE; } + | + { kvSeparator = JsonKeyValuePairSeparator.COLON; } + | + LOOKAHEAD({getAsBoolean(Feature.allowCommaAsKeyValueSeparator)}) { kvSeparator = JsonKeyValuePairSeparator.COMMA; } + ) + expression = Expression() + ] + + // Optional: FORMAT JSON - Is not allowed with * or t1.* + [ LOOKAHEAD(1, { !isWildcard } ) { usingFormatJason = true; } ] { final JsonKeyValuePair keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, kvSeparator ); keyValuePair.setUsingFormatJson( usingFormatJason ); From aaebe591001a16459f017697e66af28b411b3804 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Mon, 13 Oct 2025 08:30:23 +0700 Subject: [PATCH 109/123] fix: parsing `STRUCT` data types Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 17 +++++++---------- .../statement/create/table/ColDataTypeTest.java | 10 ++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index a22565f6e..a026420a0 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -7983,11 +7983,8 @@ ColumnDefinition ColumnDefinition(): { List parameter; } { columnName=RelObjectName() - - colDataType = ColDataType() - + colDataType=ColDataType() ( LOOKAHEAD(2) parameter=CreateParameter() { columnSpecs.addAll(parameter); } )* - { coldef = new ColumnDefinition(); coldef.setColumnName(columnName); @@ -8366,13 +8363,13 @@ ColDataType ColDataType(): ( "(" - ( tk= | tk= ) - colDataType = ColDataType() { argumentsStringList.add( tk.image + " " + colDataType.toString()); } - [ + type = RelObjectNameExt2() + colDataType = ColDataType() { argumentsStringList.add( type + " " + colDataType.toString()); } + ( "," - ( tk= | tk= ) - colDataType = ColDataType() { argumentsStringList.add( tk.image + " " + colDataType.toString()); } - ] + type = RelObjectNameExt2() + colDataType = ColDataType() { argumentsStringList.add( type + " " + colDataType.toString()); } + )* ")" { colDataType = new ColDataType("STRUCT"); } ) | diff --git a/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java b/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java index e3462a66f..5fdae46c2 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java @@ -47,4 +47,14 @@ void testIssue1879() throws JSQLParserException { public void testNestedCast() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT acolumn::bit(64)::int(64) FROM mytable"); } + + @Test + void testStruct() throws JSQLParserException { + String sqlStr = + "CREATE TABLE IT.u (\n" + + " details struct( id varchar(255), name varchar(255)) NOT NULL,\n" + + " name VARCHAR(255) NOT NULL\n" + + " );\n"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From 297ef84673521fd75c70ea7acb20b25d143489bd Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Mon, 13 Oct 2025 11:58:46 +0700 Subject: [PATCH 110/123] fix: DuckDB `STRUCT` Signed-off-by: Andreas Reichel --- src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 7 ++++--- .../java/net/sf/jsqlparser/expression/StructTypeTest.java | 7 ++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index a026420a0..4305b09e1 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -6902,12 +6902,13 @@ StructType StructType() #StruckType: | ( { arguments= new ArrayList>(); dialect = StructType.Dialect.DUCKDB;} - - id = RelObjectName() expression = Expression() { arguments.add( new SelectItem( expression, id) ); } + ( id = RelObjectNameExt2() | tk1= { id = tk1.image; } ) + expression = Expression() { arguments.add( new SelectItem( expression, id) ); } ( "," - id = RelObjectName() expression = Expression() { arguments.add( new SelectItem( expression, id) ); } + ( id = RelObjectNameExt2() | tk1= { id = tk1.image; } ) + expression = Expression() { arguments.add( new SelectItem( expression, id) ); } )* diff --git a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java index c6645b4c9..e579f05a1 100644 --- a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java @@ -39,7 +39,6 @@ void testStructTypeBigQuery() throws JSQLParserException { @Test void testStructTypeDuckDB() throws JSQLParserException { - // @todo: check why the white-space after the "{" is needed?! String sqlStr = "SELECT { t:'abc',len:5}"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); @@ -64,6 +63,12 @@ void testStructTypeConstructorDuckDB() throws JSQLParserException { TestUtils.assertStatementCanBeDeparsedAs(select, sqlStr, true); } + @Test + void testStructTypeConstructorDuckDBWithQuotesAndTypes() throws JSQLParserException { + String sqlStr = "SELECT {'t':'abc'::STRING,'len':5::INT}"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + @Test void testStructTypeWithArgumentsDuckDB() throws JSQLParserException { // @todo: check why the white-space after the "{" is needed?! From 5fb44410ca844e6f6da315715118d5be7e9860c5 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 10:52:43 +0700 Subject: [PATCH 111/123] build: Action for `mvn verify`, on all three Operation Systems Signed-off-by: Andreas Reichel --- .github/workflows/ci.yml | 57 +++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cf7d4c46..0e75f7177 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,63 +2,102 @@ name: CI Pipeline on: push: - branches: [ "master" ] + branches: [ "**" ] # Run on every commit to any branch pull_request: - branches: [ "master" ] + branches: [ "**" ] # Run for PRs from any branch workflow_dispatch: permissions: write-all jobs: gradle_check: - runs-on: ubuntu-latest + name: Gradle Check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] steps: - uses: actions/checkout@main with: fetch-depth: 0 + - name: Set up JDK 17 uses: actions/setup-java@main with: java-version: '17' distribution: 'temurin' - - name: Build with Gradle + + - name: Set up Gradle uses: gradle/actions/setup-gradle@main + - name: Run Gradle Check run: ./gradlew check + maven_verify: + name: Maven Verify + needs: gradle_check # ✅ Run only after Gradle check succeeds + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Run Maven Verify + run: mvn --batch-mode verify + gradle_publish: - needs: gradle_check + name: Gradle Publish + needs: [ gradle_check, maven_verify ] # ✅ Run only after both succeed + if: github.ref == 'refs/heads/master' && github.repository == 'YOUR-ORG/YOUR-REPO' # ✅ Only for master branch of main repo runs-on: ubuntu-latest steps: - uses: actions/checkout@main with: fetch-depth: 0 + - name: Set up JDK 17 uses: actions/setup-java@main with: java-version: '17' distribution: 'temurin' + - name: Build with Gradle uses: gradle/actions/setup-gradle@main + - name: Publish with Gradle run: ./gradlew publish env: ossrhUsername: ${{ secrets.OSSRHUSERNAME }} ossrhPassword: ${{ secrets.OSSRHPASSWORD }} + - uses: actions/setup-python@main + - name: Install XSLT Processor - run: sudo apt-get install xsltproc sphinx-common + run: sudo apt-get install -y xsltproc sphinx-common + - name: Install Python dependencies - #run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments run: pip install furo myst_parser sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments + - name: Build Sphinx documentation with Gradle - run: ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx - - name: Deploy Sphinx documentation + run: FLOATING_TOC=false ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx + + - name: Configure GitHub Pages uses: actions/configure-pages@main + - name: Upload artifact uses: actions/upload-pages-artifact@main with: path: 'build/sphinx' + - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@main From be92a134c327eb732a9af1afae0f3c2a6f0c3e90 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 10:53:06 +0700 Subject: [PATCH 112/123] build: force UTF-8 output Signed-off-by: Andreas Reichel --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index a9f412955..eb123417f 100644 --- a/pom.xml +++ b/pom.xml @@ -680,6 +680,7 @@ UTF-8 + UTF-8 6.55.0 10.14.0 From 4314cb80a6ab5a70c794088e4329259354e02337 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 10:53:50 +0700 Subject: [PATCH 113/123] build: BuildInfo.class Signed-off-by: Andreas Reichel --- build.gradle | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/build.gradle b/build.gradle index e566a0a10..10f374d45 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,8 @@ import se.bjurr.gitchangelog.plugin.gradle.GitChangelogTask import com.nwalsh.gradle.saxon.SaxonXsltTask +import java.time.Instant + buildscript { dependencies { classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: 'latest.release' @@ -72,6 +74,56 @@ version = getVersion( !System.getenv("RELEASE") ) group = 'com.github.jsqlparser' description = 'JSQLParser library' +tasks.register('generateBuildInfo') { + outputs.dir layout.buildDirectory.file("resources/main") + doLast { + def outputDir = new File( layout.buildDirectory.file("generated/sources/buildinfo/java/main").get().asFile, "net/sf/jsqlparser") + outputDir.mkdirs() + + def gitVersionStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" + }.standardOutput.asText.get().trim() + + def gitCommitStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "rev-parse", "--short", "HEAD" + }.standardOutput.asText.get().trim() + + def buildTime = Instant.now().toString() + + def content = """\ + |package ai.starlake.jsqltranspiler; + | + |public final class BuildInfo { + | public static final String NAME = "${project.name}"; + | public static final String VERSION = "${gitVersionStr}"; + | public static final String GIT_COMMIT = "${gitCommitStr ?: 'unknown'}"; + | public static final String BUILD_TIME = "${buildTime}"; + |} + """.stripMargin() + + new File(outputDir, "BuildInfo.java").text = content + } +} + +// Make sure the file is included in the compiled sources +sourceSets { + main { + java { + srcDir layout.buildDirectory.file("generated/sources/buildinfo/java/main").get().asFile + } + } +} + +tasks.withType(Pmd).configureEach { + mustRunAfter("generateBuildInfo") +} + +tasks.withType(Checkstyle).configureEach { + exclude '**/module-info.java', '**/package-info.java' + + mustRunAfter("generateBuildInfo") +} + repositories { gradlePluginPortal() mavenCentral() @@ -179,6 +231,8 @@ jar { "Automatic-Module-Name": "net.sf.jsqlparser" ) } + + dependsOn(generateBuildInfo) } tasks.register('xmldoc', Javadoc) { From d747b818e529b00c3daf484b89e588488309313c Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 10:54:38 +0700 Subject: [PATCH 114/123] style: add license header Signed-off-by: Andreas Reichel --- .../jsqlparser/expression/JsonKeyValuePairSeparator.java | 9 +++++++++ .../java/net/sf/jsqlparser/statement/lock/LockMode.java | 9 +++++++++ .../net/sf/jsqlparser/statement/lock/LockStatement.java | 9 +++++++++ src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java | 9 +++++++++ .../java/net/sf/jsqlparser/schema/MultiPartNameTest.java | 9 +++++++++ .../java/net/sf/jsqlparser/statement/lock/LockTest.java | 9 +++++++++ 6 files changed, 54 insertions(+) diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java index aa0e599a4..e4e998aa5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.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; /** diff --git a/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java b/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java index 552da946e..be372218e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java +++ b/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.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.statement.lock; /** diff --git a/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java b/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java index 3e88c6065..2ec25e220 100644 --- a/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.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.statement.lock; import net.sf.jsqlparser.schema.Table; diff --git a/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java b/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java index df3b6acc9..c122279d6 100644 --- a/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java @@ -11,6 +11,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; /** @@ -45,4 +48,10 @@ public void testNullDatabaseAndServer() { assertSame(server, database.getServer()); } + @Test + void testBigQuerycatalogs() throws JSQLParserException { + String sqlStr = "SELECT * FROM \"starlake-325712\".starlake_tbl.transactions"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + } diff --git a/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java b/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java index e554e49eb..dfb5034f6 100644 --- a/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.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.schema; import org.assertj.core.api.Assertions; diff --git a/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java b/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java index 0e71c0107..1ffed8cc4 100644 --- a/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.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.statement.lock; import net.sf.jsqlparser.JSQLParserException; From 3f36a84252c96f67049989f5175b51d3b1b9d732 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 11:19:46 +0700 Subject: [PATCH 115/123] build: Windows/Maven/Code-page issues Signed-off-by: Andreas Reichel --- pom.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pom.xml b/pom.xml index eb123417f..45acca703 100644 --- a/pom.xml +++ b/pom.xml @@ -286,6 +286,9 @@ java + true + UTF-8 + true From abb06c01dd2c3812ab9d6a8f716b06ba29f77ea9 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 11:38:21 +0700 Subject: [PATCH 116/123] build: Windows/Maven/Code-page issues Signed-off-by: Andreas Reichel --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 45acca703..92dbb4bc7 100644 --- a/pom.xml +++ b/pom.xml @@ -288,7 +288,7 @@ java true UTF-8 - true + From d8019cab2f24441a0179d79b3d47a2f2c3cc77cb Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Fri, 24 Oct 2025 11:54:23 +0700 Subject: [PATCH 117/123] build: Windows/Maven/Code-page issues Signed-off-by: Andreas Reichel --- build.gradle | 4 ++++ pom.xml | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 10f374d45..15e9e50e2 100644 --- a/build.gradle +++ b/build.gradle @@ -114,6 +114,10 @@ sourceSets { } } +tasks.withType(JavaCompile).configureEach { + mustRunAfter("generateBuildInfo") +} + tasks.withType(Pmd).configureEach { mustRunAfter("generateBuildInfo") } diff --git a/pom.xml b/pom.xml index 92dbb4bc7..20f6b7066 100644 --- a/pom.xml +++ b/pom.xml @@ -285,9 +285,13 @@ jjtree-javacc - java - true UTF-8 + false + false + false + java + + From 01034cd08c3e9d75692abb5f8afc9cee97700dad Mon Sep 17 00:00:00 2001 From: Hayssam Saleh Date: Tue, 28 Oct 2025 12:48:22 +0100 Subject: [PATCH 118/123] Update README.md (#2331) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 999f043e2..80dffcc39 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 86.592 ± 5.781 m | RDBMS | Statements | |-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| -| Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | +| BigQuery
Snowflake
DuckDB
Redshift
Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | | Salesforce SOQL | `INCLUDES`, `EXCLUDES` | | Piped SQL (also known as FROM SQL) | | From 4fdfa785dcfd2d5b34f52cb7df57f402c86569e2 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 2 Nov 2025 20:02:54 +0700 Subject: [PATCH 119/123] feat: `DateUnitExpression` for parsing `HOUR`, `DAY`, `MONTH` etc. in Date Functions not as column Signed-off-by: Andreas Reichel --- .github/workflows/ci.yml | 6 ++- .../expression/DateUnitExpression.java | 50 +++++++++++++++++++ .../expression/ExpressionVisitor.java | 2 + .../expression/ExpressionVisitorAdapter.java | 5 ++ .../sf/jsqlparser/util/TablesNamesFinder.java | 5 ++ .../util/deparser/ExpressionDeParser.java | 6 +++ .../validator/ExpressionValidator.java | 6 +++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 35 +++++++++---- .../expression/DateUnitExpressionTest.java | 21 ++++++++ .../statement/select/SelectTest.java | 12 +++++ 10 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.java create mode 100644 src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e75f7177..4c12bac81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,9 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ ubuntu-latest, windows-latest, macos-latest ] +# currently Windows does not work w/ code page related issues +# os: [ ubuntu-latest, windows-latest, macos-latest ] + os: [ ubuntu-latest, macos-latest ] steps: - uses: actions/checkout@main with: @@ -57,7 +59,7 @@ jobs: gradle_publish: name: Gradle Publish needs: [ gradle_check, maven_verify ] # ✅ Run only after both succeed - if: github.ref == 'refs/heads/master' && github.repository == 'YOUR-ORG/YOUR-REPO' # ✅ Only for master branch of main repo + if: github.ref == 'refs/heads/master' && github.repository == 'JSQLParser/JSqlParser' # ✅ Only for master branch of main repo runs-on: ubuntu-latest steps: - uses: actions/checkout@main diff --git a/src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.java new file mode 100644 index 000000000..298cff0cc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.java @@ -0,0 +1,50 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Objects; + +public class DateUnitExpression extends ASTNodeAccessImpl implements Expression { + + private final DateUnit type; + + public DateUnitExpression(DateUnit type) { + this.type = Objects.requireNonNull(type); + } + + public DateUnitExpression(String DateUnitStr) { + this.type = Objects.requireNonNull(DateUnit.from(DateUnitStr)); + } + + public DateUnit getType() { + return type; + } + + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return type.toString(); + } + + public enum DateUnit { + CENTURY, DECADE, YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND; + + public static DateUnit from(String UnitStr) { + return Enum.valueOf(DateUnit.class, UnitStr.toUpperCase()); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index 8b5ade13d..e9b5f1b37 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -779,4 +779,6 @@ default void visit(Inverse inverse) { T visit(CosineSimilarity cosineSimilarity, S context); T visit(FromQuery fromQuery, S context); + + T visit(DateUnitExpression dateUnitExpression, S context); } diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 96d80d514..88f92369b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -840,4 +840,9 @@ public T visit(FromQuery fromQuery, S context) { return null; } + @Override + public T visit(DateUnitExpression dateUnitExpression, S context) { + return null; + } + } diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 9c33c4f27..b062d2503 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -829,6 +829,11 @@ public Void visit(FromQuery fromQuery, S context) { return null; } + @Override + public Void visit(DateUnitExpression dateUnitExpression, S context) { + return null; + } + /** * Initializes table names collector. Important is the usage of Column instances to find table * names. This is only allowed for expression parsing, where a better place for tablenames could diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 27176d625..c97a28423 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -23,6 +23,7 @@ import net.sf.jsqlparser.expression.ConnectByRootOperator; import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; +import net.sf.jsqlparser.expression.DateUnitExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.Expression; @@ -1829,4 +1830,9 @@ public StringBuilder visit(CosineSimilarity cosineSimilarity, S context) { public StringBuilder visit(FromQuery fromQuery, S context) { return null; } + + @Override + public StringBuilder visit(DateUnitExpression dateUnitExpression, S context) { + return builder.append(dateUnitExpression.toString()); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java index a4b27d765..87f0205d8 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java @@ -22,6 +22,7 @@ import net.sf.jsqlparser.expression.ConnectByRootOperator; import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; +import net.sf.jsqlparser.expression.DateUnitExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.Expression; @@ -1314,4 +1315,9 @@ public Void visit(FromQuery fromQuery, S context) { return null; } + @Override + public Void visit(DateUnitExpression dateUnitExpression, S context) { + return null; + } + } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 4305b09e1..0f2dd1df6 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -6559,9 +6559,11 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch() - | LOOKAHEAD(2, {!interrupted}) retval=CastExpression() + | LOOKAHEAD(2, {!interrupted}) retval= CastExpression() - | LOOKAHEAD(16) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] + | LOOKAHEAD(16) retval = Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] + + | LOOKAHEAD(2) retval = DateUnitExpression() | LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; } @@ -6804,10 +6806,25 @@ NumericBind NumericBind() : { DateTimeLiteralExpression DateTimeLiteralExpression() : { DateTimeLiteralExpression expr = new DateTimeLiteralExpression(); Token t; -} { - t= { expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); } +} +{ + t= + { + expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); + } - ( t= | t= ) { expr.setValue(t.image); return expr; } + ( t= | t= ) + { + expr.setValue(t.image); + return expr; + } +} + +DateUnitExpression DateUnitExpression() : { + Token t; +} +{ + t= { return new DateUnitExpression( t.image ); } } RangeExpression RangeExpression(Expression startExpression): @@ -6892,7 +6909,7 @@ StructType StructType() #StruckType: LOOKAHEAD(4) ( tk1= { keyword = tk1.image; } "<" parameters = StructParameters() ">" - "(" { System.out.println("found arguments!"); } arguments = SelectItemsList() ")" + "(" arguments = SelectItemsList() ")" ) | ( @@ -6916,10 +6933,6 @@ StructType StructType() #StruckType: LOOKAHEAD(2) "::" "(" parameters = StructParameters() ")" )* ) - - // don't parse this as an Struct, but rather use an Expressionlist - // | - // arguments = StructArguments() ) { type = new StructType(dialect, keyword, parameters, arguments); @@ -7703,7 +7716,7 @@ Function SpecialStringFunctionWithNamedParameters() : "(" ( - LOOKAHEAD(6, { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() + LOOKAHEAD( NamedExpressionListExprFirst() , { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() | expressionList=ExpressionList() ) diff --git a/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java new file mode 100644 index 000000000..054b25e9a --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java @@ -0,0 +1,21 @@ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.test.TestUtils; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + + +class DateUnitExpressionTest { + + @Test + void testParsing() throws JSQLParserException { + String sqlStr = "SELECT Last_Day( DATE '2024-12-31', month ) as month"; + + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Function f = select.getSelectItem(0).getExpression(Function.class); + Assertions.assertThat(f.getParameters().get(1)).isInstanceOf(DateUnitExpression.class); + } +} 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 260d1a330..9a361b525 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -6422,4 +6422,16 @@ void testSQL2016CorrespondingBy() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testIssue2332SubStrCTE() throws JSQLParserException { + String sqlStr = + "create table t as\n" + + " with\n" + + " _ as (select f(id = '') from v)\n" + + " select\n" + + " substring (f (u.id))\n" + + " from u ;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } From 999cdca2ac1be893eb73117e2642d63fb2692da0 Mon Sep 17 00:00:00 2001 From: Eyal Gehasie Date: Fri, 21 Nov 2025 01:31:53 +0200 Subject: [PATCH 120/123] feat: add PostgreSQL Row Level Security (RLS) support (#2345) * feat: add PostgreSQL Row Level Security (RLS) support Add support for PostgreSQL Row Level Security statements: - CREATE POLICY with full syntax (FOR, TO, USING, WITH CHECK clauses) - ALTER TABLE ENABLE/DISABLE/FORCE/NO FORCE ROW LEVEL SECURITY Changes: - New CreatePolicy AST class for CREATE POLICY statements - Added RLS operations to AlterOperation enum - Updated grammar with POLICY, LEVEL, SECURITY keywords - Fixed grammar conflicts with LOOKAHEAD directives - Updated all visitor interfaces and implementations - Added comprehensive unit tests (19 tests, 100% passing) - Updated README.md with new features All code quality checks passing: - CheckStyle: 0 violations - PMD: passed * fix: correct grammar alternative ordering for RLS statements Fixed parser failures when parsing PostgreSQL Row Level Security (RLS) statements by reordering grammar alternatives to check more specific patterns before less specific ones. Problem: - ALTER TABLE ... ENABLE/DISABLE ROW LEVEL SECURITY failed to parse - Parser was incorrectly choosing ENABLE/DISABLE KEYS path first - Grammar warning about WITH keyword conflict in CREATE POLICY Solution: 1. Reordered ENABLE alternatives: ENABLE ROW LEVEL SECURITY now checked before ENABLE KEYS (lines 9674-9684) 2. Reordered DISABLE alternatives: DISABLE ROW LEVEL SECURITY now checked before DISABLE KEYS (lines 9661-9671) 3. Added LOOKAHEAD(2) to WITH CHECK clause in CREATE POLICY to resolve conflict with CTEs (line 10470) Impact: - All 19 existing RLS tests pass (8 AlterRowLevelSecurityTest, 11 CreatePolicyTest) - WITH keyword conflict warning eliminated - Parser can now handle real-world SQL migration files with RLS statements - No regressions in existing functionality Technical Note: In JavaCC, when multiple alternatives share a common prefix (like ENABLE), the more specific pattern (longer token sequence) must appear FIRST in the grammar to be matched correctly. LOOKAHEAD values help disambiguate, but ordering is critical for correct parsing. * fix: allow RLS keywords (LEVEL, POLICY, SECURITY) as aliases Added K_LEVEL, K_POLICY, and K_SECURITY tokens to RelObjectNameWithoutStart() production to allow these keywords to be used as column aliases in addition to table/column names. This resolves the conflict where RLS keywords were breaking Oracle hierarchical queries and keywords-as-identifiers tests. The fix maintains RLS functionality while allowing these keywords to work in all SQL contexts including aliases (e.g., SELECT col AS level). * chore: update keywords after running updateKeywords task After running `./gradlew updateKeywords`, the task automatically added LEVEL, POLICY, and SECURITY keywords to RelObjectNameWithoutValue() in alphabetical order (line 3275). Removed redundant manual additions from RelObjectName() and RelObjectNameWithoutStart() that were causing unreachable statement compilation errors. The keywords are now properly maintained in the canonical location (RelObjectNameWithoutValue) and will work as identifiers in all contexts. Tests: All 4154 tests passing * run ./gradlew spotlessApply * fix: complete TablesNamesFinder integration for CREATE POLICY Add expression visitor calls to traverse USING and WITH CHECK clauses, enabling discovery of all table references in subqueries. This completes the TablesNamesFinder visitor implementation for CREATE POLICY statements by following the same pattern used in Update, Delete, and PlainSelect statements. Includes comprehensive test coverage (12 tests) covering simple subqueries, nested subqueries, CTEs, JOINs, and edge cases. --------- Co-authored-by: raz aranyi --- README.md | 1 + .../statement/StatementVisitor.java | 7 + .../statement/StatementVisitorAdapter.java | 7 + .../statement/alter/AlterExpression.java | 8 + .../statement/alter/AlterOperation.java | 2 +- .../statement/create/policy/CreatePolicy.java | 131 +++++++++ .../sf/jsqlparser/util/TablesNamesFinder.java | 25 ++ .../util/deparser/StatementDeParser.java | 7 + .../validator/StatementValidator.java | 11 + .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 88 +++++- .../expression/DateUnitExpressionTest.java | 9 + .../alter/AlterRowLevelSecurityTest.java | 115 ++++++++ .../create/CreatePolicyTablesFinderTest.java | 263 ++++++++++++++++++ .../statement/create/CreatePolicyTest.java | 158 +++++++++++ 14 files changed, 822 insertions(+), 10 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/alter/AlterRowLevelSecurityTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java diff --git a/README.md b/README.md index 80dffcc39..aab8ae510 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 86.592 ± 5.781 m | RDBMS | Statements | |-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | BigQuery
Snowflake
DuckDB
Redshift
Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | +| PostgreSQL Row Level Security | `CREATE POLICY`
`ALTER TABLE ... ENABLE/DISABLE/FORCE/NO FORCE ROW LEVEL SECURITY` | | Salesforce SOQL | `INCLUDES`, `EXCLUDES` | | Piped SQL (also known as FROM SQL) | | diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index 4636cbc8e..9ebab53a8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -17,6 +17,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -351,4 +352,10 @@ default void visit(LockStatement lock) { this.visit(lock, null); } + T visit(CreatePolicy createPolicy, S context); + + default void visit(CreatePolicy createPolicy) { + this.visit(createPolicy, null); + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index ce0f5c82c..3b12c01c0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -21,6 +21,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -296,6 +297,12 @@ public T visit(LockStatement lock, S context) { return null; } + @Override + public T visit(CreatePolicy createPolicy, S context) { + + return null; + } + @Override public T visit(SetStatement set, S context) { diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java index 372d9c790..336d66b44 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java @@ -856,6 +856,14 @@ public String toString() { } else { if (operation == AlterOperation.COMMENT_WITH_EQUAL_SIGN) { b.append("COMMENT =").append(" "); + } else if (operation == AlterOperation.ENABLE_ROW_LEVEL_SECURITY) { + b.append("ENABLE ROW LEVEL SECURITY").append(" "); + } else if (operation == AlterOperation.DISABLE_ROW_LEVEL_SECURITY) { + b.append("DISABLE ROW LEVEL SECURITY").append(" "); + } else if (operation == AlterOperation.FORCE_ROW_LEVEL_SECURITY) { + b.append("FORCE ROW LEVEL SECURITY").append(" "); + } else if (operation == AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY) { + b.append("NO FORCE ROW LEVEL SECURITY").append(" "); } else { b.append(operation).append(" "); } diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java index 839685b1a..48fe639ea 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java @@ -10,7 +10,7 @@ package net.sf.jsqlparser.statement.alter; public enum AlterOperation { - ADD, ALTER, DROP, DROP_PRIMARY_KEY, DROP_UNIQUE, DROP_FOREIGN_KEY, MODIFY, CHANGE, CONVERT, COLLATE, ALGORITHM, RENAME, RENAME_TABLE, RENAME_INDEX, RENAME_KEY, RENAME_CONSTRAINT, COMMENT, COMMENT_WITH_EQUAL_SIGN, UNSPECIFIC, ADD_PARTITION, DROP_PARTITION, DISCARD_PARTITION, IMPORT_PARTITION, TRUNCATE_PARTITION, COALESCE_PARTITION, REORGANIZE_PARTITION, EXCHANGE_PARTITION, ANALYZE_PARTITION, CHECK_PARTITION, OPTIMIZE_PARTITION, REBUILD_PARTITION, REPAIR_PARTITION, REMOVE_PARTITIONING, PARTITION_BY, SET_TABLE_OPTION, ENGINE, FORCE, KEY_BLOCK_SIZE, LOCK, DISCARD_TABLESPACE, IMPORT_TABLESPACE, DISABLE_KEYS, ENABLE_KEYS; + ADD, ALTER, DROP, DROP_PRIMARY_KEY, DROP_UNIQUE, DROP_FOREIGN_KEY, MODIFY, CHANGE, CONVERT, COLLATE, ALGORITHM, RENAME, RENAME_TABLE, RENAME_INDEX, RENAME_KEY, RENAME_CONSTRAINT, COMMENT, COMMENT_WITH_EQUAL_SIGN, UNSPECIFIC, ADD_PARTITION, DROP_PARTITION, DISCARD_PARTITION, IMPORT_PARTITION, TRUNCATE_PARTITION, COALESCE_PARTITION, REORGANIZE_PARTITION, EXCHANGE_PARTITION, ANALYZE_PARTITION, CHECK_PARTITION, OPTIMIZE_PARTITION, REBUILD_PARTITION, REPAIR_PARTITION, REMOVE_PARTITIONING, PARTITION_BY, SET_TABLE_OPTION, ENGINE, FORCE, KEY_BLOCK_SIZE, LOCK, DISCARD_TABLESPACE, IMPORT_TABLESPACE, DISABLE_KEYS, ENABLE_KEYS, ENABLE_ROW_LEVEL_SECURITY, DISABLE_ROW_LEVEL_SECURITY, FORCE_ROW_LEVEL_SECURITY, NO_FORCE_ROW_LEVEL_SECURITY; public static AlterOperation from(String operation) { return Enum.valueOf(AlterOperation.class, operation.toUpperCase()); diff --git a/src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java b/src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java new file mode 100644 index 000000000..7c11636aa --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java @@ -0,0 +1,131 @@ +/*- + * #%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.statement.create.policy; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +import java.util.ArrayList; +import java.util.List; + +/** + * PostgreSQL CREATE POLICY statement for Row Level Security (RLS). + * + * Syntax: CREATE POLICY name ON table_name [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO + * { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] [ USING ( using_expression ) ] [ + * WITH CHECK ( check_expression ) ] + */ +public class CreatePolicy implements Statement { + + private String policyName; + private Table table; + private String command; // ALL, SELECT, INSERT, UPDATE, DELETE + private List roles = new ArrayList<>(); + private Expression usingExpression; + private Expression withCheckExpression; + + public String getPolicyName() { + return policyName; + } + + public CreatePolicy setPolicyName(String policyName) { + this.policyName = policyName; + return this; + } + + public Table getTable() { + return table; + } + + public CreatePolicy setTable(Table table) { + this.table = table; + return this; + } + + public String getCommand() { + return command; + } + + public CreatePolicy setCommand(String command) { + this.command = command; + return this; + } + + public List getRoles() { + return roles; + } + + public CreatePolicy setRoles(List roles) { + this.roles = roles; + return this; + } + + public CreatePolicy addRole(String role) { + this.roles.add(role); + return this; + } + + public Expression getUsingExpression() { + return usingExpression; + } + + public CreatePolicy setUsingExpression(Expression usingExpression) { + this.usingExpression = usingExpression; + return this; + } + + public Expression getWithCheckExpression() { + return withCheckExpression; + } + + public CreatePolicy setWithCheckExpression(Expression withCheckExpression) { + this.withCheckExpression = withCheckExpression; + return this; + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("CREATE POLICY "); + builder.append(policyName); + builder.append(" ON "); + builder.append(table.toString()); + + if (command != null) { + builder.append(" FOR ").append(command); + } + + if (roles != null && !roles.isEmpty()) { + builder.append(" TO "); + for (int i = 0; i < roles.size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(roles.get(i)); + } + } + + if (usingExpression != null) { + builder.append(" USING (").append(usingExpression.toString()).append(")"); + } + + if (withCheckExpression != null) { + builder.append(" WITH CHECK (").append(withCheckExpression.toString()).append(")"); + } + + return builder.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index b062d2503..020332caf 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -90,6 +90,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -1845,4 +1846,28 @@ public Void visit(LockStatement lock, S context) { public void visit(LockStatement lock) { StatementVisitor.super.visit(lock); } + + @Override + public Void visit(CreatePolicy createPolicy, S context) { + if (createPolicy.getTable() != null) { + visit(createPolicy.getTable(), context); + } + + // Visit USING expression to find tables in subqueries + if (createPolicy.getUsingExpression() != null) { + createPolicy.getUsingExpression().accept(this, context); + } + + // Visit WITH CHECK expression to find tables in subqueries + if (createPolicy.getWithCheckExpression() != null) { + createPolicy.getWithCheckExpression().accept(this, context); + } + + return null; + } + + @Override + public void visit(CreatePolicy createPolicy) { + StatementVisitor.super.visit(createPolicy); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index a27aee7af..751c4bf64 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -42,6 +42,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -520,4 +521,10 @@ public StringBuilder visit(LockStatement lock, S context) { builder.append(lock.toString()); return builder; } + + @Override + public StringBuilder visit(CreatePolicy createPolicy, S context) { + builder.append(createPolicy.toString()); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index e6c42ab48..9e073a227 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -39,6 +39,7 @@ import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.function.CreateFunction; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.procedure.CreateProcedure; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; @@ -589,4 +590,14 @@ public void visit(Import imprt) { public void visit(Export export) { visit(export, null); } + + @Override + public Void visit(CreatePolicy createPolicy, S context) { + // TODO: not yet implemented + return null; + } + + public void visit(CreatePolicy createPolicy) { + visit(createPolicy, null); + } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 0f2dd1df6..36f60ed58 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -50,6 +50,7 @@ import net.sf.jsqlparser.statement.alter.sequence.*; import net.sf.jsqlparser.statement.comment.*; import net.sf.jsqlparser.statement.create.function.*; import net.sf.jsqlparser.statement.create.index.*; +import net.sf.jsqlparser.statement.create.policy.*; import net.sf.jsqlparser.statement.create.procedure.*; import net.sf.jsqlparser.statement.create.schema.*; import net.sf.jsqlparser.statement.create.synonym.*; @@ -453,6 +454,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -541,6 +543,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -590,6 +593,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -3268,7 +3272,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | 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="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXCLUSIVE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | 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="LTRIM" | 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="MODE" | tk="MODIFY" | tk="MOVEMENT" | tk="NAME" | tk="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | 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="REJECT" | 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="RTRIM" | tk="SAFE_CAST" | tk="SAFE_CONVERT" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="TRY_CONVERT" | tk="TUMBLING" | tk="TYPE" | tk="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXCLUSIVE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | 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="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | 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="KILL" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LEVEL" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="LTRIM" | 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="MODE" | tk="MODIFY" | tk="MOVEMENT" | tk="NAME" | tk="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | tk="PARALLEL" | tk="PARENT" | tk="PARSER" | tk="PARTITION" | tk="PARTITIONING" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="POLICY" | 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="REJECT" | 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="RTRIM" | tk="SAFE_CAST" | tk="SAFE_CONVERT" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SECURITY" | 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="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | 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="TRY_CONVERT" | tk="TUMBLING" | tk="TYPE" | tk="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | 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; } } @@ -3292,7 +3296,8 @@ String RelObjectNameWithoutStart() : { Token tk = null; String result = null; } { (result = RelObjectNameWithoutValue() | tk= | tk= | tk= - | tk= ) + | tk= + ) { return tk!=null ? tk.image : result; } } @@ -9491,7 +9496,19 @@ AlterExpression AlterExpression(): ) ) | - ( + LOOKAHEAD(5) ( + { + alterExp.setOperation(AlterOperation.FORCE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(5) ( + { + alterExp.setOperation(AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(1) ( { alterExp.setOperation(AlterOperation.FORCE); } ) | @@ -9641,16 +9658,28 @@ AlterExpression AlterExpression(): ) ) | - ( - (tk = ) - (tk2 = ) { + + LOOKAHEAD(4) ( + { + alterExp.setOperation(AlterOperation.DISABLE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(2) ( + { alterExp.setOperation(AlterOperation.DISABLE_KEYS); } ) + | - ( - (tk = ) - (tk2 = ) { + LOOKAHEAD(4) ( + { + alterExp.setOperation(AlterOperation.ENABLE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(2) ( + { alterExp.setOperation(AlterOperation.ENABLE_KEYS); } ) @@ -10326,6 +10355,8 @@ Statement Create(): | LOOKAHEAD(2) statement = CreateView(isUsingOrReplace) | + statement = CreatePolicy() + | // @fixme: must appear with TRIGGER before INDEX or it will collide with INDEX's CreateParameter() production ( tk= | tk= ) captureRest = captureRest() { @@ -10406,6 +10437,45 @@ Synonym Synonym() #Synonym : } } +CreatePolicy CreatePolicy() #CreatePolicy: +{ + CreatePolicy createPolicy = new CreatePolicy(); + String policyName; + Table table; + Token commandToken = null; + String roleName; + Expression usingExpr = null; + Expression checkExpr = null; +} +{ + policyName=RelObjectName() { createPolicy.setPolicyName(policyName); } + table=Table() { createPolicy.setTable(table); } + + [ + ( commandToken= + | commandToken= + | commandToken= + | commandToken= + | commandToken= + ) + { createPolicy.setCommand(commandToken.image); } + ] + + [ + roleName=RelObjectName() { createPolicy.addRole(roleName); } + ( "," roleName=RelObjectName() { createPolicy.addRole(roleName); } )* + ] + + [ "(" usingExpr=Expression() ")" { createPolicy.setUsingExpression(usingExpr); } ] + + [ LOOKAHEAD(2) "(" checkExpr=Expression() ")" { createPolicy.setWithCheckExpression(checkExpr); } ] + + { + + return createPolicy; + } +} + UnsupportedStatement UnsupportedStatement(): { List tokens = new LinkedList(); diff --git a/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java index 054b25e9a..164c9e112 100644 --- a/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.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/statement/alter/AlterRowLevelSecurityTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterRowLevelSecurityTest.java new file mode 100644 index 000000000..d91cd6341 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterRowLevelSecurityTest.java @@ -0,0 +1,115 @@ +/*- + * #%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.statement.alter; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import org.junit.jupiter.api.Test; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for PostgreSQL ALTER TABLE ... ROW LEVEL SECURITY statements + */ +public class AlterRowLevelSecurityTest { + + @Test + public void testEnableRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 ENABLE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("table1", alter.getTable().getName()); + assertEquals(AlterOperation.ENABLE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testEnableRowLevelSecurityWithSchema() throws JSQLParserException { + String sql = "ALTER TABLE customer_custom_data.phone_opt_out ENABLE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals("customer_custom_data.phone_opt_out", + alter.getTable().getFullyQualifiedName()); + assertEquals(AlterOperation.ENABLE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testDisableRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 DISABLE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.DISABLE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testForceRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 FORCE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.FORCE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testNoForceRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 NO FORCE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testMultipleStatements() throws JSQLParserException { + // Test CREATE POLICY followed by ENABLE RLS + String sql = "CREATE POLICY policy1 ON table1 USING (id = user_id()); " + + "ALTER TABLE table1 ENABLE ROW LEVEL SECURITY"; + + net.sf.jsqlparser.statement.Statements stmts = CCJSqlParserUtil.parseStatements(sql); + assertEquals(2, stmts.getStatements().size()); + + assertInstanceOf(net.sf.jsqlparser.statement.create.policy.CreatePolicy.class, + stmts.getStatements().get(0)); + assertInstanceOf(Alter.class, stmts.getStatements().get(1)); + } + + @Test + public void testEnableKeysStillWorks() throws JSQLParserException { + // Ensure our changes don't break existing ENABLE KEYS syntax + String sql = "ALTER TABLE table1 ENABLE KEYS"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.ENABLE_KEYS, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testDisableKeysStillWorks() throws JSQLParserException { + // Ensure our changes don't break existing DISABLE KEYS syntax + String sql = "ALTER TABLE table1 DISABLE KEYS"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.DISABLE_KEYS, + alter.getAlterExpressions().get(0).getOperation()); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java new file mode 100644 index 000000000..031c86b6e --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java @@ -0,0 +1,263 @@ +/*- + * #%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.statement.create; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.util.TablesNamesFinder; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for TablesNamesFinder integration with PostgreSQL CREATE POLICY statements. + * + *

+ * These tests verify that TablesNamesFinder correctly identifies ALL tables referenced in a CREATE + * POLICY statement, including: + *

    + *
  • The policy's target table
  • + *
  • Tables in USING expression subqueries
  • + *
  • Tables in WITH CHECK expression subqueries
  • + *
  • Tables in complex expressions (JOINs, CTEs, nested subqueries)
  • + *
+ * + *

+ * Current Status: These tests will FAIL until + * TablesNamesFinder.visit(CreatePolicy) is updated to traverse USING and WITH CHECK expressions. + * This is incomplete feature support, not a regression - CREATE POLICY parsing works correctly, but + * analysis tools don't yet have complete integration. + * + *

+ * Expected Behavior: Once fixed, TablesNamesFinder should find tables in policy + * expressions using the same pattern as other statements (CreateView, Insert, Update). + */ +public class CreatePolicyTablesFinderTest { + + // ========================================================================= + // Helper Methods + // ========================================================================= + + /** + * Parse SQL and extract table names using TablesNamesFinder. + */ + private List getTablesFromSQL(String sql) throws JSQLParserException { + Statement stmt = CCJSqlParserUtil.parse(sql); + TablesNamesFinder finder = new TablesNamesFinder(); + return finder.getTableList(stmt); + } + + /** + * Assert that the actual table list contains exactly the expected tables. + */ + private void assertContainsAllTables(List actual, String... expected) { + assertEquals(expected.length, actual.size(), + "Expected " + expected.length + " tables but found " + actual.size() + ". " + + "Expected: " + java.util.Arrays.toString(expected) + ", " + + "Actual: " + actual); + + for (String table : expected) { + assertTrue(actual.contains(table), + "Expected to find table '" + table + "' but it was missing. " + + "Found tables: " + actual); + } + } + + // ========================================================================= + // Simple Subqueries - Basic USE Cases + // ========================================================================= + + @Test + public void testTablesFinderWithSubqueryInUsing() throws JSQLParserException { + String sql = "CREATE POLICY tenant_policy ON documents " + + "USING (tenant_id IN (SELECT tenant_id FROM tenant_access))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in USING subquery + assertContainsAllTables(tables, "documents", "tenant_access"); + } + + @Test + public void testTablesFinderWithSubqueryInWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY data_policy ON user_data " + + "WITH CHECK (status IN (SELECT allowed_status FROM status_config))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in WITH CHECK subquery + assertContainsAllTables(tables, "user_data", "status_config"); + } + + @Test + public void testTablesFinderWithBothUsingAndWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY dual_check_policy ON records " + + "USING (user_id IN (SELECT id FROM active_users)) " + + "WITH CHECK (status IN (SELECT status FROM valid_statuses))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in USING + table in WITH CHECK + assertContainsAllTables(tables, "records", "active_users", "valid_statuses"); + } + + // ========================================================================= + // Complex Expressions - Multiple/Nested Subqueries + // ========================================================================= + + @Test + public void testTablesFinderWithMultipleSubqueries() throws JSQLParserException { + String sql = "CREATE POLICY complex_policy ON documents " + + "USING (" + + " tenant_id IN (SELECT tenant_id FROM tenant_access) " + + " AND status IN (SELECT status FROM allowed_statuses) " + + " AND department_id = (SELECT id FROM departments WHERE name = 'Engineering')" + + ")"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + 3 tables from subqueries + assertContainsAllTables(tables, "documents", "tenant_access", "allowed_statuses", + "departments"); + } + + @Test + public void testTablesFinderWithNestedSubqueries() throws JSQLParserException { + String sql = "CREATE POLICY nested_policy ON orders " + + "USING (customer_id IN (" + + " SELECT customer_id FROM customer_access " + + " WHERE region_id IN (SELECT id FROM regions WHERE active = true)" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + tables from nested subqueries + assertContainsAllTables(tables, "orders", "customer_access", "regions"); + } + + @Test + public void testTablesFinderWithJoinsInSubquery() throws JSQLParserException { + String sql = "CREATE POLICY join_policy ON orders " + + "USING (EXISTS (" + + " SELECT 1 FROM customers c " + + " JOIN customer_access ca ON c.id = ca.customer_id " + + " WHERE c.id = orders.customer_id" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + tables from JOIN in subquery + assertContainsAllTables(tables, "orders", "customers", "customer_access"); + } + + // ========================================================================= + // Advanced SQL Features - CTEs, Schema Qualification, Functions + // ========================================================================= + + @Test + public void testTablesFinderWithCTE() throws JSQLParserException { + String sql = "CREATE POLICY cte_policy ON documents " + + "USING (tenant_id IN (" + + " WITH active_tenants AS (SELECT id FROM tenants WHERE active = true) " + + " SELECT id FROM active_tenants" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table referenced in CTE + assertContainsAllTables(tables, "documents", "tenants"); + } + + @Test + public void testTablesFinderWithSchemaQualifiedTables() throws JSQLParserException { + String sql = "CREATE POLICY schema_policy ON myschema.documents " + + "USING (tenant_id IN (SELECT id FROM otherschema.tenants))"; + + List tables = getTablesFromSQL(sql); + + // Should find both schema-qualified tables + assertEquals(2, tables.size(), + "Should find both schema-qualified tables. Found: " + tables); + + // Check if tables are found (with or without schema prefix depending on TablesNamesFinder + // behavior) + boolean foundDocuments = tables.stream() + .anyMatch(t -> t.contains("documents")); + boolean foundTenants = tables.stream() + .anyMatch(t -> t.contains("tenants")); + + assertTrue(foundDocuments, "Should find documents table. Found: " + tables); + assertTrue(foundTenants, "Should find tenants table. Found: " + tables); + } + + @Test + public void testTablesFinderWithTableFunctions() throws JSQLParserException { + // PostgreSQL table-valued functions can be used in FROM clauses + String sql = "CREATE POLICY function_policy ON documents " + + "USING (tenant_id IN (" + + " SELECT tenant_id FROM get_accessible_tenants(current_user_id())" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should at least find the target table + // Note: Table-valued functions might not be reported as "tables" depending on + // implementation + assertTrue(tables.contains("documents"), + "Should at least find the target table. Found: " + tables); + } + + // ========================================================================= + // Edge Cases - EXISTS, UNION, Empty Policies + // ========================================================================= + + @Test + public void testTablesFinderWithExistsClause() throws JSQLParserException { + String sql = "CREATE POLICY exists_policy ON documents " + + "USING (EXISTS (" + + " SELECT 1 FROM tenant_access " + + " WHERE tenant_id = documents.tenant_id AND active = true" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in EXISTS subquery + assertContainsAllTables(tables, "documents", "tenant_access"); + } + + @Test + public void testTablesFinderWithUnionInSubquery() throws JSQLParserException { + String sql = "CREATE POLICY union_policy ON documents " + + "USING (tenant_id IN (" + + " SELECT tenant_id FROM primary_tenants " + + " UNION " + + " SELECT tenant_id FROM secondary_tenants" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + both tables in UNION + assertContainsAllTables(tables, "documents", "primary_tenants", "secondary_tenants"); + } + + @Test + public void testTablesFinderEmptyPolicy() throws JSQLParserException { + // Policy with no USING or WITH CHECK clauses + String sql = "CREATE POLICY simple_policy ON documents"; + + List tables = getTablesFromSQL(sql); + + // Should only find the target table + assertContainsAllTables(tables, "documents"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java new file mode 100644 index 000000000..829efd2c7 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java @@ -0,0 +1,158 @@ +/*- + * #%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.statement.create; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; +import org.junit.jupiter.api.Test; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for PostgreSQL CREATE POLICY statement (Row Level Security) + */ +public class CreatePolicyTest { + + @Test + public void testCreatePolicyBasic() throws JSQLParserException { + String sql = "CREATE POLICY policy_name ON table_name"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(CreatePolicy.class, stmt); + CreatePolicy policy = (CreatePolicy) stmt; + assertEquals("policy_name", policy.getPolicyName()); + assertEquals("table_name", policy.getTable().getName()); + } + + @Test + public void testCreatePolicyWithSchema() throws JSQLParserException { + String sql = + "CREATE POLICY single_tenant_access_policy ON customer_custom_data.phone_opt_out"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Statement stmt = CCJSqlParserUtil.parse(sql); + CreatePolicy policy = (CreatePolicy) stmt; + assertEquals("single_tenant_access_policy", policy.getPolicyName()); + assertEquals("customer_custom_data.phone_opt_out", + policy.getTable().getFullyQualifiedName()); + } + + @Test + public void testCreatePolicyWithForClause() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 FOR SELECT"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals("SELECT", policy.getCommand()); + } + + @Test + public void testCreatePolicyWithAllCommands() throws JSQLParserException { + String[] commands = {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE"}; + for (String cmd : commands) { + String sql = "CREATE POLICY p ON t FOR " + cmd; + assertSqlCanBeParsedAndDeparsed(sql, true); + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals(cmd, policy.getCommand()); + } + } + + @Test + public void testCreatePolicyWithSingleRole() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 TO role1"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals(1, policy.getRoles().size()); + assertEquals("role1", policy.getRoles().get(0)); + } + + @Test + public void testCreatePolicyWithMultipleRoles() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 TO role1, role2, role3"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals(3, policy.getRoles().size()); + assertEquals("role1", policy.getRoles().get(0)); + assertEquals("role2", policy.getRoles().get(1)); + assertEquals("role3", policy.getRoles().get(2)); + } + + @Test + public void testCreatePolicyWithUsing() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 USING (user_id = current_user_id())"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertNotNull(policy.getUsingExpression()); + } + + @Test + public void testCreatePolicyWithWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 WITH CHECK (status = 'active')"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertNotNull(policy.getWithCheckExpression()); + } + + @Test + public void testCreatePolicyComplete() throws JSQLParserException { + String sql = + "CREATE POLICY single_tenant_access_policy ON customer_custom_data.phone_opt_out " + + "FOR SELECT " + + "TO gong_app_single_tenant_ro_role, gong_app_single_tenant_rw_role " + + "USING (company_id = current_setting('gong.tenant.company_id')::bigint)"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals("single_tenant_access_policy", policy.getPolicyName()); + assertEquals("customer_custom_data.phone_opt_out", + policy.getTable().getFullyQualifiedName()); + assertEquals("SELECT", policy.getCommand()); + assertEquals(2, policy.getRoles().size()); + assertNotNull(policy.getUsingExpression()); + } + + @Test + public void testCreatePolicyWithBothUsingAndWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 " + + "USING (department_id = current_user_department()) " + + "WITH CHECK (status IN ('draft', 'published'))"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertNotNull(policy.getUsingExpression()); + assertNotNull(policy.getWithCheckExpression()); + } + + @Test + public void testCreatePolicyCompleteWithAllClauses() throws JSQLParserException { + String sql = "CREATE POLICY admin_policy ON documents " + + "FOR UPDATE " + + "TO admin_role, superuser " + + "USING (author_id = current_user_id()) " + + "WITH CHECK (updated_at >= CURRENT_TIMESTAMP)"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals("admin_policy", policy.getPolicyName()); + assertEquals("documents", policy.getTable().getName()); + assertEquals("UPDATE", policy.getCommand()); + assertEquals(2, policy.getRoles().size()); + assertNotNull(policy.getUsingExpression()); + assertNotNull(policy.getWithCheckExpression()); + } +} From 8d967803c780f5facaea4295f84fcd3c4306962b Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 21 Nov 2025 03:17:13 +0100 Subject: [PATCH 121/123] [fix] Enable qualified table name for DROP INDEX command (#2344) Thank you for your contribution. --- .../jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 11 +++++++++-- .../net/sf/jsqlparser/statement/drop/DropTest.java | 10 ++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 36f60ed58..c4840d16b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -8787,8 +8787,15 @@ Drop Drop(): name = Table() { drop.setName(name); } [ LOOKAHEAD(2) funcArgs = FuncArgsList() ] - ((tk= | tk= | tk= | tk=) { dropArgs.add(tk.image); })* - + ( + ( + tk= | tk= | tk= + ) { dropArgs.add(tk.image); } + | + ( + name = Table() { dropArgs.add("ON"); dropArgs.add(name.toString()); } + ) + )* { if (dropArgs.size() > 0) { drop.setParameters(dropArgs); diff --git a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java index 75d4524c7..a48b2fe7d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java @@ -53,6 +53,16 @@ public void testDropIndexOnTable() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("DROP INDEX idx ON abc"); } + @Test + public void testDropIndexOnQualifiedTable() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("DROP INDEX idx ON qual.tbl"); + } + + @Test + public void testDropIndexOnDoubleQualifiedTable() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("DROP INDEX idx ON dbl.qual.tbl"); + } + @Test public void testDrop2() throws JSQLParserException { Drop drop = (Drop) parserManager.parse(new StringReader("DROP TABLE \"testtable\"")); From 2d83cea9ba65a7ca1cf30bcec218e64e6b9029de Mon Sep 17 00:00:00 2001 From: Will Needham <136266921+willneedham93@users.noreply.github.com> Date: Fri, 21 Nov 2025 02:18:54 +0000 Subject: [PATCH 122/123] [feat] Add 'K_DATA' to KeywordOrIdentifier to allow usages of 'data' as an identifier (#2340) Allows for support of data as a column name when changing or dropping a column in an alter table statement --- .../jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 7 ++++--- .../net/sf/jsqlparser/statement/alter/AlterTest.java | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index c4840d16b..3a685f0fa 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -890,7 +890,7 @@ TOKEN: * Supported tokens: * - : Standard unquoted SQL identifier * - : Quoted identifier (e.g., `identifier` or "identifier") - * - , , , , : Specific keywords treated as identifiers + * - , , , , , : Specific keywords treated as identifiers * * @return Token representing the identifier or keyword used as identifier */ @@ -907,6 +907,7 @@ Token KeywordOrIdentifier(): | tk = | tk = | tk = + | tk = ) { return tk; } } @@ -9426,7 +9427,7 @@ AlterExpression AlterExpression(): { alterExp.setOperation(AlterOperation.CHANGE); } [ { alterExp.hasColumn(true); alterExp.setOptionalSpecifier("COLUMN"); } ] ( - (tk= | tk=) + (tk=KeywordOrIdentifier()) alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.withColumnOldName(tk.image).addColDataType(alterExpressionColumnDataType); } ) ) @@ -9460,7 +9461,7 @@ AlterExpression AlterExpression(): ( LOOKAHEAD(2) { alterExp.hasColumn(true); } )? [ { alterExp.setUsingIfExists(true); } ] // @todo: replace with a proper identifier - (tk= | tk= | tk=) { alterExp.setColumnName(tk.image); } + (tk=KeywordOrIdentifier() ) { alterExp.setColumnName(tk.image); } [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java index 559517b9d..749e12853 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java @@ -249,6 +249,11 @@ public void testAlterTableDropColumn2() throws JSQLParserException { assertEquals("col2", col2Exp.getColumnName()); } + @Test + public void testAlterTableDropColumnIssue2339() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("ALTER TABLE test DROP COLUMN Data"); + } + @Test public void testAlterTableDropConstraint() throws JSQLParserException { final String sql = "ALTER TABLE test DROP CONSTRAINT YYY"; @@ -455,6 +460,11 @@ public void testAlterTableChangeColumn4() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("ALTER TABLE tb_test CHANGE c1 c2 INT (10)"); } + @Test + public void testAlterTableChangeColumnIssue2339() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("ALTER TABLE tb_test CHANGE data INT (10)"); + } + @Test public void testAlterTableAddColumnWithZone() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( From 40ccf4b87171494e83cc28bea2ef233213da93ce Mon Sep 17 00:00:00 2001 From: mjog Date: Fri, 21 Nov 2025 18:21:30 +1100 Subject: [PATCH 123/123] Support PostgreSQL-specific [CREATE SEQUENCE name START n ...] (#2348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support PostgreSQL-specific [CREATE SEQUENCE name START n ...] I.e. no `START WITH` Fixes #2347 * Support PostgreSQL-specific [CREATE SEQUENCE … INCREMENT n ...] I.e. no `INCREMENT BY` Fixes #2347 --- .../net/sf/jsqlparser/schema/Sequence.java | 6 +++++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 18 ++++++++++++++---- .../statement/create/CreateSequenceTest.java | 10 ++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Sequence.java b/src/main/java/net/sf/jsqlparser/schema/Sequence.java index 2f813c1d7..083122434 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Sequence.java +++ b/src/main/java/net/sf/jsqlparser/schema/Sequence.java @@ -158,7 +158,7 @@ public Sequence addParameters(Collection parameters) { * The available parameters to a sequence */ public enum ParameterType { - INCREMENT_BY, START_WITH, RESTART_WITH, MAXVALUE, NOMAXVALUE, MINVALUE, NOMINVALUE, CYCLE, NOCYCLE, CACHE, NOCACHE, ORDER, NOORDER, KEEP, NOKEEP, SESSION, GLOBAL; + INCREMENT_BY, INCREMENT, START_WITH, START, RESTART_WITH, MAXVALUE, NOMAXVALUE, MINVALUE, NOMINVALUE, CYCLE, NOCYCLE, CACHE, NOCACHE, ORDER, NOORDER, KEEP, NOKEEP, SESSION, GLOBAL; public static ParameterType from(String type) { return Enum.valueOf(ParameterType.class, type.toUpperCase()); @@ -189,8 +189,12 @@ public String formatParameter() { switch (option) { case INCREMENT_BY: return prefix("INCREMENT BY"); + case INCREMENT: + return prefix("INCREMENT"); case START_WITH: return prefix("START WITH"); + case START: + return prefix("START"); case RESTART_WITH: if (value != null) { return prefix("RESTART WITH"); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 3a685f0fa..74d36e5a5 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -10217,23 +10217,33 @@ List SequenceParameters(): List sequenceParameters = new ArrayList(); Sequence.Parameter parameter = null; Token token = null; + Token byToken = null; + Token withToken = null; } { ( LOOKAHEAD(2) ( ( - token= + [ byToken= ] token= { - parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT_BY); + if (byToken != null) { + parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT_BY); + } else { + parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT); + } parameter.setValue(Long.parseLong(token.image)); sequenceParameters.add(parameter); } ) | ( - token= + [ withToken= ] token= { - parameter = new Sequence.Parameter(Sequence.ParameterType.START_WITH); + if (withToken != null) { + parameter = new Sequence.Parameter(Sequence.ParameterType.START_WITH); + } else { + parameter = new Sequence.Parameter(Sequence.ParameterType.START); + } parameter.setValue(Long.parseLong(token.image)); sequenceParameters.add(parameter); } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java index db4e1984d..2ef0de36f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java @@ -39,11 +39,21 @@ public void testCreateSequence_withIncrement() throws JSQLParserException { statement); } + @Test + public void testCreateSequence_withIncrementPostres() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE db.schema.my_seq INCREMENT 1"); + } + @Test public void testCreateSequence_withStart() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_seq START WITH 10"); } + @Test + public void testCreateSequence_withStartPostgres() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_seq START 10"); + } + @Test public void testCreateSequence_withMaxValue() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_seq MAXVALUE 5");