2
2
3
3
import java .io .StringReader ;
4
4
import java .lang .reflect .Method ;
5
+ import java .util .List ;
6
+ import java .util .stream .Collectors ;
5
7
6
8
import org .codehaus .commons .compiler .ISimpleCompiler ;
7
9
import org .codehaus .janino .CompilerFactory ;
8
10
11
+ import co .clflushopt .glint .query .logical .plan .LogicalPlan ;
12
+ import co .clflushopt .glint .query .logical .plan .Scan ;
13
+
9
14
/**
10
15
* Core Query Compiler using Janino for runtime code generation. This class
11
16
* provides the fundamental mechanism for generating and compiling executable
@@ -64,13 +69,134 @@ public long execute() {
64
69
long totalRecords = 0;
65
70
66
71
for (RecordBatch batch : dataSource.scan(List.of())) {
67
- totalRecords += batch.getRowSize ();
68
- System.out.println("Batch size: " + batch.getRowSize ());
72
+ totalRecords += batch.getRowCount ();
73
+ System.out.println("Batch size: " + batch.getRowCount ());
69
74
}
70
75
71
76
return totalRecords;
72
77
}
73
78
}
74
79
""" , filename );
75
80
}
81
+
82
+ /**
83
+ * Compiles and executes a logical plan.
84
+ *
85
+ * @param logicalPlan The root of the logical plan to compile
86
+ * @return The result of executing the compiled plan
87
+ * @throws Exception If compilation or execution fails
88
+ */
89
+ public Object compile (LogicalPlan logicalPlan ) throws Exception {
90
+ // Generate source code for the entire logical plan
91
+ String sourceCode = generateSourceCode (logicalPlan );
92
+
93
+ // Create a new simple compiler
94
+ ISimpleCompiler compiler = compilerFactory .newSimpleCompiler ();
95
+
96
+ // Set the source version to Java 21
97
+ compiler .setSourceVersion (21 );
98
+ compiler .setTargetVersion (21 );
99
+
100
+ // Cook (compile) the source code
101
+ compiler .cook (new StringReader (sourceCode ));
102
+
103
+ // Load the compiled class
104
+ Class <?> compiledClass = compiler .getClassLoader ()
105
+ .loadClass ("co.clflushopt.glint.generated.LogicalPlanExecutor" );
106
+
107
+ // Create an instance
108
+ Object instance = compiledClass .getDeclaredConstructor ().newInstance ();
109
+
110
+ // Find and invoke the execute method
111
+ Method executeMethod = compiledClass .getMethod ("execute" );
112
+ return executeMethod .invoke (instance );
113
+ }
114
+
115
+ /**
116
+ * Generates source code for a given logical plan.
117
+ *
118
+ * @param logicalPlan The logical plan to generate code for
119
+ * @return Generated Java source code as a string
120
+ */
121
+ private String generateSourceCode (LogicalPlan logicalPlan ) {
122
+ return String .format (
123
+ """
124
+ package co.clflushopt.glint.generated;
125
+
126
+ import co.clflushopt.glint.query.logical.plan.LogicalPlan;
127
+ import co.clflushopt.glint.query.logical.plan.Scan;
128
+ import co.clflushopt.glint.datasource.DataSource;
129
+ import co.clflushopt.glint.types.RecordBatch;
130
+ import co.clflushopt.glint.types.Schema;
131
+ import java.util.List;
132
+
133
+ public class LogicalPlanExecutor {
134
+ public long execute() {
135
+ return executePlan(%s);
136
+ }
137
+
138
+ private long executePlan(LogicalPlan plan) {
139
+ // Handle different logical plan types
140
+ if (plan instanceof Scan) {
141
+ Scan scan = (Scan) plan;
142
+ return executeScan(scan);
143
+ }
144
+
145
+ // TODO: Add support for other logical plan types
146
+ throw new UnsupportedOperationException("Unsupported logical plan type: " + plan.getClass().getSimpleName());
147
+ }
148
+
149
+ private long executeScan(Scan scan) {
150
+ DataSource dataSource = scan.getDataSource();
151
+ List<String> projections = scan.getProjections();
152
+
153
+ long totalRecords = 0;
154
+ for (RecordBatch batch : dataSource.scan(projections)) {
155
+ totalRecords += batch.getRowCount();
156
+ System.out.println("Scan batch size: " + batch.getRowCount() +
157
+ " Path: " + scan.getPath());
158
+ }
159
+
160
+ return totalRecords;
161
+ }
162
+ }
163
+ """ ,
164
+ generatePlanArgument (logicalPlan ));
165
+ }
166
+
167
+ /**
168
+ * Generates a string representation of the logical plan to be used as a method
169
+ * argument.
170
+ *
171
+ * @param plan The logical plan to convert
172
+ * @return A string that can be used to reconstruct the plan in the generated
173
+ * code
174
+ */
175
+ private String generatePlanArgument (LogicalPlan plan ) {
176
+ if (plan instanceof Scan scan ) {
177
+ return String .format ("new Scan(\" %s\" , new %s(\" %s\" ), %s)" , scan .getPath (),
178
+ scan .getDataSource ().getClass ().getName (), scan .getPath (),
179
+ formatProjections (scan .getProjections ()));
180
+ }
181
+
182
+ // TODO: Add support for other logical plan types
183
+ throw new UnsupportedOperationException (
184
+ "Unsupported logical plan type: " + plan .getClass ().getSimpleName ());
185
+ }
186
+
187
+ /**
188
+ * Formats the list of projections as a Java code string.
189
+ *
190
+ * @param projections List of projection column names
191
+ * @return A Java code representation of the projections list
192
+ */
193
+ private String formatProjections (List <String > projections ) {
194
+ if (projections == null || projections .isEmpty ()) {
195
+ return "List.of()" ;
196
+ }
197
+
198
+ return "List.of("
199
+ + projections .stream ().map (p -> "\" " + p + "\" " ).collect (Collectors .joining (", " ))
200
+ + ")" ;
201
+ }
76
202
}
0 commit comments