1212import net .sf .jsqlparser .expression .Expression ;
1313import net .sf .jsqlparser .statement .Statement ;
1414import net .sf .jsqlparser .statement .StatementVisitor ;
15+ import net .sf .jsqlparser .statement .create .table .ColDataType ;
1516import net .sf .jsqlparser .statement .select .Select ;
1617
1718import java .io .Serializable ;
19+ import java .util .ArrayList ;
1820import java .util .List ;
1921import java .util .function .Consumer ;
2022
2123/**
22- * DuckDB's {@code CREATE [OR REPLACE] [TEMPORARY] MACRO name (parameters) AS [TABLE] body}, a named
23- * expression or query that is inlined at call sites.
24+ * DuckDB's
25+ * {@code CREATE [OR REPLACE] [TEMPORARY] {MACRO | FUNCTION} [IF NOT EXISTS] name (parameters) AS [TABLE] body [, (parameters) AS [TABLE] body ...]},
26+ * a named expression or query that is inlined at call sites, optionally overloaded on its
27+ * parameters.
28+ *
29+ * <p>
30+ * {@link #getParameters()}, {@link #getExpression()} and {@link #getSelect()} and their setters
31+ * address the first overload.
2432 *
2533 * @see <a href="https://duckdb.org/docs/stable/sql/statements/create_macro">CREATE MACRO</a>
2634 */
2735public class CreateMacro implements Statement {
2836 private boolean orReplace ;
2937 private boolean temporary ;
38+ private boolean functionKeyword ;
39+ private boolean ifNotExists ;
3040 private String name ;
31- private List <Parameter > parameters ;
32- private Expression expression ;
33- private Select select ;
41+ private List <Overload > overloads = new ArrayList <>();
3442
3543 public boolean isOrReplace () {
3644 return orReplace ;
@@ -58,6 +66,33 @@ public CreateMacro withTemporary(boolean temporary) {
5866 return this ;
5967 }
6068
69+ /** Whether it was written {@code CREATE FUNCTION}, DuckDB's alias of {@code CREATE MACRO}. */
70+ public boolean isFunctionKeyword () {
71+ return functionKeyword ;
72+ }
73+
74+ public void setFunctionKeyword (boolean functionKeyword ) {
75+ this .functionKeyword = functionKeyword ;
76+ }
77+
78+ public CreateMacro withFunctionKeyword (boolean functionKeyword ) {
79+ setFunctionKeyword (functionKeyword );
80+ return this ;
81+ }
82+
83+ public boolean isIfNotExists () {
84+ return ifNotExists ;
85+ }
86+
87+ public void setIfNotExists (boolean ifNotExists ) {
88+ this .ifNotExists = ifNotExists ;
89+ }
90+
91+ public CreateMacro withIfNotExists (boolean ifNotExists ) {
92+ setIfNotExists (ifNotExists );
93+ return this ;
94+ }
95+
6196 public String getName () {
6297 return name ;
6398 }
@@ -71,12 +106,32 @@ public CreateMacro withName(String name) {
71106 return this ;
72107 }
73108
109+ public List <Overload > getOverloads () {
110+ return overloads ;
111+ }
112+
113+ public void setOverloads (List <Overload > overloads ) {
114+ this .overloads = overloads ;
115+ }
116+
117+ public CreateMacro withOverloads (List <Overload > overloads ) {
118+ setOverloads (overloads );
119+ return this ;
120+ }
121+
122+ private Overload firstOverload () {
123+ if (overloads .isEmpty ()) {
124+ overloads .add (new Overload ());
125+ }
126+ return overloads .get (0 );
127+ }
128+
74129 public List <Parameter > getParameters () {
75- return parameters ;
130+ return overloads . isEmpty () ? null : overloads . get ( 0 ). getParameters () ;
76131 }
77132
78133 public void setParameters (List <Parameter > parameters ) {
79- this . parameters = parameters ;
134+ firstOverload (). setParameters ( parameters ) ;
80135 }
81136
82137 public CreateMacro withParameters (List <Parameter > parameters ) {
@@ -85,11 +140,11 @@ public CreateMacro withParameters(List<Parameter> parameters) {
85140 }
86141
87142 public Expression getExpression () {
88- return expression ;
143+ return overloads . isEmpty () ? null : overloads . get ( 0 ). getExpression () ;
89144 }
90145
91146 public void setExpression (Expression expression ) {
92- this . expression = expression ;
147+ firstOverload (). setExpression ( expression ) ;
93148 }
94149
95150 public CreateMacro withExpression (Expression expression ) {
@@ -98,11 +153,11 @@ public CreateMacro withExpression(Expression expression) {
98153 }
99154
100155 public Select getSelect () {
101- return select ;
156+ return overloads . isEmpty () ? null : overloads . get ( 0 ). getSelect () ;
102157 }
103158
104159 public void setSelect (Select select ) {
105- this . select = select ;
160+ firstOverload (). setSelect ( select ) ;
106161 }
107162
108163 public CreateMacro withSelect (Select select ) {
@@ -112,7 +167,7 @@ public CreateMacro withSelect(Select select) {
112167
113168 /** A table macro returns a relation, a scalar macro an expression. */
114169 public boolean isTable () {
115- return select != null ;
170+ return getSelect () != null ;
116171 }
117172
118173 public StringBuilder appendTo (StringBuilder builder ) {
@@ -129,19 +184,16 @@ public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expres
129184 if (temporary ) {
130185 builder .append ("TEMPORARY " );
131186 }
132- builder .append ("MACRO " ).append (name ).append (" (" );
133- for (int i = 0 ; i < parameters .size (); i ++) {
187+ builder .append (functionKeyword ? "FUNCTION " : "MACRO " );
188+ if (ifNotExists ) {
189+ builder .append ("IF NOT EXISTS " );
190+ }
191+ builder .append (name ).append (" " );
192+ for (int i = 0 ; i < overloads .size (); i ++) {
134193 if (i > 0 ) {
135194 builder .append (", " );
136195 }
137- parameters .get (i ).appendTo (builder , expressionRenderer );
138- }
139- builder .append (") AS " );
140- if (select != null ) {
141- builder .append ("TABLE " );
142- selectRenderer .accept (select );
143- } else {
144- expressionRenderer .accept (expression );
196+ overloads .get (i ).appendTo (builder , expressionRenderer , selectRenderer );
145197 }
146198 return builder ;
147199 }
@@ -156,24 +208,113 @@ public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
156208 return statementVisitor .visit (this , context );
157209 }
158210
159- /** A macro parameter, optionally carrying a default value ({@code b := 5}). */
211+ /** One {@code (parameters) AS [TABLE] body} of a macro. */
212+ public static class Overload implements Serializable {
213+ private List <Parameter > parameters = new ArrayList <>();
214+ private Expression expression ;
215+ private Select select ;
216+
217+ public List <Parameter > getParameters () {
218+ return parameters ;
219+ }
220+
221+ public void setParameters (List <Parameter > parameters ) {
222+ this .parameters = parameters ;
223+ }
224+
225+ public Overload withParameters (List <Parameter > parameters ) {
226+ setParameters (parameters );
227+ return this ;
228+ }
229+
230+ public Expression getExpression () {
231+ return expression ;
232+ }
233+
234+ public void setExpression (Expression expression ) {
235+ this .expression = expression ;
236+ }
237+
238+ public Overload withExpression (Expression expression ) {
239+ setExpression (expression );
240+ return this ;
241+ }
242+
243+ public Select getSelect () {
244+ return select ;
245+ }
246+
247+ public void setSelect (Select select ) {
248+ this .select = select ;
249+ }
250+
251+ public Overload withSelect (Select select ) {
252+ setSelect (select );
253+ return this ;
254+ }
255+
256+ /** A table overload returns a relation, a scalar one an expression. */
257+ public boolean isTable () {
258+ return select != null ;
259+ }
260+
261+ @ Override
262+ public String toString () {
263+ StringBuilder builder = new StringBuilder ();
264+ return appendTo (builder , builder ::append , builder ::append ).toString ();
265+ }
266+
267+ private StringBuilder appendTo (StringBuilder builder ,
268+ Consumer <Expression > expressionRenderer , Consumer <Select > selectRenderer ) {
269+ builder .append ("(" );
270+ for (int i = 0 ; i < parameters .size (); i ++) {
271+ if (i > 0 ) {
272+ builder .append (", " );
273+ }
274+ parameters .get (i ).appendTo (builder , expressionRenderer );
275+ }
276+ builder .append (") AS " );
277+ if (select != null ) {
278+ builder .append ("TABLE " );
279+ selectRenderer .accept (select );
280+ } else {
281+ expressionRenderer .accept (expression );
282+ }
283+ return builder ;
284+ }
285+ }
286+
287+ /**
288+ * A macro parameter, optionally typed ({@code a INTEGER}) and carrying a default value
289+ * ({@code b := 5}).
290+ */
160291 public static class Parameter implements Serializable {
161292 private final String name ;
293+ private final ColDataType type ;
162294 private final Expression defaultValue ;
163295
164296 public Parameter (String name ) {
165- this (name , null );
297+ this (name , null , null );
166298 }
167299
168300 public Parameter (String name , Expression defaultValue ) {
301+ this (name , null , defaultValue );
302+ }
303+
304+ public Parameter (String name , ColDataType type , Expression defaultValue ) {
169305 this .name = name ;
306+ this .type = type ;
170307 this .defaultValue = defaultValue ;
171308 }
172309
173310 public String getName () {
174311 return name ;
175312 }
176313
314+ public ColDataType getType () {
315+ return type ;
316+ }
317+
177318 public Expression getDefaultValue () {
178319 return defaultValue ;
179320 }
@@ -187,6 +328,9 @@ public String toString() {
187328 private StringBuilder appendTo (StringBuilder builder ,
188329 Consumer <Expression > expressionRenderer ) {
189330 builder .append (name );
331+ if (type != null ) {
332+ builder .append (" " ).append (type );
333+ }
190334 if (defaultValue != null ) {
191335 builder .append (" := " );
192336 expressionRenderer .accept (defaultValue );
0 commit comments