1717 */
1818package org .apache .drill .exec .server .rest ;
1919
20- import java .io .IOException ;
21- import java .io .InputStream ;
22- import java .nio .charset .StandardCharsets ;
23-
2420import org .graalvm .polyglot .Context ;
2521import org .graalvm .polyglot .Source ;
2622import org .graalvm .polyglot .Value ;
2723import org .slf4j .Logger ;
2824import org .slf4j .LoggerFactory ;
2925
26+ import java .io .IOException ;
27+ import java .io .InputStream ;
28+ import java .nio .charset .StandardCharsets ;
29+
3030/**
3131 * Singleton service that wraps a GraalPy context with sqlglot
3232 * for SQL dialect transpilation. Thread-safe via synchronized access
@@ -49,6 +49,8 @@ public final class SqlTranspiler {
4949 private Context pythonContext ;
5050 private Value transpileFunc ;
5151 private Value jsonParseFunc ;
52+ private Value convertDataTypeFunc ;
53+ private Value formatSqlFunc ;
5254 private boolean available ;
5355
5456 /**
@@ -77,6 +79,8 @@ private SqlTranspiler() {
7779
7880 transpileFunc = pythonContext .getBindings ("python" ).getMember ("transpile_sql" );
7981 jsonParseFunc = pythonContext .getBindings ("python" ).getMember ("json_parse" );
82+ convertDataTypeFunc = pythonContext .getBindings ("python" ).getMember ("convert_data_type_raw" );
83+ formatSqlFunc = pythonContext .getBindings ("python" ).getMember ("format_sql" );
8084 available = true ;
8185 logger .info ("SqlTranspiler initialized successfully with GraalPy + sqlglot" );
8286 } catch (Exception e ) {
@@ -104,29 +108,66 @@ public synchronized String transpile(String sql, String sourceDialect, String ta
104108 */
105109 public synchronized String transpile (String sql , String sourceDialect ,
106110 String targetDialect , String schemasJson ) {
107- System .out .println ("=== TRANSPILE INPUT ===" );
108- System .out .println ("Available: " + available );
109- System .out .println ("SQL: " + sql );
110- System .out .println ("Source dialect: " + sourceDialect );
111- System .out .println ("Target dialect: " + targetDialect );
112- System .out .println ("Schemas JSON: " + schemasJson );
113- System .out .println ("======================" );
114111 if (!available ) {
115112 return sql ;
116113 }
117114 try {
118115 Value schemas = jsonParseFunc .execute (schemasJson != null ? schemasJson : "[]" );
119116 String result = transpileFunc .execute (sql , sourceDialect , targetDialect , schemas ).asString ();
120- System .out .println ("=== TRANSPILE OUTPUT ===" );
121- System .out .println ("Result: " + result );
122- System .out .println ("========================" );
123117 return result ;
124118 } catch (Exception e ) {
125119 logger .debug ("SQL transpilation failed, returning original SQL: {}" , e .getMessage ());
126120 return sql ;
127121 }
128122 }
129123
124+ /**
125+ * Convert a column's data type in a SQL query using sqlglot AST manipulation.
126+ *
127+ * @param sql the SQL query
128+ * @param columnName the column to convert
129+ * @param dataType the target SQL data type (e.g. "INTEGER", "VARCHAR")
130+ * @param columnsJson optional JSON object mapping column names to types (for star queries)
131+ * @return the transformed SQL, or null if conversion fails
132+ */
133+ public synchronized String convertDataType (String sql , String columnName ,
134+ String dataType , String columnsJson ) {
135+ if (!available ) {
136+ logger .warn ("convertDataType called but transpiler is not available" );
137+ return null ;
138+ }
139+ try {
140+ String result ;
141+ if (columnsJson != null && !columnsJson .isEmpty ()) {
142+ result = convertDataTypeFunc .execute (sql , columnName , dataType , columnsJson ).asString ();
143+ } else {
144+ result = convertDataTypeFunc .execute (sql , columnName , dataType ).asString ();
145+ }
146+ return result ;
147+ } catch (Exception e ) {
148+ logger .warn ("Data type conversion failed: {}" , e .getMessage (), e );
149+ return null ;
150+ }
151+ }
152+
153+ /**
154+ * Pretty-print a SQL string using sqlglot.
155+ *
156+ * @param sql the SQL string to format
157+ * @return the formatted SQL, or the original if formatting fails
158+ */
159+ public synchronized String formatSql (String sql ) {
160+ if (!available ) {
161+ return sql ;
162+ }
163+ try {
164+ return formatSqlFunc .execute (sql ).asString ();
165+ } catch (Exception e ) {
166+ logger .debug ("SQL formatting failed, returning original: {}" , e .getMessage ());
167+ return sql ;
168+ }
169+ }
170+
130171 /**
131172 * Returns whether the transpiler is available (GraalPy + sqlglot initialized successfully).
132173 */
0 commit comments