diff --git a/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java b/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java index 85734fed1..252d6b8cd 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java @@ -57,7 +57,8 @@ public class PlainSelect implements SelectBody { private boolean forUpdate = false; private Table forUpdateTable = null; private boolean useBrackets = false; - + private Wait wait; + public boolean isUseBrackets() { return useBrackets; } @@ -266,6 +267,25 @@ public OracleHint getOracleHint() { public void setOracleHint(OracleHint oracleHint) { this.oracleHint = oracleHint; } + + /** + * Sets the {@link Wait} for this SELECT + * + * @param wait + * the {@link Wait} for this SELECT + */ + public void setWait(final Wait wait) { + this.wait = wait; + } + + /** + * Returns the value of the {@link Wait} set for this SELECT + * + * @return the value of the {@link Wait} set for this SELECT + */ + public Wait getWait() { + return wait; + } @Override public String toString() { @@ -344,6 +364,11 @@ public String toString() { if (forUpdateTable != null) { sql.append(" OF ").append(forUpdateTable); } + + if (wait != null) { + // Wait's toString will do the formatting for us + sql.append(wait); + } } } else { //without from @@ -432,4 +457,4 @@ public static String getStringList(List list, boolean useComma, boolean useBr return ans.toString(); } -} +} \ No newline at end of file diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Wait.java b/src/main/java/net/sf/jsqlparser/statement/select/Wait.java new file mode 100644 index 000000000..f9d4f82bb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/Wait.java @@ -0,0 +1,52 @@ +/* + * #%L JSQLParser library %% Copyright (C) 2004 - 2017 JSQLParser %% This program is free software: + * you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 2.1 of the License, or (at your + * option) any later version. This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Lesser Public License for more details. You should have + * received a copy of the GNU General Lesser Public License along with this program. If not, see + * . #L% + */ +package net.sf.jsqlparser.statement.select; + +/** + * A timeout applied to SELECT to specify how long to wait for the row on the + * lock to be released. + * + * @author janmonterrubio + */ +public class Wait { + private long timeout; + + /** + * Returns the number of seconds specified for the WAIT command + * + * @return the number of seconds specified for the WAIT command + */ + public long getTimeout() { + return timeout; + } + + /** + * Sets the number of seconds to WAIT for this {@link Wait} + * + * @param timeout + * the number of seconds to WAIT for this {@link Wait} + */ + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + /** + * Returns a String containing the WAIT clause and its timeout, where + * TIMEOUT is specified by {@link #getTimeout()}. The returned string will + * be: + * " WAIT <TIMEOUT>" + * + */ + @Override + public String toString() { + return " WAIT " + timeout; + } +} 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 03cd864fd..cc0929771 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -168,6 +168,10 @@ public void visit(PlainSelect plainSelect) { if (plainSelect.getForUpdateTable() != null) { buffer.append(" OF ").append(plainSelect.getForUpdateTable()); } + if (plainSelect.getWait() != null) { + // wait's toString will do the formatting for us + buffer.append(plainSelect.getWait()); + } } if (plainSelect.isUseBrackets()) { buffer.append(")"); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 3693b832f..0a028840b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -255,6 +255,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| } TOKEN : /* Stuff */ @@ -889,6 +890,7 @@ PlainSelect PlainSelect(): OracleHierarchicalExpression oracleHierarchicalQueryClause = null; List intoTables = null; Table updateTable = null; + Wait wait = null; } { @@ -931,8 +933,9 @@ PlainSelect PlainSelect(): [LOOKAHEAD() offset = Offset() { plainSelect.setOffset(offset); } ] [LOOKAHEAD() fetch = Fetch() { plainSelect.setFetch(fetch); } ] - [ { plainSelect.setForUpdate(true); } - [ updateTable = Table() { plainSelect.setForUpdateTable(updateTable); } ] ] + [ { plainSelect.setForUpdate(true); } + [ updateTable = Table() { plainSelect.setForUpdateTable(updateTable); } ] + [ LOOKAHEAD() wait = Wait() { plainSelect.setWait(wait); } ] ] { plainSelect.setSelectItems(selectItems); @@ -3220,3 +3223,18 @@ Alter AlterTable(): return alter; } } + +Wait Wait(): +{ + Wait wait = new Wait(); + Token token = null; +} +{ + // sqlserver-oracle-> WAIT (TIMEOUT) + // https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10002.htm#i2126016 + token= { wait.setTimeout(Long.parseLong(token.image)); } + + { + return wait; + } +} \ No newline at end of file diff --git a/src/test/java/net/sf/jsqlparser/test/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/test/select/SelectTest.java index db09d2bbe..4d9f160c6 100644 --- a/src/test/java/net/sf/jsqlparser/test/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/test/select/SelectTest.java @@ -2482,6 +2482,29 @@ public void testKeyWorkReplaceIssue393() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT replace(\"aaaabbb\", 4, 4, \"****\")"); } + /** + * Validates that a SELECT with FOR UPDATE WAIT can be parsed and + * deparsed + */ + public void testForUpdateWaitParseDeparse() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("SELECT * FROM mytable FOR UPDATE WAIT 60"); + } + + /** + * Validates that a SELECT with FOR UPDATE WAIT correctly sets a + * {@link Wait} with the correct timeout value. + */ + public void testForUpdateWaitWithTimeout() throws JSQLParserException { + String statement = "SELECT * FROM mytable FOR UPDATE WAIT 60"; + Select select = (Select) parserManager.parse(new StringReader(statement)); + PlainSelect ps = (PlainSelect) select.getSelectBody(); + Wait wait = ps.getWait(); + assertNotNull("wait should not be null", wait); + + long waitTime = wait.getTimeout(); + assertEquals("wait time should be 60", waitTime, 60L); + } + // public void testSubSelectFailsIssue394() throws JSQLParserException { // assertSqlCanBeParsedAndDeparsed("select aa.* , t.* from accenter.all aa, (select a.* from pacioli.emc_plan a) t"); // }