-
Notifications
You must be signed in to change notification settings - Fork 154
/
SnowflakeDriver.java
274 lines (240 loc) · 9.04 KB
/
SnowflakeDriver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
* Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved.
*/
package net.snowflake.client.jdbc;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.List;
import java.util.Properties;
import net.snowflake.client.core.SecurityUtil;
import net.snowflake.common.core.ResourceBundleManager;
import net.snowflake.common.core.SqlState;
/**
* JDBC Driver implementation of Snowflake for production. To use this driver, specify the following
* URL: jdbc:snowflake://host:port
*
* <p>Note: don't add logger to this class since logger init will potentially break driver class
* loading
*/
public class SnowflakeDriver implements Driver {
static SnowflakeDriver INSTANCE;
public static final Properties EMPTY_PROPERTIES = new Properties();
public static String implementVersion = "3.16.2";
static int majorVersion = 0;
static int minorVersion = 0;
static long patchVersion = 0;
protected static boolean disableIncidents = false;
private static boolean disableArrowResultFormat = false;
private static String disableArrowResultFormatMessage;
private static final ResourceBundleManager versionResourceBundleManager =
ResourceBundleManager.getSingleton("net.snowflake.client.jdbc.version");
static {
try {
DriverManager.registerDriver(INSTANCE = new SnowflakeDriver());
} catch (SQLException ex) {
throw new IllegalStateException("Unable to register " + SnowflakeDriver.class.getName(), ex);
}
initializeArrowSupport();
/*
* Get the manifest properties here.
*/
initializeClientVersionFromManifest();
SecurityUtil.addBouncyCastleProvider();
}
/** try to initialize Arrow support if fails, JDBC is going to use the legacy format */
private static void initializeArrowSupport() {
try {
// this is required to enable direct memory usage for Arrow buffers in Java
System.setProperty("io.netty.tryReflectionSetAccessible", "true");
} catch (Throwable t) {
// fail to enable required feature for Arrow
disableArrowResultFormat = true;
disableArrowResultFormatMessage = t.getLocalizedMessage();
}
if ("true"
.equals(SnowflakeUtil.systemGetProperty("snowflake.jdbc.enable.illegalAccessWarning"))) {
return;
}
disableIllegalReflectiveAccessWarning();
}
static void disableIllegalReflectiveAccessWarning() {
// The netty dependency of arrow will cause an illegal reflective access warning
// This function try to eliminate the warning by setting
// jdk.internal.module.IllegalAccessLogger's logger as null
// Disable this function and manually run arrow tests, e.g. testResultSetMetadata., then
// the warning can be found in output.
try {
Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Object unsafe = field.get(null);
Method putObjectVolatile =
unsafeClass.getDeclaredMethod(
"putObjectVolatile", Object.class, long.class, Object.class);
Method staticFieldOffset = unsafeClass.getDeclaredMethod("staticFieldOffset", Field.class);
Method staticFieldBase = unsafeClass.getDeclaredMethod("staticFieldBase", Field.class);
Class loggerClass = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field loggerField = loggerClass.getDeclaredField("logger");
Long loggerOffset = (Long) staticFieldOffset.invoke(unsafe, loggerField);
Object loggerBase = staticFieldBase.invoke(unsafe, loggerField);
putObjectVolatile.invoke(unsafe, loggerBase, loggerOffset, null);
} catch (Throwable ex) {
// If failed to eliminate warnings, do nothing
}
}
private static void initializeClientVersionFromManifest() {
/*
* Get JDBC version numbers from static string in snowflake-jdbc
*/
try {
// parse implementation version major.minor.change
if (implementVersion != null) {
String[] versionBreakdown = implementVersion.split("\\.");
if (versionBreakdown.length == 3) {
majorVersion = Integer.parseInt(versionBreakdown[0]);
minorVersion = Integer.parseInt(versionBreakdown[1]);
patchVersion = Long.parseLong(versionBreakdown[2]);
} else {
throw new SnowflakeSQLLoggedException(
null,
ErrorCode.INTERNAL_ERROR.getMessageCode(),
SqlState.INTERNAL_ERROR,
/*session = */ "Invalid Snowflake JDBC Version: " + implementVersion);
}
} else {
throw new SnowflakeSQLException(
SqlState.INTERNAL_ERROR,
ErrorCode.INTERNAL_ERROR.getMessageCode(),
/*session = */ null,
"Snowflake JDBC Version is not set. "
+ "Ensure static version string was initialized.");
}
} catch (Throwable ex) {
}
}
/**
* For testing purposes only- used to compare that JDBC version in pom.xml matches static string
*
* @return String with version from pom.xml file
*/
static String getClientVersionStringFromManifest() {
return versionResourceBundleManager.getLocalizedMessage("version");
}
public static boolean isDisableArrowResultFormat() {
return disableArrowResultFormat;
}
public static String getDisableArrowResultFormatMessage() {
return disableArrowResultFormatMessage;
}
/**
* Utility method to verify if the standard or fips snowflake-jdbc driver is being used.
*
* @return
*/
public static String getImplementationTitle() {
Package pkg = Package.getPackage("net.snowflake.client.jdbc");
return pkg.getImplementationTitle();
}
/**
* Utility method to get the complete jar name with version.
*
* @return
*/
public static String getJdbcJarname() {
return String.format("%s-%s", getImplementationTitle(), implementVersion);
}
/**
* Checks whether a given url is in a valid format.
*
* <p>The current uri format is: jdbc:snowflake://[host[:port]]
*
* <p>jdbc:snowflake:// - run in embedded mode jdbc:snowflake://localhost - connect to localhost
* default port (8080)
*
* <p>jdbc:snowflake://localhost:8080- connect to localhost port 8080
*
* @param url url of the database including host and port
* @return true if the url is valid
*/
@Override
public boolean acceptsURL(String url) {
return SnowflakeConnectString.parse(url, EMPTY_PROPERTIES).isValid();
}
/**
* Connect method
*
* @param url jdbc url
* @param info addition info for passing database/schema names
* @return connection
* @throws SQLException if failed to create a snowflake connection
*/
@Override
public Connection connect(String url, Properties info) throws SQLException {
if (url == null) {
// expected return format per the JDBC spec for java.sql.Driver#connect()
throw new SnowflakeSQLException("Unable to connect to url of 'null'.");
}
if (!SnowflakeConnectString.hasSupportedPrefix(url)) {
return null; // expected return format per the JDBC spec for java.sql.Driver#connect()
}
SnowflakeConnectString conStr = SnowflakeConnectString.parse(url, info);
if (!conStr.isValid()) {
throw new SnowflakeSQLException("Connection string is invalid. Unable to parse.");
}
return new SnowflakeConnectionV1(url, info);
}
@Override
public int getMajorVersion() {
return majorVersion;
}
@Override
public int getMinorVersion() {
return minorVersion;
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
DriverPropertyInfo[] retVal;
if (url == null || url.isEmpty()) {
retVal = new DriverPropertyInfo[1];
retVal[0] = new DriverPropertyInfo("serverURL", null);
retVal[0].description =
"server URL in form of <protocol>://<host or domain>:<port number>/<path of resource>";
return retVal;
}
Connection con = new SnowflakeConnectionV1(url, info, true);
List<DriverPropertyInfo> missingProperties =
((SnowflakeConnectionV1) con).returnMissingProperties();
con.close();
retVal = new DriverPropertyInfo[missingProperties.size()];
retVal = missingProperties.toArray(retVal);
return retVal;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public static boolean isDisableIncidents() {
return disableIncidents;
}
public static void setDisableIncidents(boolean throttleIncidents) {
SnowflakeDriver.disableIncidents = throttleIncidents;
}
public static final void main(String[] args) {
if (args.length > 0 && "--version".equals(args[0])) {
Package pkg = Package.getPackage("net.snowflake.client.jdbc");
if (pkg != null) {
System.out.println(pkg.getImplementationVersion());
}
}
}
}