OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HeavyAIConnection.java
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package ai.heavy.jdbc;
17 
19 
20 import org.apache.thrift.TException;
21 import org.apache.thrift.protocol.TBinaryProtocol;
22 import org.apache.thrift.protocol.TJSONProtocol;
23 import org.apache.thrift.protocol.TProtocol;
24 import org.apache.thrift.transport.TTransport;
25 import org.apache.thrift.transport.TTransportException;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28 
29 import java.io.*;
30 import java.security.*;
31 import java.security.cert.X509Certificate;
32 import java.sql.Array;
33 import java.sql.Blob;
34 import java.sql.CallableStatement;
35 import java.sql.Clob;
36 import java.sql.Connection;
37 import java.sql.DatabaseMetaData;
38 import java.sql.NClob;
39 import java.sql.PreparedStatement;
40 import java.sql.SQLClientInfoException;
41 import java.sql.SQLException;
42 import java.sql.SQLWarning;
43 import java.sql.SQLXML;
44 import java.sql.Savepoint;
45 import java.sql.Statement;
46 import java.sql.Struct;
47 import java.util.*;
48 import java.util.concurrent.Executor;
49 
50 import javax.crypto.Cipher;
51 
52 import ai.heavy.thrift.server.Heavy;
53 import ai.heavy.thrift.server.TDBException;
54 import ai.heavy.thrift.server.TDatumType;
55 import ai.heavy.thrift.server.TServerStatus;
56 import sun.security.provider.X509Factory;
57 
58 class KeyLoader {
59  static class S_struct {
60  public String cert;
61  public Key key;
62  }
63 
64  public static String getX509(X509Certificate cert) throws Exception {
65  String encoded = Base64.getMimeEncoder().encodeToString(cert.getEncoded());
66  // Note mimeEncoder inserts \r\n in the text - the server is okay with that.
67  encoded = X509Factory.BEGIN_CERT + "\n" + encoded + "\n" + X509Factory.END_CERT;
68  return encoded;
69  }
70 
71  public static S_struct getDetails_pkcs12(String filename, String password)
72  throws Exception {
73  S_struct s_struct = new S_struct();
74  try {
75  KeyStore keystore = KeyStore.getInstance("PKCS12");
76  java.io.FileInputStream fis = new java.io.FileInputStream(filename);
77  keystore.load(fis, password.toCharArray());
78  String alias = null;
79  Enumeration<String> eE = keystore.aliases();
80  int count = 0;
81  while (eE.hasMoreElements()) {
82  alias = eE.nextElement();
83  count++;
84  }
85  if (count != 1) {
86  throw new SQLException("pkcs12 file [" + filename
87  + "] contains an incorrect number [" + count
88  + "] of certificate(s); only a single certificate is allowed");
89  }
90 
91  X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
92  s_struct.cert = getX509(cert);
93  s_struct.key = keystore.getKey(alias, password.toCharArray());
94  } catch (Exception eX) {
95  HeavyAIConnection.logger.error(eX.getMessage());
96  throw eX;
97  }
98  return s_struct;
99  }
100 }
101 
102 class Options {
103  // The Options class supplies the keys for the
104  // Connection_properties class
105  static String host_name = "host_name";
106  static String port_num = "port_num";
107  static String db_name = "db_name";
108  static String protocol = "protocol";
109  static String server_trust_store = "server_trust_store";
110  static String server_trust_store_pwd = "server_trust_store_pwd";
111  static String pkiauth = "pkiauth";
112  static String sslcert = "sslcert";
113  static String sslkey = "sslkey";
114  static String sslkey_password = "sslkey_password";
115  static String max_rows = "max_rows";
116  static String user = "user";
117  static String password = "password";
118  // The order in the array corresponds to the order the value will appear in the
119  // ':'
120  // separated URL. Used to loop over the incoming URL and store in the properties
121  // struct
122  // Note user and password are not expected to come via the main body of the url
123  // However they may be supplied in the query string portion.
124 
125  static String[] option_order = {host_name,
126  port_num,
127  db_name,
128  protocol,
131  pkiauth,
132  sslcert,
133  sslkey,
135  max_rows};
136 }
137 
138 public class HeavyAIConnection implements java.sql.Connection, Cloneable {
139  final static Logger logger = LoggerFactory.getLogger(HeavyAIConnection.class);
140 
141  Set<String> protocol_set = new HashSet<String>(
142  Arrays.asList("binary", "binary_tls", "http", "https", "https_insecure"));
143 
144  class Connection_properties extends Properties {
145  // Properties can come in three ways:
146  // 1. via main part of the url,
147  // 2, via the query string portion of the URL or
148  // 3. via a Properties param
149  //
150  // Example url. Note the first two fields are constants and must be present. '
151  // jdbc:heavyai:localhost:4247:db_name?max_rows=2000&protocol=binary
152  //
153  // Priority is given to the URL data, followed by the query fragment data and
154  // lastly the Properties information
155  //
156  // All connection parameters can be supplied via the main portion of the
157  // connection
158  // URL, however as this structure is position dependent the nth argument must be
159  // preceded by the n - 1 arguments. In the case of complex connection strings it
160  // is
161  // recommended to use either a properties object or the query string portion of
162  // the
163  // URL.
164  //
165  // Note the class java.sql.DriverManager expects the URL to contain three
166  // components
167  // the literal string JDBC a 'subprotocol' followed by a 'subname', as in
168  // 'jdbc:heavyao:localhost' For this reason host mame must be supplied in the
169  // main
170  // part of the URL and should not be supplied in the query portion.
171 
173  String connection_url, Properties query_props) throws SQLException {
174  // The heavy.ai version of the connection_url is a ':' separated list
175  // with an optional 'query component' at the end (see example above).
176  // The query component starts with the first '?' in the string.
177  // Its is made up of key=value pairs separated by the '&' character.
178  //
179  // The query component is terminated by the end of the string and is
180  // assumed to be at the end of the URL
181 
182  String[] url_components = connection_url.split("\\?");
183  if (url_components.length == 2) {
184  // Query component are separated by an '&' - replace each with a '\n'
185  // will allow Properties.load method to build a properties obj
186  StringReader reader = new StringReader(url_components[1].replace('&', '\n'));
187  try {
188  query_props.load(reader);
189  } catch (IOException iex) {
190  throw new SQLException(iex.toString());
191  }
192  } else if (url_components.length > 2) {
193  throw new SQLException(
194  "Invalid connection string. Multiple query components included ["
195  + connection_url + "]");
196  }
197  // return the url with out any query component
198  return url_components[0];
199  }
200 
201  public Connection_properties(String connection_url, Properties baseProperties)
202  throws SQLException {
203  connection_url = extract_and_remove_query_components(connection_url, this);
204  String[] url_values = connection_url.split(":");
205  // add 2 for the default jdbc:heavy.ai at the start of the url.
206  if (url_values.length > Options.option_order.length + 2) {
207  // would be nice to print the url at this stage, but the user may have added
208  // their
209  // password into the list.
210  throw new SQLException("Invalid number of arguments provided in url ["
211  + url_values.length + "]. Maximum allowed ["
212  + (Options.option_order.length + 2) + "]");
213  }
214  for (int i = 2; i < url_values.length; i++) {
215  // the offest of 2 is caused by the 2 lables 'jdbc:heavyai' at the start if the
216  // URL
217  String existingValue = getProperty(Options.option_order[i - 2]);
218  if (existingValue != null && !existingValue.equals((url_values[i]))) {
219  logger.warn("Connection property [" + Options.option_order[i - 2]
220  + "] has been provided with different values in the URL and query component of the url. Defaulting to the URL value");
221  }
222  setProperty(Options.option_order[i - 2], url_values[i]);
223  }
224 
225  for (String key : baseProperties.stringPropertyNames()) {
226  String existingValue = getProperty(key);
227  if (existingValue != null
228  && !existingValue.equals(baseProperties.getProperty(key))) {
229  logger.warn("Connection property " + key
230  + "] has been provided with different values in the properties object and the url. Defaulting to the URL value");
231  } else {
232  setProperty(key, baseProperties.getProperty(key));
233  }
234  }
235 
236  validate_params();
237  }
238 
239  private void validate_params() throws SQLException {
240  // Warn if config values with invalid keys have been used.
241  for (String key : this.stringPropertyNames()) {
242  if (key != Options.user && key != Options.password
243  && !Arrays.asList(Options.option_order).contains(key)) {
244  logger.warn("Unsupported configuration key" + key + " used.");
245  }
246  }
247  // if present remove "//" from front of hostname
248  if (containsKey(Options.host_name)) {
249  String hN = this.getProperty(Options.host_name);
250  if (hN.startsWith("//")) {
251  this.setProperty(Options.host_name, hN.substring(2));
252  }
253  }
254 
255  // Default to binary if no protocol specified
256  String protocol = "binary";
257  if (this.containsKey(Options.protocol)) {
258  protocol = this.getProperty(Options.protocol);
259  protocol.toLowerCase();
260  if (!protocol_set.contains(protocol)) {
261  logger.warn("Incorrect protcol [" + protocol
262  + "] supplied. Possible values are [" + protocol_set.toString()
263  + "]. Using binary as default");
264  protocol = "binary";
265  }
266  }
267  this.setProperty(Options.protocol, protocol);
268 
269  if (this.containsKey(Options.port_num)) {
270  try {
271  Integer.parseInt(getProperty(Options.port_num));
272  } catch (NumberFormatException nfe) {
273  throw new SQLException(
274  "Invalid port number supplied" + getProperty(Options.port_num));
275  }
276  }
277 
278  if (this.containsKey(Options.server_trust_store)
279  && !this.containsKey(Options.server_trust_store_pwd)) {
280  logger.warn("server trust store ["
281  + (String) this.getProperty(Options.server_trust_store)
282  + " specfied without a password");
283  }
284  if (this.containsKey(Options.server_trust_store_pwd)
285  && !this.containsKey(Options.server_trust_store)) {
286  logger.warn("server trust store password specified without a keystore file");
287  }
288  if (!this.containsKey(Options.max_rows)) {
289  this.setProperty(Options.max_rows, "100000");
290  } else {
291  try {
292  Integer.parseInt(getProperty(Options.max_rows));
293  } catch (NumberFormatException nfe) {
294  throw new SQLException(
295  "Invalid value supplied for max rows " + getProperty(Options.max_rows));
296  }
297  }
298  }
299 
300  boolean isHttpProtocol() {
301  return (this.containsKey(Options.protocol)
302  && this.getProperty(Options.protocol).equals("http"));
303  }
304 
306  return (this.containsKey(Options.protocol)
307  && this.getProperty(Options.protocol).equals("https_insecure"));
308  }
309 
310  boolean isHttpsProtocol() {
311  return (this.containsKey(Options.protocol)
312  && this.getProperty(Options.protocol).equals("https"));
313  }
314 
315  boolean isBinary() {
316  return (this.containsKey(Options.protocol)
317  && this.getProperty(Options.protocol).equals("binary"));
318  }
319 
320  boolean isBinary_tls() {
321  return (this.containsKey(Options.protocol)
322  && this.getProperty(Options.protocol).equals("binary_tls"));
323  }
324 
325  boolean containsTrustStore() {
326  return this.containsKey(Options.server_trust_store);
327  }
328  }
329  /*
330  * End class Connection_properties
331  */
332 
333  protected String session = null;
334  protected Heavy.Client client = null;
335  protected String catalog;
336  protected TTransport transport;
337  protected SQLWarning warnings;
338  protected String url;
339  protected Connection_properties cP = null;
340 
341  public HeavyAIConnection getAlternateConnection() throws SQLException {
342  // Clones the orignal java connection object, and then reconnects
343  // at the thrift layer - doesn't re-authenticate at the application
344  // level. Instead reuses the orignal connections session number.
345  logger.debug("HeavyAIConnection clone");
346  HeavyAIConnection dbConnection = null;
347  try {
348  dbConnection = (HeavyAIConnection) super.clone();
349  } catch (CloneNotSupportedException eE) {
350  throw new SQLException(
351  "Error cloning connection [" + HeavyAIExceptionText.getExceptionDetail(eE),
352  eE);
353  }
354  // Now over write the old connection.
355  try {
356  TProtocol protocol = dbConnection.manageConnection();
357  dbConnection.client = new Heavy.Client(protocol);
358  } catch (java.lang.Exception jE) {
359  throw new SQLException("Error creating new connection "
361  jE);
362  }
363  return dbConnection;
364  }
365 
366  // any java.lang.Exception thrown is caught downstream and converted
367  // to a SQLException
368  private TProtocol manageConnection() throws java.lang.Exception {
369  SockTransportProperties skT = null;
370  String trust_store = null;
371  if (cP.getProperty(Options.server_trust_store) != null
372  && !cP.getProperty(Options.server_trust_store).isEmpty()) {
373  trust_store = cP.getProperty(Options.server_trust_store);
374  }
375  String trust_store_pwd = null;
376  if (cP.getProperty(Options.server_trust_store_pwd) != null
377  && !cP.getProperty(Options.server_trust_store_pwd).isEmpty()) {
378  trust_store_pwd = cP.getProperty(Options.server_trust_store_pwd);
379  }
380 
381  TProtocol protocol = null;
382  if (this.cP.isHttpProtocol()) {
383  // HTTP
384  skT = SockTransportProperties.getUnencryptedClient();
385 
386  transport = skT.openHttpClientTransport(this.cP.getProperty(Options.host_name),
387  Integer.parseInt(this.cP.getProperty(Options.port_num)));
388  transport.open();
389  protocol = new TJSONProtocol(transport);
390 
391  } else if (this.cP.isBinary()) {
392  skT = SockTransportProperties.getUnencryptedClient();
393  transport = skT.openClientTransport(this.cP.getProperty(Options.host_name),
394  Integer.parseInt(this.cP.getProperty(Options.port_num)));
395  if (!transport.isOpen()) transport.open();
396  protocol = new TBinaryProtocol(transport);
397 
398  } else if (this.cP.isHttpsProtocol() || this.cP.isHttpsProtocol_insecure()) {
399  if (trust_store == null) {
400  skT = SockTransportProperties.getEncryptedClientDefaultTrustStore(
401  !this.cP.isHttpsProtocol_insecure());
402  } else {
403  skT = SockTransportProperties.getEncryptedClientSpecifiedTrustStore(
404  trust_store, trust_store_pwd, !this.cP.isHttpsProtocol_insecure());
405  }
406  transport = skT.openHttpsClientTransport(this.cP.getProperty(Options.host_name),
407  Integer.parseInt(this.cP.getProperty(Options.port_num)));
408  transport.open();
409  protocol = new TJSONProtocol(transport);
410 
411  } else if (cP.isBinary_tls()) {
412  if (trust_store == null) {
413  skT = SockTransportProperties.getEncryptedClientDefaultTrustStore(false);
414  } else {
415  skT = SockTransportProperties.getEncryptedClientSpecifiedTrustStore(
416  trust_store, trust_store_pwd, false);
417  }
418  transport = skT.openClientTransport(this.cP.getProperty(Options.host_name),
419  Integer.parseInt(this.cP.getProperty(Options.port_num)));
420 
421  if (!transport.isOpen()) transport.open();
422  protocol = new TBinaryProtocol(transport);
423  } else {
424  throw new SQLException("Invalid protocol supplied");
425  }
426  return protocol;
427  }
428 
429  private void setSession(Object pki_auth) throws java.lang.Exception {
430  KeyLoader.S_struct s_struct = null;
431  // If pki aut then stuff public cert into password.
432  if (pki_auth != null && pki_auth.toString().equalsIgnoreCase("true")) {
433  s_struct = KeyLoader.getDetails_pkcs12(this.cP.getProperty(Options.sslcert),
434  this.cP.getProperty(Options.sslkey_password));
435  this.cP.setProperty(Options.password, s_struct.cert);
436  }
437 
438  // Get the seesion for all connectioms
439  session = client.connect((String) this.cP.getProperty(Options.user),
440  (String) this.cP.getProperty(Options.password),
441  (String) this.cP.getProperty(Options.db_name));
442 
443  // if pki auth the session will be encoded.
444  if (pki_auth != null && pki_auth.toString().equalsIgnoreCase("true")) {
445  Cipher cipher = Cipher.getInstance(s_struct.key.getAlgorithm());
446  cipher.init(Cipher.DECRYPT_MODE, s_struct.key);
447  // session is encrypted and encoded in b64
448  byte[] decodedBytes = Base64.getDecoder().decode(session);
449  byte[] decoded_bytes = cipher.doFinal(decodedBytes);
450  session = new String(decoded_bytes, "UTF-8");
451  }
452  }
453 
454  public HeavyAIConnection(String url, Properties base_properties) throws SQLException {
455  this.url = url;
456  this.cP = new Connection_properties(url, base_properties);
457  try {
458  TProtocol protocol = manageConnection();
459  client = new Heavy.Client(protocol);
460  setSession(this.cP.getProperty(Options.pkiauth));
461  catalog = (String) this.cP.getProperty(Options.db_name);
462  } catch (TTransportException ex) {
463  throw new SQLException("Thrift transport connection failed - "
465  ex);
466  } catch (TDBException ex) {
467  throw new SQLException("HEAVY.AI connection failed - "
469  ex);
470  } catch (TException ex) {
471  throw new SQLException(
472  "Thrift failed - " + HeavyAIExceptionText.getExceptionDetail(ex), ex);
473  } catch (java.lang.Exception ex) {
474  throw new SQLException(
475  "Connection failed - " + HeavyAIExceptionText.getExceptionDetail(ex), ex);
476  }
477  }
478 
479  @Override
480  public Statement createStatement() throws SQLException { // logger.debug("Entered");
481  return new HeavyAIStatement(session, this);
482  }
483 
484  @Override
485  public PreparedStatement prepareStatement(String sql)
486  throws SQLException { // logger.debug("Entered");
487  return new HeavyAIPreparedStatement(sql, session, this);
488  }
489 
490  @Override
491  public CallableStatement prepareCall(String sql)
492  throws SQLException { // logger.debug("Entered");
493  throw new UnsupportedOperationException("Not supported yet,"
494  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
495  + " class:" + new Throwable().getStackTrace()[0].getClassName()
496  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
497  }
498 
499  @Override
500  public String nativeSQL(String sql) throws SQLException { // logger.debug("Entered");
501  throw new UnsupportedOperationException("Not supported yet,"
502  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
503  + " class:" + new Throwable().getStackTrace()[0].getClassName()
504  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
505  }
506 
507  @Override
508  public void setAutoCommit(boolean autoCommit)
509  throws SQLException { // logger.debug("Entered");
510  // we always autocommit per statement
511  }
512 
513  @Override
514  public boolean getAutoCommit() throws SQLException { // logger.debug("Entered");
515  return true;
516  }
517 
518  @Override
519  public void commit() throws SQLException { // logger.debug("Entered");
520  // noop
521  }
522 
523  @Override
524  public void rollback() throws SQLException { // logger.debug("Entered");
525  throw new UnsupportedOperationException("Not supported yet,"
526  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
527  + " class:" + new Throwable().getStackTrace()[0].getClassName()
528  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
529  }
530 
531  @Override
532  public void close() throws SQLException { // logger.debug("Entered");
533  try {
534  logger.debug("Session at close is " + session);
535  if (session != null) {
536  client.disconnect(session);
537  }
538  closeConnection();
539  } catch (TDBException ex) {
540  throw new SQLException("disconnect failed." + ex.getError_msg());
541  } catch (TException ex) {
542  throw new SQLException("disconnect failed." + ex.toString());
543  }
544  }
545 
546  // needs to be accessed by other classes with in the package
547  protected void closeConnection() throws SQLException { // logger.debug("Entered");
548  session = null;
549  transport.close();
550  }
551 
552  @Override
553  public boolean isClosed() throws SQLException { // logger.debug("Entered");
554  if (session == null) {
555  return true;
556  }
557  return false;
558  }
559 
560  @Override
561  public DatabaseMetaData getMetaData() throws SQLException { // logger.debug("Entered");
562  DatabaseMetaData dbMetaData = new HeavyAIDatabaseMetaData(this);
563 
564  return dbMetaData;
565  }
566 
567  @Override
568  public void setReadOnly(boolean readOnly)
569  throws SQLException { // logger.debug("Entered");
570  // TODO MAT we can't push the readonly upstream currently
571  // but we could make JDBC obey this command
572  }
573 
574  @Override
575  public boolean isReadOnly() throws SQLException { // logger.debug("Entered");
576  try {
577  if (session != null) {
578  TServerStatus server_status = client.get_server_status(session);
579  return server_status.read_only;
580  }
581  } catch (TDBException ex) {
582  throw new SQLException(
583  "get_server_status failed during isReadOnly check." + ex.getError_msg());
584  } catch (TException ex) {
585  throw new SQLException(
586  "get_server_status failed during isReadOnly check." + ex.toString());
587  }
588  // never should get here
589  return true;
590  }
591 
592  @Override
593  public void setCatalog(String catalog) throws SQLException { // logger.debug("Entered");
594  throw new UnsupportedOperationException("Not supported yet,"
595  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
596  + " class:" + new Throwable().getStackTrace()[0].getClassName()
597  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
598  }
599 
600  @Override
601  public String getCatalog() throws SQLException { // logger.debug("Entered");
602  return catalog;
603  }
604 
605  @Override
606  public void setTransactionIsolation(int level)
607  throws SQLException { // logger.debug("Entered");
608  }
609 
610  @Override
611  public int getTransactionIsolation() throws SQLException { // logger.debug("Entered");
612  return Connection.TRANSACTION_NONE;
613  }
614 
615  @Override
616  public SQLWarning getWarnings() throws SQLException { // logger.debug("Entered");
617  return warnings;
618  }
619 
620  @Override
621  public void clearWarnings() throws SQLException { // logger.debug("Entered");
622  warnings = null;
623  }
624 
625  @Override
626  public Statement createStatement(int resultSetType, int resultSetConcurrency)
627  throws SQLException { // logger.debug("Entered");
628  return new HeavyAIStatement(session, this);
629  }
630 
631  @Override
632  public PreparedStatement prepareStatement(
633  String sql, int resultSetType, int resultSetConcurrency)
634  throws SQLException { // logger.debug("Entered");
635  return new HeavyAIPreparedStatement(sql, session, this);
636  }
637 
638  @Override
639  public CallableStatement prepareCall(
640  String sql, int resultSetType, int resultSetConcurrency)
641  throws SQLException { // logger.debug("Entered");
642  throw new UnsupportedOperationException("Not supported yet,"
643  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
644  + " class:" + new Throwable().getStackTrace()[0].getClassName()
645  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
646  }
647 
648  @Override
649  public Map<String, Class<?>> getTypeMap()
650  throws SQLException { // logger.debug("Entered");
651  throw new UnsupportedOperationException("Not supported yet,"
652  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
653  + " class:" + new Throwable().getStackTrace()[0].getClassName()
654  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
655  }
656 
657  @Override
658  public void setTypeMap(Map<String, Class<?>> map)
659  throws SQLException { // logger.debug("Entered");
660  throw new UnsupportedOperationException("Not supported yet,"
661  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
662  + " class:" + new Throwable().getStackTrace()[0].getClassName()
663  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
664  }
665 
666  @Override
667  public void setHoldability(int holdability)
668  throws SQLException { // logger.debug("Entered");
669  throw new UnsupportedOperationException("Not supported yet,"
670  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
671  + " class:" + new Throwable().getStackTrace()[0].getClassName()
672  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
673  }
674 
675  @Override
676  public int getHoldability() throws SQLException { // logger.debug("Entered");
677  throw new UnsupportedOperationException("Not supported yet,"
678  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
679  + " class:" + new Throwable().getStackTrace()[0].getClassName()
680  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
681  }
682 
683  @Override
684  public Savepoint setSavepoint() throws SQLException { // logger.debug("Entered");
685  throw new UnsupportedOperationException("Not supported yet,"
686  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
687  + " class:" + new Throwable().getStackTrace()[0].getClassName()
688  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
689  }
690 
691  @Override
692  public Savepoint setSavepoint(String name)
693  throws SQLException { // logger.debug("Entered");
694  throw new UnsupportedOperationException("Not supported yet,"
695  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
696  + " class:" + new Throwable().getStackTrace()[0].getClassName()
697  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
698  }
699 
700  @Override
701  public void rollback(Savepoint savepoint)
702  throws SQLException { // logger.debug("Entered");
703  throw new UnsupportedOperationException("Not supported yet,"
704  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
705  + " class:" + new Throwable().getStackTrace()[0].getClassName()
706  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
707  }
708 
709  @Override
710  public void releaseSavepoint(Savepoint savepoint)
711  throws SQLException { // logger.debug("Entered");
712  throw new UnsupportedOperationException("Not supported yet,"
713  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
714  + " class:" + new Throwable().getStackTrace()[0].getClassName()
715  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
716  }
717 
718  @Override
719  public Statement createStatement(
720  int resultSetType, int resultSetConcurrency, int resultSetHoldability)
721  throws SQLException { // logger.debug("Entered");
722  throw new UnsupportedOperationException("Not supported yet,"
723  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
724  + " class:" + new Throwable().getStackTrace()[0].getClassName()
725  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
726  }
727 
728  @Override
729  public PreparedStatement prepareStatement(String sql,
730  int resultSetType,
731  int resultSetConcurrency,
732  int resultSetHoldability) throws SQLException { // logger.debug("Entered");
733  throw new UnsupportedOperationException("Not supported yet,"
734  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
735  + " class:" + new Throwable().getStackTrace()[0].getClassName()
736  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
737  }
738 
739  @Override
740  public CallableStatement prepareCall(String sql,
741  int resultSetType,
742  int resultSetConcurrency,
743  int resultSetHoldability) throws SQLException { // logger.debug("Entered");
744  throw new UnsupportedOperationException("Not supported yet,"
745  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
746  + " class:" + new Throwable().getStackTrace()[0].getClassName()
747  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
748  }
749 
750  @Override
751  public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
752  throws SQLException { // logger.debug("Entered");
753  throw new UnsupportedOperationException("Not supported yet,"
754  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
755  + " class:" + new Throwable().getStackTrace()[0].getClassName()
756  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
757  }
758 
759  @Override
760  public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
761  throws SQLException { // logger.debug("Entered");
762  throw new UnsupportedOperationException("Not supported yet,"
763  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
764  + " class:" + new Throwable().getStackTrace()[0].getClassName()
765  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
766  }
767 
768  @Override
769  public PreparedStatement prepareStatement(String sql, String[] columnNames)
770  throws SQLException { // logger.debug("Entered");
771  throw new UnsupportedOperationException("Not supported yet,"
772  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
773  + " class:" + new Throwable().getStackTrace()[0].getClassName()
774  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
775  }
776 
777  @Override
778  public Clob createClob() throws SQLException { // logger.debug("Entered");
779  throw new UnsupportedOperationException("Not supported yet,"
780  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
781  + " class:" + new Throwable().getStackTrace()[0].getClassName()
782  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
783  }
784 
785  @Override
786  public Blob createBlob() throws SQLException { // logger.debug("Entered");
787  throw new UnsupportedOperationException("Not supported yet,"
788  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
789  + " class:" + new Throwable().getStackTrace()[0].getClassName()
790  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
791  }
792 
793  @Override
794  public NClob createNClob() throws SQLException { // logger.debug("Entered");
795  throw new UnsupportedOperationException("Not supported yet,"
796  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
797  + " class:" + new Throwable().getStackTrace()[0].getClassName()
798  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
799  }
800 
801  @Override
802  public SQLXML createSQLXML() throws SQLException { // logger.debug("Entered");
803  throw new UnsupportedOperationException("Not supported yet,"
804  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
805  + " class:" + new Throwable().getStackTrace()[0].getClassName()
806  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
807  }
808 
809  @Override
810  public boolean isValid(int timeout) throws SQLException { // logger.debug("Entered");
811  try {
812  client.get_server_status(session);
813  } catch (TTransportException ex) {
814  throw new SQLException("Connection failed - " + ex.toString());
815  } catch (TDBException ex) {
816  throw new SQLException("Connection failed - " + ex.getError_msg());
817  } catch (TException ex) {
818  throw new SQLException("Connection failed - " + ex.toString());
819  }
820  return true;
821  }
822 
823  @Override
824  public void setClientInfo(String name, String value) throws SQLClientInfoException {
825  throw new UnsupportedOperationException("Not supported yet,"
826  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
827  + " class:" + new Throwable().getStackTrace()[0].getClassName()
828  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
829  }
830 
831  @Override
832  public void setClientInfo(Properties properties) throws SQLClientInfoException {
833  throw new UnsupportedOperationException("Not supported yet,"
834  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
835  + " class:" + new Throwable().getStackTrace()[0].getClassName()
836  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
837  }
838 
839  @Override
840  public String getClientInfo(String name)
841  throws SQLException { // logger.debug("Entered");
842  throw new UnsupportedOperationException("Not supported yet,"
843  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
844  + " class:" + new Throwable().getStackTrace()[0].getClassName()
845  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
846  }
847 
848  @Override
849  public Properties getClientInfo() throws SQLException { // logger.debug("Entered");
850  throw new UnsupportedOperationException("Not supported yet,"
851  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
852  + " class:" + new Throwable().getStackTrace()[0].getClassName()
853  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
854  }
855 
856  @Override
857  public Array createArrayOf(String typeName, Object[] elements)
858  throws SQLException { // logger.debug("Entered");
859  TDatumType type;
860  try {
861  type = TDatumType.valueOf(typeName.toUpperCase());
862  } catch (IllegalArgumentException ex) {
863  throw new SQLException("No matching heavyDB type for " + typeName);
864  }
865  return new HeavyAIArray(type, elements);
866  }
867 
868  @Override
869  public Struct createStruct(String typeName, Object[] attributes)
870  throws SQLException { // logger.debug("Entered");
871  throw new UnsupportedOperationException("Not supported yet,"
872  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
873  + " class:" + new Throwable().getStackTrace()[0].getClassName()
874  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
875  }
876 
877  @Override
878  public void setSchema(String schema) throws SQLException { // logger.debug("Entered");
879  // Setting setSchema to be a NOOP allows integration with third party products
880  // that require a successful call to setSchema to work.
881  Object db_name = this.cP.getProperty(Options.db_name);
882  if (db_name == null) {
883  throw new SQLException("db name not set, "
884  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
885  + " class:" + new Throwable().getStackTrace()[0].getClassName()
886  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
887  }
888  if (!schema.equals(db_name.toString())) {
889  logger.warn("Connected to schema [" + schema + "] differs from db name [" + db_name
890  + "].");
891  }
892  return;
893  }
894 
895  @Override
896  public String getSchema() throws SQLException { // logger.debug("Entered");
897  throw new UnsupportedOperationException("Not supported yet,"
898  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
899  + " class:" + new Throwable().getStackTrace()[0].getClassName()
900  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
901  }
902 
903  @Override
904  public void abort(Executor executor) throws SQLException { // logger.debug("Entered");
905  throw new UnsupportedOperationException("Not supported yet,"
906  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
907  + " class:" + new Throwable().getStackTrace()[0].getClassName()
908  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
909  }
910 
911  @Override
912  public void setNetworkTimeout(Executor executor, int milliseconds)
913  throws SQLException { // logger.debug("Entered");
914  throw new UnsupportedOperationException("Not supported yet,"
915  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
916  + " class:" + new Throwable().getStackTrace()[0].getClassName()
917  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
918  }
919 
920  @Override
921  public int getNetworkTimeout() throws SQLException { // logger.debug("Entered");
922  throw new UnsupportedOperationException("Not supported yet,"
923  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
924  + " class:" + new Throwable().getStackTrace()[0].getClassName()
925  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
926  }
927 
928  @Override
929  public <T> T unwrap(Class<T> iface) throws SQLException { // logger.debug("Entered");
930  throw new UnsupportedOperationException("Not supported yet,"
931  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
932  + " class:" + new Throwable().getStackTrace()[0].getClassName()
933  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
934  }
935 
936  @Override
937  public boolean isWrapperFor(Class<?> iface)
938  throws SQLException { // logger.debug("Entered");
939  throw new UnsupportedOperationException("Not supported yet,"
940  + " line:" + new Throwable().getStackTrace()[0].getLineNumber()
941  + " class:" + new Throwable().getStackTrace()[0].getClassName()
942  + " method:" + new Throwable().getStackTrace()[0].getMethodName());
943  }
944 }
static S_struct getDetails_pkcs12(String filename, String password)
void setAutoCommit(boolean autoCommit)
HeavyAIConnection getAlternateConnection()
static String server_trust_store_pwd
static String getX509(X509Certificate cert)
Struct createStruct(String typeName, Object[] attributes)
void setHoldability(int holdability)
void setClientInfo(Properties properties)
void setReadOnly(boolean readOnly)
Map< String, Class<?> > getTypeMap()
static String server_trust_store
HeavyAIConnection(String url, Properties base_properties)
Array createArrayOf(String typeName, Object[] elements)
PreparedStatement prepareStatement(String sql, String[] columnNames)
Connection_properties(String connection_url, Properties baseProperties)
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
boolean isWrapperFor(Class<?> iface)
Statement createStatement(int resultSetType, int resultSetConcurrency)
PreparedStatement prepareStatement(String sql)
PreparedStatement prepareStatement(String sql, int[] columnIndexes)
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
String extract_and_remove_query_components(String connection_url, Properties query_props)
CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
static String getExceptionDetail(Exception ex)
void rollback(Savepoint savepoint)
static String[] option_order
void setClientInfo(String name, String value)
Savepoint setSavepoint(String name)
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
void setTypeMap(Map< String, Class<?>> map)
std::string typeName(const T *v)
Definition: toString.h:106
void setNetworkTimeout(Executor executor, int milliseconds)
public< T > T unwrap(Class< T > iface)
Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
string name
Definition: setup.in.py:72
CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
void releaseSavepoint(Savepoint savepoint)
CallableStatement prepareCall(String sql)