From 39636005f1f947ae7d3ef14c910eac64aad800db Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sun, 20 Aug 2023 09:57:59 +0700 Subject: [PATCH] refactor: TableFunction extends Function, supports `LATERAL` prefix - implements `Function`, extends `FromItem` - supports `LATERAL` prefix - fixes #1835 Signed-off-by: Andreas Reichel --- .../statement/select/TableFunction.java | 87 ++++++++++++++++--- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 12 +-- .../builder/ReflectionModelTest.java | 2 +- .../statement/select/SelectTest.java | 2 +- .../statement/select/TableFunctionTest.java | 25 ++++++ 5 files changed, 107 insertions(+), 21 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java diff --git a/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java b/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java index 8dcfacecb..44309b1a9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java @@ -13,31 +13,59 @@ import net.sf.jsqlparser.expression.Function; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class TableFunction extends SelectItem implements FromItem { +public class TableFunction extends Function implements FromItem { + private String prefix = null; + private Alias alias = null; + private Pivot pivot = null; + private UnPivot unPivot = null; + private Function function; - @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public TableFunction(Function function) { + this.function = function; } - @Override - public Pivot getPivot() { - return null; + public TableFunction(String prefix, Function function) { + this.prefix = prefix; + this.function = function; } - @Override - public void setPivot(Pivot pivot) { + public Function getFunction() { + return function; + } + @Deprecated + public Function getExpression() { + return getFunction(); + } + + + public TableFunction setFunction(Function function) { + this.function = function; + return this; + } + + public String getPrefix() { + return prefix; + } + + public TableFunction setPrefix(String prefix) { + this.prefix = prefix; + return this; } @Override - public UnPivot getUnPivot() { - return null; + public void accept(FromItemVisitor fromItemVisitor) { + fromItemVisitor.visit(this); } @Override - public void setUnPivot(UnPivot unpivot) { + public Alias getAlias() { + return alias; + } + @Override + public void setAlias(Alias alias) { + this.alias = alias; } @Override @@ -46,8 +74,13 @@ public TableFunction withAlias(Alias alias) { } @Override - public TableFunction withExpression(Function function) { - return (TableFunction) super.withExpression(function); + public Pivot getPivot() { + return pivot; + } + + @Override + public void setPivot(Pivot pivot) { + this.pivot = pivot; } @Override @@ -55,9 +88,35 @@ public TableFunction withPivot(Pivot pivot) { return (TableFunction) FromItem.super.withPivot(pivot); } + @Override + public UnPivot getUnPivot() { + return unPivot; + } + + @Override + public void setUnPivot(UnPivot unPivot) { + this.unPivot = unPivot; + } + @Override public TableFunction withUnPivot(UnPivot unpivot) { return (TableFunction) FromItem.super.withUnPivot(unpivot); } + public StringBuilder appendTo(StringBuilder builder) { + if (prefix != null) { + builder.append(prefix).append(" "); + } + builder.append(function.toString()); + + if (alias != null) { + builder.append(alias); + } + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 60a3473c4..5cbf1b367 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5063,16 +5063,18 @@ MySQLGroupConcat MySQLGroupConcat():{ TableFunction TableFunction(): { - Alias alias = null; + Token prefix = null; Function function; TableFunction functionItem; } { - function=Function() { - functionItem = new TableFunction().withExpression(function); + [ prefix = ] + function=Function() + { + return prefix!=null + ? new TableFunction(prefix.image, function) + : new TableFunction(function); } - [LOOKAHEAD(2) alias=Alias() { functionItem.setAlias(alias); }] - { return functionItem; } } List ColumnNamesWithParamsList() : { 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 497be3371..6027a286e 100644 --- a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java @@ -194,7 +194,7 @@ public class ReflectionModelTest { // new net.sf.jsqlparser.statement.select.SetOperationList(), new net.sf.jsqlparser.statement.select.Skip(), // new net.sf.jsqlparser.statement.select.ParenthesedSelect(), - new net.sf.jsqlparser.statement.select.TableFunction(), + // new net.sf.jsqlparser.statement.select.TableFunction("LATERAL", new Function()), new net.sf.jsqlparser.statement.select.Top(), new net.sf.jsqlparser.statement.select.UnPivot(), new net.sf.jsqlparser.statement.select.UnionOp(), 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 498c21949..b35d62e15 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -3349,7 +3349,7 @@ public void testTableFunctionWithNoParams() throws Exception { assertTrue(plainSelect.getFromItem() instanceof TableFunction); TableFunction fromItem = (TableFunction) plainSelect.getFromItem(); - Function function = fromItem.getExpression(); + Function function = fromItem.getFunction(); assertNotNull(function); assertEquals("SOME_FUNCTION", function.getName()); assertNull(function.getParameters()); diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java new file mode 100644 index 000000000..867a1f011 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java @@ -0,0 +1,25 @@ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class TableFunctionTest { + + @Test + void testLateralFlat() throws JSQLParserException { + String sqlStr = "WITH t AS (\n" + + " SELECT \n" + + " 'ABC' AS dim, \n" + + " ARRAY_CONSTRUCT('item1', 'item2', 'item3') AS user_items\n" + + ")\n" + + "SELECT DIM, count(value) as COUNT_\n" + + "FROM t a,\n" + + "LATERAL FLATTEN(input => a.user_items) b\n" + + "group by 1"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + +}