1414import java .util .Collections ;
1515import java .util .List ;
1616import java .util .Optional ;
17+ import java .util .function .Consumer ;
18+ import net .sf .jsqlparser .statement .create .function .FunctionReturnType ;
19+ import net .sf .jsqlparser .statement .create .table .TableElement ;
1720
1821/**
1922 * A base for the declaration of function like statements
@@ -23,6 +26,39 @@ public abstract class CreateFunctionalStatement implements Statement {
2326 private String kind ;
2427 private boolean orReplace = false ;
2528
29+ public enum Operation {
30+ CREATE , ALTER , CREATE_OR_ALTER
31+ }
32+
33+ private Operation operation = Operation .CREATE ;
34+ private FunctionReturnType returnType ;
35+ private List <String > routineBodyParts ;
36+
37+ public Operation getOperation () {
38+ return operation ;
39+ }
40+
41+ public void setOperation (Operation operation ) {
42+ this .operation = operation ;
43+ }
44+
45+ public FunctionReturnType getReturnType () {
46+ return returnType ;
47+ }
48+
49+ public void setReturnType (FunctionReturnType returnType ) {
50+ this .returnType = returnType ;
51+ }
52+
53+ public List <String > getRoutineBodyParts () {
54+ return routineBodyParts ;
55+ }
56+
57+ public void setRoutineBodyParts (List <String > parts ) {
58+ routineBodyParts = parts ;
59+ }
60+
61+
2662 private List <String > functionDeclarationParts ;
2763
2864 protected CreateFunctionalStatement (String kind ) {
@@ -41,7 +77,9 @@ protected CreateFunctionalStatement(boolean orReplace, String kind,
4177 }
4278
4379 /**
44- * @return the declaration parts after {@code CREATE FUNCTION|PROCEDURE}
80+ * @return the declaration parts after {@code CREATE FUNCTION|PROCEDURE}. For a SQL Server
81+ * function with a structured {@link #getReturnType()}, these are the name and parameter
82+ * tokens before RETURNS; {@link #getRoutineBodyParts()} holds the remaining tokens.
4583 */
4684 public List <String > getFunctionDeclarationParts () {
4785 return functionDeclarationParts ;
@@ -66,22 +104,43 @@ public void setOrReplace(boolean orReplace) {
66104 * @return a whitespace appended String with the declaration parts with some minimal formatting.
67105 */
68106 public String formatDeclaration () {
69- StringBuilder declaration = new StringBuilder ();
70- int currIndex = 0 ;
71- while (currIndex < functionDeclarationParts .size ()) {
72- String token = functionDeclarationParts .get (currIndex );
73- declaration .append (token );
74- // if the next token is a ; don't put a space
75- if (currIndex + 1 < functionDeclarationParts .size ()) {
76- // peek ahead just to format nicely
77- String nextToken = functionDeclarationParts .get (currIndex + 1 );
78- if (!nextToken .equals (";" )) {
79- declaration .append (" " );
80- }
107+ StringBuilder builder = new StringBuilder ();
108+ return appendDeclarationTo (builder , builder ::append ).toString ();
109+ }
110+
111+ private StringBuilder appendDeclarationTo (StringBuilder builder ,
112+ Consumer <TableElement > printer ) {
113+ appendTokens (builder , functionDeclarationParts );
114+ if (returnType != null ) {
115+ builder .append (' ' );
116+ returnType .appendTo (builder , printer );
117+ if (routineBodyParts != null && !routineBodyParts .isEmpty ()) {
118+ builder .append (' ' );
119+ appendTokens (builder , routineBodyParts );
81120 }
82- currIndex ++;
83121 }
84- return declaration .toString ();
122+ return builder ;
123+ }
124+
125+ private static void appendTokens (StringBuilder builder , List <String > tokens ) {
126+ if (tokens == null ) {
127+ return ;
128+ }
129+ for (int i = 0 ; i < tokens .size (); i ++) {
130+ if (i > 0 && !";" .equals (tokens .get (i ))) {
131+ builder .append (' ' );
132+ }
133+ builder .append (tokens .get (i ));
134+ }
135+ }
136+
137+ public StringBuilder appendTo (StringBuilder builder , Consumer <TableElement > printer ) {
138+ builder .append (operation .name ().replace ('_' , ' ' )).append (' ' );
139+ if (orReplace && operation == Operation .CREATE ) {
140+ builder .append ("OR REPLACE " );
141+ }
142+ builder .append (kind ).append (' ' );
143+ return appendDeclarationTo (builder , printer );
85144 }
86145
87146 @ Override
@@ -91,9 +150,8 @@ public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
91150
92151 @ Override
93152 public String toString () {
94- return "CREATE "
95- + (orReplace ? "OR REPLACE " : "" )
96- + kind + " " + formatDeclaration ();
153+ StringBuilder builder = new StringBuilder ();
154+ return appendTo (builder , builder ::append ).toString ();
97155 }
98156
99157 public CreateFunctionalStatement withFunctionDeclarationParts (
0 commit comments