docs: public static void main(String[] args) throws IOException,
              InterruptedException {
          start = System.currentTimeMillis();
          long insertTimeStart = start;
          long insertTimeEnd;
  
          final JDBCLoaderConfig cfg = new JDBCLoaderConfig();
          cfg.parse(JDBCLoader.class.getName(), args);
  
          FileReader fr = null;
          BufferedReader br = null;
          m_config = cfg;
          configuration();
          // Split server list
          final String[] serverlist = m_config.servers.split(",");
  
          // read username and password from txt file
          if (m_config.credentials != null && !m_config.credentials.trim().isEmpty()) {
              Properties props = MiscUtils.readPropertiesFromCredentials(m_config.credentials);
              m_config.user = props.getProperty("username");
              m_config.password = props.getProperty("password");
          }
          // If we need to prompt the user for a VoltDB password, do so.
          m_config.password = CLIConfig.readPasswordIfNeeded(m_config.user, m_config.password, "Enter VoltDB password: ");
  
          // Create connection
          final ClientConfig c_config;
          AutoReconnectListener listener = new AutoReconnectListener();
          if (m_config.stopondisconnect) {
              c_config = new ClientConfig(m_config.user, m_config.password, null);
              c_config.setReconnectOnConnectionLoss(false);
          } else {
              c_config = new ClientConfig(m_config.user, m_config.password, listener);
              c_config.setReconnectOnConnectionLoss(true);
          }
          if (m_config.ssl != null && !m_config.ssl.trim().isEmpty()) {
              c_config.setTrustStoreConfigFromPropertyFile(m_config.ssl);
              c_config.enableSSL();
          }
          c_config.setProcedureCallTimeout(0); // Set procedure all to infinite
          Client csvClient = null;
          try {
              csvClient = JDBCLoader.getClient(c_config, serverlist, m_config.port);
          } catch (Exception e) {
              System.err.println("Error connecting to the servers: "
                                 + m_config.servers + ": " + e);
              System.exit(-1);
          }
          assert (csvClient != null);
  
          try {
              long readerTime;
              long insertCount;
              long ackCount;
              final JDBCLoader errHandler = new JDBCLoader();
              final CSVDataLoader dataLoader;
  
              errHandler.launchErrorFlushProcessor();
  
  
              if (m_config.useSuppliedProcedure) {
                  dataLoader = new CSVTupleDataLoader((ClientImpl) csvClient, m_config.procedure, errHandler);
              } else {
                  dataLoader = new CSVBulkDataLoader((ClientImpl) csvClient, m_config.table, m_config.batch, m_config.update, errHandler);
              }
  
              if (!m_config.stopondisconnect) {
                  listener.setLoader(dataLoader);
              }
  
              // If we need to prompt the user for a JDBC datasource password, do so.
              m_config.jdbcpassword = CLIConfig.readPasswordIfNeeded(m_config.jdbcuser, m_config.jdbcpassword, "Enter JDBC source database password: ");
  
              //Created Source reader
              JDBCStatementReader.initializeReader(cfg, csvClient);
  
              JDBCStatementReader jdbcReader = new JDBCStatementReader(dataLoader, errHandler);
              Thread readerThread = new Thread(jdbcReader);
              readerThread.setName("JDBCSourceReader");
              readerThread.setDaemon(true);
  
              //Wait for reader to finish.
              readerThread.start();
              readerThread.join();
  
              insertTimeEnd = System.currentTimeMillis();
  
              csvClient.close();
  
              errHandler.waitForErrorFlushComplete();
  
              readerTime = (jdbcReader.m_parsingTime) / 1000000;
              insertCount = dataLoader.getProcessedRows();
              ackCount = insertCount - dataLoader.getFailedRows();
  
              if (errHandler.hasReachedErrorLimit()) {
                  System.out.println("The number of failed rows exceeds the configured maximum failed rows: "
                          + m_config.maxerrors);
              }
              System.out.println("Read " + insertCount + " rows from file and successfully inserted "
                         + ackCount + " rows (final)");
              errHandler.produceFiles(ackCount, insertCount);
              close_cleanup();
  
              //In test junit mode we let it continue for reuse
              if (!JDBCLoader.testMode) {
                  System.exit(errHandler.m_errorInfo.isEmpty() ? 0 : -1);
              }
          } catch (Exception ex) {
              System.err.println("Exception Happened while loading CSV data : " + ex);
              System.exit(1);
          }
      }