public boolean init(StepMetaInterface smi, StepDataInterface sdi) {
    meta = (TableOutputMeta) smi;
    data = (TableOutputData) sdi;

    if (super.init(smi, sdi)) {
      try {
        data.commitSize = Integer.parseInt(environmentSubstitute(meta.getCommitSize()));

        data.databaseMeta = meta.getDatabaseMeta();
        DatabaseInterface dbInterface = data.databaseMeta.getDatabaseInterface();

        // Batch updates are not supported on PostgreSQL (and look-a-likes)
        // together with error handling (PDI-366).
        // For these situations we can use savepoints to help out.
        //
        data.useSafePoints =
            data.databaseMeta.getDatabaseInterface().useSafePoints()
                && getStepMeta().isDoingErrorHandling();

        // Get the boolean that indicates whether or not we can/should release
        // savepoints during data load.
        //
        data.releaseSavepoint = dbInterface.releaseSavepoint();

        // Disable batch mode in case
        // - we use an unlimited commit size
        // - if we need to pick up auto-generated keys
        // - if you are running the transformation as a single database transaction (unique
        // connections)
        // - if we are reverting to save-points
        //
        data.batchMode =
            meta.useBatchUpdate()
                && data.commitSize > 0
                && !meta.isReturningGeneratedKeys()
                && !getTransMeta().isUsingUniqueConnections()
                && !data.useSafePoints;

        // Per PDI-6211 : give a warning that batch mode operation in combination with step error
        // handling can lead to
        // incorrectly processed rows.
        //
        if (getStepMeta().isDoingErrorHandling()
            && !dbInterface.supportsErrorHandlingOnBatchUpdates()) {
          log.logMinimal(
              BaseMessages.getString(
                  PKG, "TableOutput.Warning.ErrorHandlingIsNotFullySupportedWithBatchProcessing"));
        }

        if (meta.getDatabaseMeta() == null) {
          throw new KettleException(
              BaseMessages.getString(PKG, "TableOutput.Exception.DatabaseNeedsToBeSelected"));
        }
        if (meta.getDatabaseMeta() == null) {
          logError(
              BaseMessages.getString(PKG, "TableOutput.Init.ConnectionMissing", getStepname()));
          return false;
        }
        data.db = new Database(this, meta.getDatabaseMeta());
        data.db.shareVariablesWith(this);

        if (getTransMeta().isUsingUniqueConnections()) {
          synchronized (getTrans()) {
            data.db.connect(getTrans().getTransactionId(), getPartitionID());
          }
        } else {
          data.db.connect(getPartitionID());
        }

        if (log.isBasic()) {
          logBasic(
              "Connected to database ["
                  + meta.getDatabaseMeta()
                  + "] (commit="
                  + data.commitSize
                  + ")");
        }

        // Postpone commit as long as possible. PDI-2091
        //
        if (data.commitSize == 0) {
          data.commitSize = Integer.MAX_VALUE;
        }
        data.db.setCommit(data.commitSize);

        if (!meta.isPartitioningEnabled() && !meta.isTableNameInField()) {
          data.tableName = environmentSubstitute(meta.getTableName());

          // Only the first one truncates in a non-partitioned step copy
          //
          if (meta.truncateTable()
              && ((getCopy() == 0 && getUniqueStepNrAcrossSlaves() == 0)
                  || !Const.isEmpty(getPartitionID()))) {
            data.db.truncateTable(
                environmentSubstitute(meta.getSchemaName()),
                environmentSubstitute(meta.getTableName()));
          }
        }

        return true;
      } catch (KettleException e) {
        logError("An error occurred intialising this step: " + e.getMessage());
        stopAll();
        setErrors(1);
      }
    }
    return false;
  }