Skip to content

Commit 9df19b9

Browse files
authored
partial func support (#1000)
1 parent 7a19a9b commit 9df19b9

File tree

9 files changed

+255
-13
lines changed

9 files changed

+255
-13
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2020 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement;
11+
12+
import java.util.List;
13+
14+
/**
15+
* A base for the declaration of function like statements
16+
*/
17+
public abstract class CreateFunctionalStatement implements Statement {
18+
19+
private String kind;
20+
private List<String> functionDeclarationParts;
21+
22+
protected CreateFunctionalStatement(String kind, List<String> functionDeclarationParts) {
23+
this.kind = kind;
24+
this.functionDeclarationParts = functionDeclarationParts;
25+
}
26+
27+
/**
28+
* @return the declaration parts after {@code CREATE FUNCTION|PROCEDURE}
29+
*/
30+
public List<String> getFunctionDeclarationParts() {
31+
return functionDeclarationParts;
32+
}
33+
34+
/**
35+
* @return the kind of functional statement
36+
*/
37+
public String getKind() {
38+
return kind;
39+
}
40+
41+
/**
42+
* @return a whitespace appended String with the declaration parts with some minimal formatting.
43+
*/
44+
public String formatDeclaration() {
45+
StringBuilder declaration = new StringBuilder();
46+
47+
int currIndex = 0;
48+
while (currIndex < functionDeclarationParts.size()) {
49+
String token = functionDeclarationParts.get(currIndex);
50+
declaration.append(token);
51+
52+
// if the next token is a ; don't put a space
53+
if (currIndex + 1 < functionDeclarationParts.size()) {
54+
// peek ahead just to format nicely
55+
String nextToken = functionDeclarationParts.get(currIndex+1);
56+
if (!nextToken.equals(";")) {
57+
declaration.append(" ");
58+
}
59+
}
60+
currIndex++;
61+
}
62+
63+
return declaration.toString();
64+
}
65+
66+
@Override
67+
public void accept(StatementVisitor statementVisitor) {
68+
statementVisitor.visit(this);
69+
}
70+
71+
@Override
72+
public String toString() {
73+
return "CREATE " + kind + " " + formatDeclaration();
74+
}
75+
}

src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,6 @@ public interface StatementVisitor {
9494
void visit(CreateSequence createSequence);
9595

9696
void visit(AlterSequence alterSequence);
97+
98+
void visit(CreateFunctionalStatement createFunctionalStatement);
9799
}

src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,8 @@ public void visit(CreateSequence createSequence) {
175175
@Override
176176
public void visit(AlterSequence alterSequence) {
177177
}
178+
179+
@Override
180+
public void visit(CreateFunctionalStatement createFunctionalStatement) {
181+
}
178182
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2020 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.create.function;
11+
12+
import net.sf.jsqlparser.statement.CreateFunctionalStatement;
13+
14+
import java.util.List;
15+
16+
/**
17+
* A {@code CREATE PROCEDURE} statement
18+
*/
19+
public class CreateFunction extends CreateFunctionalStatement {
20+
21+
public CreateFunction(List<String> functionDeclarationParts) {
22+
super("FUNCTION", functionDeclarationParts);
23+
}
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2020 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.create.procedure;
11+
12+
import net.sf.jsqlparser.statement.CreateFunctionalStatement;
13+
14+
import java.util.List;
15+
16+
/**
17+
* A {@code CREATE PROCEDURE} statement
18+
*/
19+
public class CreateProcedure extends CreateFunctionalStatement {
20+
21+
public CreateProcedure(List<String> functionDeclarationParts) {
22+
super("PROCEDURE", functionDeclarationParts);
23+
}
24+
25+
}

src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,7 @@
5656
import net.sf.jsqlparser.expression.operators.relational.*;
5757
import net.sf.jsqlparser.schema.Column;
5858
import net.sf.jsqlparser.schema.Table;
59-
import net.sf.jsqlparser.statement.Block;
60-
import net.sf.jsqlparser.statement.Commit;
61-
import net.sf.jsqlparser.statement.DeclareStatement;
62-
import net.sf.jsqlparser.statement.DescribeStatement;
63-
import net.sf.jsqlparser.statement.ExplainStatement;
64-
import net.sf.jsqlparser.statement.SetStatement;
65-
import net.sf.jsqlparser.statement.ShowColumnsStatement;
66-
import net.sf.jsqlparser.statement.ShowStatement;
67-
import net.sf.jsqlparser.statement.Statement;
68-
import net.sf.jsqlparser.statement.StatementVisitor;
69-
import net.sf.jsqlparser.statement.Statements;
70-
import net.sf.jsqlparser.statement.UseStatement;
59+
import net.sf.jsqlparser.statement.*;
7160
import net.sf.jsqlparser.statement.alter.Alter;
7261
import net.sf.jsqlparser.statement.alter.sequence.AlterSequence;
7362
import net.sf.jsqlparser.statement.comment.Comment;
@@ -885,4 +874,9 @@ public void visit(CreateSequence createSequence) {
885874
public void visit(AlterSequence alterSequence) {
886875
throw new UnsupportedOperationException("Finding tables from AlterSequence is not supported");
887876
}
877+
878+
@Override
879+
public void visit(CreateFunctionalStatement createFunctionalStatement) {
880+
throw new UnsupportedOperationException("Finding tables from CreateFunctionalStatement is not supported");
881+
}
888882
}

src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package net.sf.jsqlparser.util.deparser;
1111

1212
import java.util.Iterator;
13+
1314
import java.util.stream.Collectors;
1415

1516
import net.sf.jsqlparser.statement.Block;
@@ -305,4 +306,9 @@ public void visit(CreateSequence createSequence) {
305306
public void visit(AlterSequence alterSequence) {
306307
new AlterSequenceDeParser(buffer).deParse(alterSequence);
307308
}
309+
310+
@Override
311+
public void visit(CreateFunctionalStatement createFunctionalStatement) {
312+
buffer.append(createFunctionalStatement.toString());
313+
}
308314
}

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ import net.sf.jsqlparser.statement.*;
3939
import net.sf.jsqlparser.statement.alter.*;
4040
import net.sf.jsqlparser.statement.alter.sequence.*;
4141
import net.sf.jsqlparser.statement.comment.*;
42+
import net.sf.jsqlparser.statement.create.function.*;
4243
import net.sf.jsqlparser.statement.create.index.*;
44+
import net.sf.jsqlparser.statement.create.procedure.*;
4345
import net.sf.jsqlparser.statement.create.schema.*;
4446
import net.sf.jsqlparser.statement.create.sequence.*;
4547
import net.sf.jsqlparser.statement.create.table.*;
@@ -199,6 +201,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
199201
| <K_FROM:"FROM">
200202
| <K_FULL:"FULL">
201203
| <K_FULLTEXT:"FULLTEXT">
204+
| <K_FUNCTION:"FUNCTION">
202205
| <K_GLOBAL:"GLOBAL">
203206
| <K_GRANT:"GRANT">
204207
| <K_GROUP:"GROUP">
@@ -280,6 +283,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
280283
| <K_PRECISION : "PRECISION">
281284
| <K_PRIMARY:"PRIMARY">
282285
| <K_PRIOR:"PRIOR">
286+
| <K_PROCEDURE:"PROCEDURE">
283287
| <K_RANGE: "RANGE">
284288
| <K_READ: "READ" >
285289
| <K_RECURSIVE:"RECURSIVE">
@@ -458,6 +462,9 @@ Statement SingleStatement() :
458462
|
459463
stm = Merge()
460464
|
465+
LOOKAHEAD(CreateFunctionStatement())
466+
stm = CreateFunctionStatement()
467+
|
461468
LOOKAHEAD(CreateIndex())
462469
stm = CreateIndex()
463470
|
@@ -1322,7 +1329,7 @@ String RelObjectNameExt():
13221329
{
13231330
( result=RelObjectName() | tk=<K_LEFT> | tk=<K_RIGHT> | tk=<K_SET>
13241331
| tk=<K_DOUBLE> | tk=<K_IF> | <K_OPTIMIZE> | tk=<K_LIMIT>
1325-
| tk=<K_OFFSET> )
1332+
| tk=<K_OFFSET> | tk=<K_PROCEDURE> )
13261333
{
13271334
if (tk!=null) result=tk.image;
13281335
return result;
@@ -4966,3 +4973,44 @@ AlterSequence AlterSequence():
49664973
return alterSequence;
49674974
}
49684975
}
4976+
4977+
CreateFunctionalStatement CreateFunctionStatement():
4978+
{
4979+
CreateFunctionalStatement type = null;
4980+
List<String> tokens = new LinkedList<String>();
4981+
String statementType = null;
4982+
}
4983+
{
4984+
<K_CREATE>
4985+
(
4986+
<K_FUNCTION> { statementType = "FUNCTION"; }
4987+
|
4988+
<K_PROCEDURE> { statementType = "PROCEDURE"; }
4989+
)
4990+
tokens=captureRest()
4991+
{
4992+
if(statementType.equals("FUNCTION")) {
4993+
type = new CreateFunction(tokens);
4994+
}
4995+
if(statementType.equals("PROCEDURE")) {
4996+
type = new CreateProcedure(tokens);
4997+
}
4998+
4999+
return type;
5000+
}
5001+
}
5002+
5003+
JAVACODE
5004+
List<String> captureRest() {
5005+
List<String> tokens = new LinkedList<String>();
5006+
Token tok;
5007+
while(true) {
5008+
tok = getToken(1);
5009+
if(tok.kind == EOF) {
5010+
break;
5011+
}
5012+
tokens.add(tok.image);
5013+
tok = getNextToken();
5014+
}
5015+
return tokens;
5016+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2020 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.create;
11+
12+
import net.sf.jsqlparser.JSQLParserException;
13+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
14+
import net.sf.jsqlparser.statement.create.function.CreateFunction;
15+
import net.sf.jsqlparser.statement.create.procedure.CreateProcedure;
16+
import org.junit.Test;
17+
18+
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
/**
22+
* Tests the behavior of {@link net.sf.jsqlparser.statement.CreateFunctionalStatement funtion statements}
23+
*/
24+
public class CreateFunctionalStatementTest {
25+
26+
@Test
27+
public void createFunctionMinimal() throws JSQLParserException {
28+
assertSqlCanBeParsedAndDeparsed("CREATE FUNCTION foo RETURN 5 END;");
29+
}
30+
31+
@Test
32+
public void createFunctionLong() throws JSQLParserException {
33+
CreateFunction stm = (CreateFunction) CCJSqlParserUtil.parse("CREATE FUNCTION fun(query_from_time date) RETURNS TABLE(foo double precision, bar double precision)\n" +
34+
" LANGUAGE plpgsql\n" +
35+
" AS $$\n" +
36+
" BEGIN\n" +
37+
" RETURN QUERY\n" +
38+
" WITH bla AS (\n" +
39+
" SELECT * from foo)\n" +
40+
" Select * from bla;\n" +
41+
" END;\n" +
42+
" $$;");
43+
assertThat(stm).isNotNull();
44+
assertThat(stm.formatDeclaration()).contains("fun ( query_from_time date )");
45+
}
46+
47+
@Test
48+
public void createProcedureMinimal() throws JSQLParserException {
49+
assertSqlCanBeParsedAndDeparsed("CREATE PROCEDURE foo AS BEGIN END;");
50+
}
51+
52+
@Test
53+
public void createProcedureLong() throws JSQLParserException {
54+
CreateProcedure stm = (CreateProcedure) CCJSqlParserUtil.parse("CREATE PROCEDURE remove_emp (employee_id NUMBER) AS\n" +
55+
" tot_emps NUMBER;\n" +
56+
" BEGIN\n" +
57+
" DELETE FROM employees\n" +
58+
" WHERE employees.employee_id = remove_emp.employee_id;\n" +
59+
" tot_emps := tot_emps - 1;\n" +
60+
" END;");
61+
assertThat(stm).isNotNull();
62+
assertThat(stm.formatDeclaration()).contains("remove_emp ( employee_id NUMBER )");
63+
}
64+
}

0 commit comments

Comments
 (0)