3
3
import java .io .IOException ;
4
4
import java .sql .Connection ;
5
5
import java .sql .SQLException ;
6
+ import java .sql .DriverManager ;
7
+ import java .sql .DriverPropertyInfo ;
6
8
import java .util .Properties ;
7
9
import java .util .function .Supplier ;
8
10
9
11
import org .apache .calcite .avatica .ConnectStringParser ;
10
- import org .apache .calcite .avatica .DriverVersion ;
11
12
import org .apache .calcite .jdbc .CalciteConnection ;
12
13
import org .apache .calcite .jdbc .CalcitePrepare ;
13
14
import org .apache .calcite .jdbc .Driver ;
17
18
import org .apache .calcite .sql .SqlNode ;
18
19
import org .apache .calcite .sql .parser .SqlParser ;
19
20
21
+ import org .slf4j .Logger ;
22
+ import org .slf4j .LoggerFactory ;
23
+ import java .util .logging .LogManager ;
24
+
20
25
import com .linkedin .hoptimator .Catalog ;
21
- import com .linkedin .hoptimator .util .WrappedSchemaPlus ;
22
26
23
27
24
28
/** Driver for :jdbc:hoptimator:// connections. */
25
- public class HoptimatorDriver extends Driver {
29
+ public class HoptimatorDriver implements java .sql .Driver {
30
+ private static final Logger logger = LoggerFactory .getLogger (HoptimatorDriver .class );
31
+ private static final HoptimatorDriver INSTANCE = new HoptimatorDriver ();
32
+
33
+ public static final String CONNECTION_PREFIX = "jdbc:hoptimator://" ;
34
+
35
+ static {{
36
+ try {
37
+ DriverManager .registerDriver (INSTANCE );
38
+ } catch (SQLException e ) {
39
+ throw new RuntimeException ("Failed to register Hoptimator driver." , e );
40
+ }
41
+ }}
26
42
27
- public HoptimatorDriver () {
28
- super ();
43
+ public static CalcitePrepare .ConvertResult convert (HoptimatorConnection conn , String sql ) {
44
+ CalcitePrepare .Context context = conn .createPrepareContext ();
45
+ return new Prepare (conn ).convert (context , sql );
29
46
}
30
47
31
- private HoptimatorDriver (Supplier <CalcitePrepare > prepareFactory ) {
32
- super (prepareFactory );
48
+ public static CalcitePrepare .AnalyzeViewResult analyzeView (HoptimatorConnection conn , String sql ) {
49
+ CalcitePrepare .Context context = conn .createPrepareContext ();
50
+ return new Prepare (conn ).analyzeView (context , sql , false );
33
51
}
34
52
35
- static {
36
- new HoptimatorDriver ().register ();
53
+ @ Override
54
+ public boolean acceptsURL (String url ) {
55
+ return url .startsWith (CONNECTION_PREFIX );
37
56
}
38
57
39
- public static CalcitePrepare . ConvertResult convert ( HoptimatorConnection conn , String sql ) {
40
- CalcitePrepare . Context context = conn . createPrepareContext ();
41
- return new Prepare ( conn . connectionProperties ()). convert ( context , sql ) ;
58
+ @ Override
59
+ public int getMajorVersion () {
60
+ return 0 ;
42
61
}
43
62
44
63
@ Override
45
- protected String getConnectStringPrefix () {
46
- return "jdbc:hoptimator://" ;
64
+ public int getMinorVersion () {
65
+ return 1 ;
47
66
}
48
67
49
68
@ Override
50
- protected DriverVersion createDriverVersion () {
51
- return DriverVersion .load (this .getClass (), "hoptimator.properties" , "hoptimator" , "0" , "hoptimator" , "0" );
69
+ public java .util .logging .Logger getParentLogger () {
70
+ return LogManager .getLogManager ().getLogger (logger .getName ());
71
+ }
72
+
73
+ @ Override
74
+ public DriverPropertyInfo [] getPropertyInfo (String url , Properties info ) throws SQLException {
75
+ return new DriverPropertyInfo [0 ];
76
+ }
77
+
78
+ @ Override
79
+ public boolean jdbcCompliant () {
80
+ return false ;
52
81
}
53
82
54
83
@ Override
55
84
public Connection connect (String url , Properties props ) throws SQLException {
56
- if (!url . startsWith ( getConnectStringPrefix () )) {
85
+ if (!acceptsURL ( url )) {
57
86
return null ;
58
87
}
59
88
try {
60
89
// Load properties from the URL and from getConnection()'s properties.
61
90
// URL properties take precedence.
62
91
Properties properties = new Properties ();
63
92
properties .putAll (props ); // via getConnection()
64
- properties .putAll (ConnectStringParser .parse (url .substring (getConnectStringPrefix () .length ())));
65
-
66
- if ( prepareFactory == null ) {
67
- // funky way of extending Driver with a custom Prepare:
68
- return withPrepareFactory (() -> new Prepare ( properties ))
69
- . connect ( url , properties );
70
- }
71
- Connection connection = super .connect (url , properties );
93
+ properties .putAll (ConnectStringParser .parse (url .substring (CONNECTION_PREFIX .length ())));
94
+
95
+ // For [Calcite]Driver.connect() to work, we need [Calcite]Driver.createPrepare()
96
+ // to return our Prepare. But our Prepare requires a HoptimatorConnection, which
97
+ // we cannot construct yet.
98
+ ConnectionHolder holder = new ConnectionHolder ( );
99
+ Connection connection = new Driver (). withPrepareFactory (() -> new Prepare ( holder ))
100
+ .connect ("jdbc:calcite:" , properties );
72
101
if (connection == null ) {
73
- throw new IOException ("Could not connect to " + url );
102
+ throw new IOException ("Could not connect to " + url + ": Could not create Calcite connection." );
74
103
}
75
- connection .setAutoCommit (true ); // to prevent rollback()
76
104
CalciteConnection calciteConnection = (CalciteConnection ) connection ;
105
+ calciteConnection .setAutoCommit (true ); // to prevent rollback()
77
106
SchemaPlus rootSchema = calciteConnection .getRootSchema ();
78
107
79
108
// built-in schemas
80
109
rootSchema .add ("DEFAULT" , new AbstractSchema ());
81
110
82
111
calciteConnection .setSchema ("DEFAULT" );
112
+
113
+ HoptimatorConnection hoptimatorConnection = new HoptimatorConnection (calciteConnection , properties );
114
+ holder .connection = hoptimatorConnection ;
83
115
84
- WrappedSchemaPlus wrappedRootSchema = new WrappedSchemaPlus ( rootSchema );
116
+ Wrapped wrapped = new Wrapped ( hoptimatorConnection , rootSchema );
85
117
String [] catalogs = properties .getProperty ("catalogs" , "" ).split ("," );
86
118
87
119
if (catalogs .length == 0 || catalogs [0 ].length () == 0 ) {
88
120
// load all catalogs (typical usage)
89
121
for (Catalog catalog : CatalogService .catalogs ()) {
90
- catalog .register (wrappedRootSchema , properties );
122
+ catalog .register (wrapped );
91
123
}
92
124
} else {
93
125
// load specific catalogs when loaded as `jdbc:hoptimator://catalogs=foo,bar`
94
126
for (String catalog : catalogs ) {
95
- CatalogService .catalog (catalog ).register (wrappedRootSchema , properties );
127
+ CatalogService .catalog (catalog ).register (wrapped );
96
128
}
97
129
}
98
130
99
- return new HoptimatorConnection ( calciteConnection , properties ) ;
131
+ return hoptimatorConnection ;
100
132
} catch (Exception e ) {
101
133
throw new SQLException ("Problem loading " + url , e );
102
134
}
103
135
}
104
136
105
- @ Override
106
- public Driver withPrepareFactory (Supplier <CalcitePrepare > prepareFactory ) {
107
- return new HoptimatorDriver (prepareFactory );
137
+ private static class ConnectionHolder {
138
+ HoptimatorConnection connection ;
108
139
}
109
140
110
141
public static class Prepare extends CalcitePrepareImpl {
111
142
112
- private final Properties connectionProperties ;
143
+ private final ConnectionHolder holder ;
144
+
145
+ Prepare (ConnectionHolder holder ) {
146
+ this .holder = holder ;
147
+ }
113
148
114
- Prepare (Properties connectionProperties ) {
115
- this .connectionProperties = connectionProperties ;
149
+ Prepare (HoptimatorConnection connection ) {
150
+ this .holder = new ConnectionHolder ();
151
+ this .holder .connection = connection ;
116
152
}
117
153
118
154
@ Override
@@ -122,7 +158,7 @@ protected SqlParser.Config parserConfig() {
122
158
123
159
@ Override
124
160
public void executeDdl (Context context , SqlNode node ) {
125
- new HoptimatorDdlExecutor (connectionProperties ).executeDdl (context , node );
161
+ new HoptimatorDdlExecutor (holder . connection ).executeDdl (context , node );
126
162
}
127
163
}
128
164
}
0 commit comments