package org.pentaho.di.core.database;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.BatchUpdateException;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.vfs2.FileObject;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.Counter;
import org.pentaho.di.core.DBCache;
import org.pentaho.di.core.DBCacheEntry;
import org.pentaho.di.core.ProgressMonitorListener;
import org.pentaho.di.core.Result;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.database.DataSourceProviderInterface.DatasourceType;
import org.pentaho.di.core.database.map.DatabaseConnectionMap;
import org.pentaho.di.core.database.util.DatabaseLogExceptionFactory;
import org.pentaho.di.core.database.util.DatabaseUtil;
import org.pentaho.di.core.encryption.Encr;
import org.pentaho.di.core.exception.KettleDatabaseBatchException;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleValueException;
import org.pentaho.di.core.extension.ExtensionPointHandler;
import org.pentaho.di.core.extension.KettleExtensionPoint;
import org.pentaho.di.core.logging.DefaultLogLevel;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.core.logging.LogLevel;
import org.pentaho.di.core.logging.LogStatus;
import org.pentaho.di.core.logging.LogTableCoreInterface;
import org.pentaho.di.core.logging.LogTableField;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.core.logging.LoggingObjectType;
import org.pentaho.di.core.logging.Metrics;
import org.pentaho.di.core.plugins.DatabasePluginType;
import org.pentaho.di.core.plugins.PluginInterface;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.row.RowDataUtil;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.ValueMeta;
import org.pentaho.di.core.row.ValueMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaBase;
import org.pentaho.di.core.row.value.ValueMetaBigNumber;
import org.pentaho.di.core.row.value.ValueMetaBinary;
import org.pentaho.di.core.row.value.ValueMetaBoolean;
import org.pentaho.di.core.row.value.ValueMetaDate;
import org.pentaho.di.core.row.value.ValueMetaFactory;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaInternetAddress;
import org.pentaho.di.core.row.value.ValueMetaNone;
import org.pentaho.di.core.row.value.ValueMetaNumber;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.row.value.ValueMetaTimestamp;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.variables.VariableSpace;
import org.pentaho.di.core.variables.Variables;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.ObjectRevision;
import org.pentaho.di.repository.RepositoryDirectory;

public class Database implements VariableSpace, LoggingObjectInterface {
    private static final Class<?> PKG = Database.class;
    private static final Map<String, Set<String>> registeredDrivers = new HashMap();
    private DatabaseMeta databaseMeta;
    private int rowlimit;
    private int commitsize;
    private Connection connection;
    private Statement sel_stmt;
    private PreparedStatement pstmt;
    private PreparedStatement prepStatementLookup;
    private PreparedStatement prepStatementUpdate;
    private PreparedStatement prepStatementInsert;
    private PreparedStatement pstmt_seq;
    private CallableStatement cstmt;
    private DatabaseMetaData dbmd;
    private RowMetaInterface rowMeta;
    private int written;
    private LogChannelInterface log;
    private LoggingObjectInterface parentLoggingObject;
    private static final String[] TABLE_TYPES_TO_GET = new String[]{"TABLE", "VIEW"};
    private static final String TABLES_META_DATA_TABLE_NAME = "TABLE_NAME";
    private volatile int opened;
    private volatile int copy;
    private String connectionGroup;
    private String partitionId;
    private VariableSpace variables = new Variables();
    private LogLevel logLevel = DefaultLogLevel.getLogLevel();
    private String containerObjectId;
    private int nrExecutedCommits;
    private static List<ValueMetaInterface> valueMetaPluginClasses;

    /** @deprecated */
    @Deprecated
    public Database(DatabaseMeta databaseMeta) {
        this.parentLoggingObject = null;
        this.databaseMeta = databaseMeta;
        this.shareVariablesWith(databaseMeta);
        this.log = new LogChannel(this);
        this.logLevel = this.log.getLogLevel();
        this.containerObjectId = this.log.getContainerObjectId();
        this.pstmt = null;
        this.rowMeta = null;
        this.dbmd = null;
        this.rowlimit = 0;
        this.written = 0;
        this.opened = this.copy = 0;
        if(this.log.isDetailed()) {
            this.log.logDetailed("New database connection defined");
        }

    }

    public Database(LoggingObjectInterface parentObject, DatabaseMeta databaseMeta) {
        this.parentLoggingObject = parentObject;
        this.databaseMeta = databaseMeta;
        this.shareVariablesWith(databaseMeta);
        if(parentObject instanceof VariableSpace) {
            this.shareVariablesWith((VariableSpace)parentObject);
        }

        this.log = new LogChannel(this, parentObject);
        this.containerObjectId = this.log.getContainerObjectId();
        this.logLevel = this.log.getLogLevel();
        if(parentObject != null) {
            this.log.setGatheringMetrics(parentObject.isGatheringMetrics());
        }

        this.pstmt = null;
        this.rowMeta = null;
        this.dbmd = null;
        this.rowlimit = 0;
        this.written = 0;
        this.opened = this.copy = 0;
        if(this.log.isDetailed()) {
            this.log.logDetailed("New database connection defined");
        }

    }

    public boolean equals(Object obj) {
        Database other = (Database)obj;
        return this.databaseMeta.equals(other.databaseMeta);
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public Connection getConnection() {
        return this.connection;
    }

    public void setQueryLimit(int rows) {
        this.rowlimit = rows;
    }

    public PreparedStatement getPrepStatementInsert() {
        return this.prepStatementInsert;
    }

    public PreparedStatement getPrepStatementLookup() {
        return this.prepStatementLookup;
    }

    public PreparedStatement getPrepStatementUpdate() {
        return this.prepStatementUpdate;
    }

    public void connect() throws KettleDatabaseException {
        this.connect((String)null);
    }

    public void connect(String partitionId) throws KettleDatabaseException {
        this.connect((String)null, partitionId);
    }

    public synchronized void connect(String group, String partitionId) throws KettleDatabaseException {
        try {
            this.log.snap(Metrics.METRIC_DATABASE_CONNECT_START, this.databaseMeta.getName(), new long[0]);
            if(!Utils.isEmpty(group)) {
                this.connectionGroup = group;
                this.partitionId = partitionId;
                Database lookup = DatabaseConnectionMap.getInstance().getOrStoreIfAbsent(group, partitionId, this);
                if(lookup == null) {
                    lookup = this;
                }

                lookup.shareConnectionWith(partitionId, this);
            } else {
                this.normalConnect(partitionId);
            }

            try {
                ExtensionPointHandler.callExtensionPoint(this.log, KettleExtensionPoint.DatabaseConnected.id, this);
            } catch (KettleException var7) {
                throw new KettleDatabaseException(var7);
            }
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_CONNECT_STOP, this.databaseMeta.getName(), new long[0]);
        }

    }

    private synchronized void shareConnectionWith(String partitionId, Database anotherDb) throws KettleDatabaseException {
        ++this.opened;
        if(this.connection == null) {
            this.normalConnect(partitionId);
            this.copy = this.opened;
            this.setAutoCommit(false);
        }

        anotherDb.connection = this.connection;
        anotherDb.copy = this.opened;
    }

    public void normalConnect(String partitionId) throws KettleDatabaseException {
        if(this.databaseMeta == null) {
            throw new KettleDatabaseException("No valid database connection defined!");
        } else {
            try {
                DataSourceProviderInterface dsp = DataSourceProviderFactory.getDataSourceProviderInterface();
                if(dsp == null) {
                    dsp = new DatabaseUtil();
                }

                String sql;
                if(this.databaseMeta.getAccessType() == 4) {
                    sql = this.environmentSubstitute(this.databaseMeta.getDatabaseName());

                    try {
                        this.connection = ((DataSourceProviderInterface)dsp).getNamedDataSource(sql, DatasourceType.JNDI).getConnection();
                    } catch (DataSourceNamingException var7) {
                        this.log.logError("Unable to find datasource by JNDI name: " + sql, var7);
                        throw var7;
                    }
                } else if(this.databaseMeta.isUsingConnectionPool()) {
                    sql = this.databaseMeta.getName();

                    try {
                        try {
                            this.connection = ((DataSourceProviderInterface)dsp).getNamedDataSource(sql, DatasourceType.POOLED).getConnection();
                        } catch (NullPointerException | UnsupportedOperationException var5) {
                            this.connection = ConnectionPoolUtil.getConnection(this.log, this.databaseMeta, partitionId);
                        }

                        if(this.getConnection().getAutoCommit() != this.isAutoCommit()) {
                            this.setAutoCommit(this.isAutoCommit());
                        }
                    } catch (DataSourceNamingException var6) {
                        this.log.logError("Unable to find pooled datasource by its name: " + sql, var6);
                        throw var6;
                    }
                } else {
                    this.connectUsingClass(this.databaseMeta.getDriverClass(), partitionId);
                }

                sql = this.environmentSubstitute(this.databaseMeta.getConnectSQL());
                if(!Utils.isEmpty(sql) && !Const.onlySpaces(sql)) {
                    this.execStatements(sql);
                    if(this.log.isDetailed()) {
                        this.log.logDetailed("Executed connect time SQL statements:" + Const.CR + sql);
                    }
                }

            } catch (Exception var8) {
                throw new KettleDatabaseException("Error occurred while trying to connect to the database", var8);
            }
        }
    }

    private void connectUsingClass(String classname, String partitionId) throws KettleDatabaseException {
        PluginInterface plugin = PluginRegistry.getInstance().getPlugin(DatabasePluginType.class, this.databaseMeta.getDatabaseInterface());

        String username;
        try {
            Class var4 = DriverManager.class;
            synchronized(DriverManager.class) {
                ClassLoader classLoader = PluginRegistry.getInstance().getClassLoader(plugin);
                Class<?> driverClass = classLoader.loadClass(classname);
                if(driverClass.getClassLoader() != this.getClass().getClassLoader()) {
                    username = PluginRegistry.getInstance().getPluginId(DatabasePluginType.class, this.databaseMeta.getDatabaseInterface());
                    Set<String> registeredDriversFromPlugin = (Set)registeredDrivers.get(username);
                    if(registeredDriversFromPlugin == null) {
                        registeredDriversFromPlugin = new HashSet();
                        registeredDrivers.put(username, registeredDriversFromPlugin);
                    }

                    if(!((Set)registeredDriversFromPlugin).contains(driverClass.getCanonicalName())) {
                        DriverManager.registerDriver(new DelegatingDriver((Driver)driverClass.newInstance()));
                        ((Set)registeredDriversFromPlugin).add(driverClass.getCanonicalName());
                    }
                } else {
                    Class.forName(classname);
                }
            }
        } catch (NoClassDefFoundError var12) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToFindClassMissingDriver", new String[]{classname, plugin.getName()}), var12);
        } catch (ClassNotFoundException var13) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToFindClassMissingDriver", new String[]{classname, plugin.getName()}), var13);
        } catch (Exception var14) {
            throw new KettleDatabaseException("Exception while loading class", var14);
        }

        try {
            String url;
            if(this.databaseMeta.isPartitioned() && !Utils.isEmpty(partitionId)) {
                url = this.environmentSubstitute(this.databaseMeta.getURL(partitionId));
            } else {
                url = this.environmentSubstitute(this.databaseMeta.getURL());
            }

            String clusterUsername = null;
            String clusterPassword = null;
            if(this.databaseMeta.isPartitioned() && !Utils.isEmpty(partitionId)) {
                PartitionDatabaseMeta partition = this.databaseMeta.getPartitionMeta(partitionId);
                if(partition != null) {
                    clusterUsername = partition.getUsername();
                    clusterPassword = Encr.decryptPasswordOptionallyEncrypted(partition.getPassword());
                }
            }

            String password;
            if(!Utils.isEmpty(clusterUsername)) {
                username = clusterUsername;
                password = clusterPassword;
            } else {
                username = this.environmentSubstitute(this.databaseMeta.getUsername());
                password = Encr.decryptPasswordOptionallyEncrypted(this.environmentSubstitute(this.databaseMeta.getPassword()));
            }

            Properties properties = this.databaseMeta.getConnectionProperties();
//            System.out.println("********** 初始化数据库连接，追加参数&characterEncoding=utf8 **********");
            url += "&characterEncoding=utf8&autoReconnect=true";
//            System.out.println("");
//            System.out.println("********** 初始化数据库连接，追加参数&characterEncoding=utf8 **********");
            if(this.databaseMeta.supportsOptionsInURL()) {
                if(Utils.isEmpty(username) && Utils.isEmpty(password)) {
                    this.connection = DriverManager.getConnection(url, properties);
                } else {
                    properties.put("user", Const.NVL(username, " "));
                    properties.put("password", Const.NVL(password, ""));
                    if(this.databaseMeta.getDatabaseInterface() instanceof MSSQLServerNativeDatabaseMeta) {
                        String instance = this.environmentSubstitute(this.databaseMeta.getSQLServerInstance());
                        if(!Utils.isEmpty(instance)) {
                            url = url + ";instanceName=" + instance;
                        }
                    }

                    this.connection = DriverManager.getConnection(url, properties);
                }
            } else {
                if(!Utils.isEmpty(username)) {
                    properties.put("user", username);
                }

                if(!Utils.isEmpty(password)) {
                    properties.put("password", password);
                }

                this.connection = DriverManager.getConnection(url, properties);
            }

        } catch (SQLException var15) {
            throw new KettleDatabaseException("Error connecting to database: (using class " + classname + ")", var15);
        } catch (Throwable var16) {
            throw new KettleDatabaseException("Error connecting to database: (using class " + classname + ")", var16);
        }
    }

    public synchronized void disconnect() {
        if(this.connection != null) {
            try {
                if(this.connection.isClosed()) {
                    return;
                }
            } catch (SQLException var25) {
                this.log.logError("Error checking closing connection:" + Const.CR + var25.getMessage());
                this.log.logError(Const.getStackTracker(var25));
            }

            if(this.pstmt != null) {
                try {
                    this.pstmt.close();
                } catch (SQLException var24) {
                    this.log.logError("Error closing statement:" + Const.CR + var24.getMessage());
                    this.log.logError(Const.getStackTracker(var24));
                }

                this.pstmt = null;
            }

            if(this.prepStatementLookup != null) {
                try {
                    this.prepStatementLookup.close();
                } catch (SQLException var23) {
                    this.log.logError("Error closing lookup statement:" + Const.CR + var23.getMessage());
                    this.log.logError(Const.getStackTracker(var23));
                }

                this.prepStatementLookup = null;
            }

            if(this.prepStatementInsert != null) {
                try {
                    this.prepStatementInsert.close();
                } catch (SQLException var22) {
                    this.log.logError("Error closing insert statement:" + Const.CR + var22.getMessage());
                    this.log.logError(Const.getStackTracker(var22));
                }

                this.prepStatementInsert = null;
            }

            if(this.prepStatementUpdate != null) {
                try {
                    this.prepStatementUpdate.close();
                } catch (SQLException var21) {
                    this.log.logError("Error closing update statement:" + Const.CR + var21.getMessage());
                    this.log.logError(Const.getStackTracker(var21));
                }

                this.prepStatementUpdate = null;
            }

            if(this.pstmt_seq != null) {
                try {
                    this.pstmt_seq.close();
                } catch (SQLException var20) {
                    this.log.logError("Error closing seq statement:" + Const.CR + var20.getMessage());
                    this.log.logError(Const.getStackTracker(var20));
                }

                this.pstmt_seq = null;
            }

            if(Utils.isEmpty(this.connectionGroup)) {
                if(!this.isAutoCommit()) {
                    try {
                        this.commit();
                    } catch (KettleDatabaseException var19) {
                        this.log.logError("Error committing:" + Const.CR + var19.getMessage());
                        this.log.logError(Const.getStackTracker(var19));
                    }
                }

                try {
                    ExtensionPointHandler.callExtensionPoint(this.log, KettleExtensionPoint.DatabaseDisconnected.id, this);
                } catch (KettleException var17) {
                    this.log.logError("Error disconnecting from database:" + Const.CR + var17.getMessage());
                    this.log.logError(Const.getStackTracker(var17));
                } finally {
                    try {
                        this.closeConnectionOnly();
                    } catch (KettleDatabaseException var16) {
                        this.log.logError("Error disconnecting from database - closeConnectionOnly failed:" + Const.CR + var16.getMessage());
                        this.log.logError(Const.getStackTracker(var16));
                    }

                }

            }
        }
    }

    public synchronized void closeConnectionOnly() throws KettleDatabaseException {
        try {
            if(this.connection != null) {
                this.connection.close();
                if(!this.databaseMeta.isUsingConnectionPool()) {
                    this.connection = null;
                }
            }

            if(this.log.isDetailed()) {
                this.log.logDetailed("Connection to database closed!");
            }

        } catch (SQLException var2) {
            throw new KettleDatabaseException("Error disconnecting from database '" + this.toString() + "'", var2);
        }
    }

    public void cancelQuery() throws KettleDatabaseException {
        if(!this.databaseMeta.isMySQLVariant() || !this.databaseMeta.isStreamingResults() || this.getDatabaseMetaData().getDriverMajorVersion() != 3) {
            this.cancelStatement(this.pstmt);
            this.cancelStatement(this.sel_stmt);
        }
    }

    public void cancelStatement(Statement statement) throws KettleDatabaseException {
        try {
            if(statement != null) {
                statement.cancel();
            }

            if(this.log.isDebug()) {
                this.log.logDebug("Statement canceled!");
            }

        } catch (SQLException var3) {
            throw new KettleDatabaseException("Error cancelling statement", var3);
        }
    }

    public void setCommit(int commsize) {
        this.commitsize = commsize;
        String onOff = this.commitsize <= 0?"on":"off";

        try {
            this.connection.setAutoCommit(this.commitsize <= 0);
            if(this.log.isDetailed()) {
                this.log.logDetailed("Auto commit " + onOff);
            }
        } catch (Exception var4) {
            if(this.log.isDebug()) {
                this.log.logDebug("Can't turn auto commit " + onOff + Const.CR + Const.getStackTracker(var4));
            }
        }

    }

    public void setAutoCommit(boolean useAutoCommit) throws KettleDatabaseException {
        try {
            this.connection.setAutoCommit(useAutoCommit);
        } catch (SQLException var3) {
            if(useAutoCommit) {
                throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToEnableAutoCommit", new String[]{this.toString()}));
            } else {
                throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToDisableAutoCommit", new String[]{this.toString()}));
            }
        }
    }

    public void commit() throws KettleDatabaseException {
        this.commit(false);
    }

    public void commit(boolean force) throws KettleDatabaseException {
        try {
            if(!Utils.isEmpty(this.connectionGroup) && !force) {
                return;
            }

            if(this.getDatabaseMetaData().supportsTransactions()) {
                if(this.log.isDebug()) {
                    this.log.logDebug("Commit on database connection [" + this.toString() + "]");
                }

                this.connection.commit();
                ++this.nrExecutedCommits;
            } else if(this.log.isDetailed()) {
                this.log.logDetailed("No commit possible on database connection [" + this.toString() + "]");
            }
        } catch (Exception var3) {
            if(this.databaseMeta.supportsEmptyTransactions()) {
                throw new KettleDatabaseException("Error comitting connection", var3);
            }
        }

    }

    public void commitLog(LogTableCoreInterface logTable) throws KettleDatabaseException {
        this.commitLog(false, logTable);
    }

    public void commitLog(boolean force, LogTableCoreInterface logTable) throws KettleDatabaseException {
        try {
            this.commitInternal(force);
        } catch (Exception var4) {
            DatabaseLogExceptionFactory.getExceptionStrategy(logTable).registerException(this.log, var4, PKG, "Database.Error.UnableToCommitToLogTable", new String[]{logTable.getActualTableName()});
        }

    }

    /** @deprecated */
    @Deprecated
    private void commitInternal(boolean force) throws KettleDatabaseException, SQLException {
        if(Utils.isEmpty(this.connectionGroup) || force) {
            if(this.getDatabaseMetaData().supportsTransactions()) {
                if(this.log.isDebug()) {
                    this.log.logDebug("Commit on database connection [" + this.toString() + "]");
                }

                this.connection.commit();
                ++this.nrExecutedCommits;
            } else if(this.log.isDetailed()) {
                this.log.logDetailed("No commit possible on database connection [" + this.toString() + "]");
            }

        }
    }

    public void rollback() throws KettleDatabaseException {
        this.rollback(false);
    }

    public void rollback(boolean force) throws KettleDatabaseException {
        try {
            if(Utils.isEmpty(this.connectionGroup) || force) {
                if(this.getDatabaseMetaData().supportsTransactions()) {
                    if(this.connection != null) {
                        if(this.log.isDebug()) {
                            this.log.logDebug("Rollback on database connection [" + this.toString() + "]");
                        }

                        this.connection.rollback();
                    }
                } else if(this.log.isDetailed()) {
                    this.log.logDetailed("No rollback possible on database connection [" + this.toString() + "]");
                }

            }
        } catch (SQLException var3) {
            throw new KettleDatabaseException("Error performing rollback on connection", var3);
        }
    }

    public void prepareInsert(RowMetaInterface rowMeta, String tableName) throws KettleDatabaseException {
        this.prepareInsert(rowMeta, (String)null, tableName);
    }

    public void prepareInsert(RowMetaInterface rowMeta, String schemaName, String tableName) throws KettleDatabaseException {
        if(rowMeta.size() == 0) {
            throw new KettleDatabaseException("No fields in row, can't insert!");
        } else {
            String ins = this.getInsertStatement(schemaName, tableName, rowMeta);
            if(this.log.isDetailed()) {
                this.log.logDetailed("Preparing statement: " + Const.CR + ins);
            }

            this.prepStatementInsert = this.prepareSQL(ins);
        }
    }

    public PreparedStatement prepareSQL(String sql) throws KettleDatabaseException {
        return this.prepareSQL(sql, false);
    }

    public PreparedStatement prepareSQL(String sql, boolean returnKeys) throws KettleDatabaseException {
        DatabaseInterface databaseInterface = this.databaseMeta.getDatabaseInterface();
        boolean supportsAutoGeneratedKeys = databaseInterface.supportsAutoGeneratedKeys();

        try {
            return returnKeys && supportsAutoGeneratedKeys?this.connection.prepareStatement(this.databaseMeta.stripCR(sql), 1):this.connection.prepareStatement(this.databaseMeta.stripCR(sql));
        } catch (SQLException var6) {
            throw new KettleDatabaseException("Couldn't prepare statement:" + Const.CR + sql, var6);
        }
    }

    public void closeLookup() throws KettleDatabaseException {
        this.closePreparedStatement(this.pstmt);
        this.pstmt = null;
    }

    public void closePreparedStatement(PreparedStatement ps) throws KettleDatabaseException {
        if(ps != null) {
            try {
                ps.close();
            } catch (SQLException var3) {
                throw new KettleDatabaseException("Error closing prepared statement", var3);
            }
        }

    }

    public void closeInsert() throws KettleDatabaseException {
        if(this.prepStatementInsert != null) {
            try {
                this.prepStatementInsert.close();
                this.prepStatementInsert = null;
            } catch (SQLException var2) {
                throw new KettleDatabaseException("Error closing insert prepared statement.", var2);
            }
        }

    }

    public void closeUpdate() throws KettleDatabaseException {
        if(this.prepStatementUpdate != null) {
            try {
                this.prepStatementUpdate.close();
                this.prepStatementUpdate = null;
            } catch (SQLException var2) {
                throw new KettleDatabaseException("Error closing update prepared statement.", var2);
            }
        }

    }

    public void setValues(RowMetaInterface rowMeta, Object[] data) throws KettleDatabaseException {
        this.setValues(rowMeta, data, this.pstmt);
    }

    public void setValues(RowMetaAndData row) throws KettleDatabaseException {
        this.setValues(row.getRowMeta(), row.getData());
    }

    public void setValuesInsert(RowMetaInterface rowMeta, Object[] data) throws KettleDatabaseException {
        this.setValues(rowMeta, data, this.prepStatementInsert);
    }

    public void setValuesInsert(RowMetaAndData row) throws KettleDatabaseException {
        this.setValues(row.getRowMeta(), row.getData(), this.prepStatementInsert);
    }

    public void setValuesUpdate(RowMetaInterface rowMeta, Object[] data) throws KettleDatabaseException {
        this.setValues(rowMeta, data, this.prepStatementUpdate);
    }

    public void setValuesLookup(RowMetaInterface rowMeta, Object[] data) throws KettleDatabaseException {
        this.setValues(rowMeta, data, this.prepStatementLookup);
    }

    public void setProcValues(RowMetaInterface rowMeta, Object[] data, int[] argnrs, String[] argdir, boolean result) throws KettleDatabaseException {
        int pos;
        if(result) {
            pos = 2;
        } else {
            pos = 1;
        }

        for(int i = 0; i < argnrs.length; ++i) {
            if(!argdir[i].equalsIgnoreCase("IN") && !argdir[i].equalsIgnoreCase("INOUT")) {
                ++pos;
            } else {
                ValueMetaInterface valueMeta = rowMeta.getValueMeta(argnrs[i]);
                Object value = data[argnrs[i]];
                this.setValue(this.cstmt, valueMeta, value, pos);
                ++pos;
            }
        }

    }

    public void setValue(PreparedStatement ps, ValueMetaInterface v, Object object, int pos) throws KettleDatabaseException {
        v.setPreparedStatementValue(this.databaseMeta, ps, pos, object);
    }

    public void setValues(RowMetaAndData row, PreparedStatement ps) throws KettleDatabaseException {
        this.setValues(row.getRowMeta(), row.getData(), ps);
    }

    public void setValues(RowMetaInterface rowMeta, Object[] data, PreparedStatement ps) throws KettleDatabaseException {
        for(int i = 0; i < rowMeta.size(); ++i) {
            ValueMetaInterface v = rowMeta.getValueMeta(i);
            Object object = data[i];

            try {
                this.setValue(ps, v, object, i + 1);
            } catch (KettleDatabaseException var8) {
                throw new KettleDatabaseException("offending row : " + rowMeta, var8);
            }
        }

    }

    public void setValues(RowMetaInterface rowMeta, Object[] data, PreparedStatement ps, int ignoreThisValueIndex) throws KettleDatabaseException {
        int index = 0;

        for(int i = 0; i < rowMeta.size(); ++i) {
            if(i != ignoreThisValueIndex) {
                ValueMetaInterface v = rowMeta.getValueMeta(i);
                Object object = data[i];

                try {
                    this.setValue(ps, v, object, index + 1);
                    ++index;
                } catch (KettleDatabaseException var10) {
                    throw new KettleDatabaseException("offending row : " + rowMeta, var10);
                }
            }
        }

    }

    public RowMetaAndData getGeneratedKeys(PreparedStatement ps) throws KettleDatabaseException {
        ResultSet keys = null;

        RowMetaAndData var5;
        try {
            keys = ps.getGeneratedKeys();
            ResultSetMetaData resultSetMetaData = keys.getMetaData();
            if(resultSetMetaData == null) {
                resultSetMetaData = ps.getMetaData();
            }

            Object rowMeta;
            if(resultSetMetaData == null) {
                rowMeta = new RowMeta();
                ((RowMetaInterface)rowMeta).addValueMeta(new ValueMetaInteger("ai-key"));
            } else {
                rowMeta = this.getRowInfo(resultSetMetaData, false, false);
            }

            var5 = new RowMetaAndData((RowMetaInterface)rowMeta, this.getRow(keys, resultSetMetaData, (RowMetaInterface)rowMeta));
        } catch (Exception var14) {
            throw new KettleDatabaseException("Unable to retrieve key(s) from auto-increment field(s)", var14);
        } finally {
            if(keys != null) {
                try {
                    keys.close();
                } catch (SQLException var13) {
                    throw new KettleDatabaseException("Unable to close resultset of auto-generated keys", var13);
                }
            }

        }

        return var5;
    }

    public Long getNextSequenceValue(String sequenceName, String keyfield) throws KettleDatabaseException {
        return this.getNextSequenceValue((String)null, sequenceName, keyfield);
    }

    public Long getNextSequenceValue(String schemaName, String sequenceName, String keyfield) throws KettleDatabaseException {
        Long retval = null;
        String schemaSequence = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, sequenceName);

        try {
            if(this.pstmt_seq == null) {
                this.pstmt_seq = this.connection.prepareStatement(this.databaseMeta.getSeqNextvalSQL(this.databaseMeta.stripCR(schemaSequence)));
            }

            ResultSet rs = null;

            try {
                rs = this.pstmt_seq.executeQuery();
                if(rs.next()) {
                    retval = Long.valueOf(rs.getLong(1));
                }
            } finally {
                if(rs != null) {
                    rs.close();
                }

            }

            return retval;
        } catch (SQLException var11) {
            throw new KettleDatabaseException("Unable to get next value for sequence : " + schemaSequence, var11);
        }
    }

    public void insertRow(String tableName, RowMetaInterface fields, Object[] data) throws KettleDatabaseException {
        this.insertRow((String)null, tableName, fields, data);
    }

    public void insertRow(String schemaName, String tableName, RowMetaInterface fields, Object[] data) throws KettleDatabaseException {
        this.prepareInsert(fields, schemaName, tableName);
        this.setValuesInsert(fields, data);
        this.insertRow();
        this.closeInsert();
    }

    public String getInsertStatement(String tableName, RowMetaInterface fields) {
        return this.getInsertStatement((String)null, tableName, fields);
    }

    public String getInsertStatement(String schemaName, String tableName, RowMetaInterface fields) {
        StringBuilder ins = new StringBuilder(128);
        String schemaTable = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
        ins.append("INSERT INTO ").append(schemaTable).append(" (");

        int i;
        for(i = 0; i < fields.size(); ++i) {
            if(i > 0) {
                ins.append(", ");
            }

            String name = fields.getValueMeta(i).getName();
            ins.append(this.databaseMeta.quoteField(name));
        }

        ins.append(") VALUES (");

        for(i = 0; i < fields.size(); ++i) {
            if(i > 0) {
                ins.append(", ");
            }

            ins.append(" ?");
        }

        ins.append(')');
        return ins.toString();
    }

    public void insertRow() throws KettleDatabaseException {
        this.insertRow(this.prepStatementInsert);
    }

    public void insertRow(boolean batch) throws KettleDatabaseException {
        this.insertRow(this.prepStatementInsert, batch);
    }

    public void updateRow() throws KettleDatabaseException {
        this.insertRow(this.prepStatementUpdate);
    }

    public void insertRow(PreparedStatement ps) throws KettleDatabaseException {
        this.insertRow(ps, false);
    }

    public boolean insertRow(PreparedStatement ps, boolean batch) throws KettleDatabaseException {
        return this.insertRow(ps, batch, true);
    }

    public boolean getUseBatchInsert(boolean batch) throws KettleDatabaseException {
        try {
            return batch && this.getDatabaseMetaData().supportsBatchUpdates() && this.databaseMeta.supportsBatchUpdates() && Utils.isEmpty(this.connectionGroup);
        } catch (SQLException var3) {
            throw createKettleDatabaseBatchException("Error determining whether to use batch", var3);
        }
    }

    public boolean insertRow(PreparedStatement ps, boolean batch, boolean handleCommit) throws KettleDatabaseException {
        String debug = "insertRow start";
        boolean rowsAreSafe = false;
        boolean isBatchUpdate = false;

        try {
            boolean useBatchInsert = this.getUseBatchInsert(batch);
            if(!this.isAutoCommit()) {
                if(useBatchInsert) {
                    debug = "insertRow add batch";
                    ps.addBatch();
                } else {
                    debug = "insertRow exec update";
                    ps.executeUpdate();
                }
            } else {
                ps.executeUpdate();
            }

            ++this.written;
            if(handleCommit && !this.isAutoCommit() && this.written % this.commitsize == 0) {
                if(useBatchInsert) {
                    isBatchUpdate = true;
                    debug = "insertRow executeBatch commit";
                    ps.executeBatch();
                    this.commit();
                    ps.clearBatch();
                } else {
                    debug = "insertRow normal commit";
                    this.commit();
                }

                this.written = 0;
                rowsAreSafe = true;
            }

            return rowsAreSafe;
        } catch (BatchUpdateException var8) {
            throw createKettleDatabaseBatchException("Error updating batch", var8);
        } catch (SQLException var9) {
            if(isBatchUpdate) {
                throw createKettleDatabaseBatchException("Error updating batch", var9);
            } else {
                throw new KettleDatabaseException("Error inserting/updating row", var9);
            }
        } catch (Exception var10) {
            throw new KettleDatabaseException("Unexpected error inserting/updating row in part [" + debug + "]", var10);
        }
    }

    /** @deprecated */
    @Deprecated
    public void clearInsertBatch() throws KettleDatabaseException {
        this.clearBatch(this.prepStatementInsert);
    }

    public void clearBatch(PreparedStatement preparedStatement) throws KettleDatabaseException {
        try {
            preparedStatement.clearBatch();
        } catch (SQLException var3) {
            throw new KettleDatabaseException("Unable to clear batch for prepared statement", var3);
        }
    }

    public void executeAndClearBatch(PreparedStatement preparedStatement) throws KettleDatabaseException {
        try {
            if(this.written > 0 && this.getDatabaseMetaData().supportsBatchUpdates()) {
                preparedStatement.executeBatch();
            }

            this.written = 0;
            preparedStatement.clearBatch();
        } catch (SQLException var3) {
            throw new KettleDatabaseException("Unable to clear batch for prepared statement", var3);
        }
    }

    public void insertFinished(boolean batch) throws KettleDatabaseException {
        this.insertFinished(this.prepStatementInsert, batch);
        this.prepStatementInsert = null;
    }

    public void emptyAndCommit(PreparedStatement ps, boolean batch) throws KettleDatabaseException {
        this.emptyAndCommit(ps, batch, this.written);
    }

    public void emptyAndCommit(PreparedStatement ps, boolean batch, int batchCounter) throws KettleDatabaseException {
        boolean isBatchUpdate = false;

        try {
            if(ps != null) {
                if(!this.isAutoCommit()) {
                    if(batch && this.getDatabaseMetaData().supportsBatchUpdates() && batchCounter > 0) {
                        isBatchUpdate = true;
                        ps.executeBatch();
                        this.commit();
                        ps.clearBatch();
                    } else {
                        this.commit();
                    }
                }

                ps.close();
            }

        } catch (BatchUpdateException var6) {
            throw createKettleDatabaseBatchException("Error updating batch", var6);
        } catch (SQLException var7) {
            if(isBatchUpdate) {
                throw createKettleDatabaseBatchException("Error updating batch", var7);
            } else {
                throw new KettleDatabaseException("Unable to empty ps and commit connection.", var7);
            }
        }
    }

    public static KettleDatabaseBatchException createKettleDatabaseBatchException(String message, SQLException ex) {
        KettleDatabaseBatchException kdbe = new KettleDatabaseBatchException(message, ex);
        if(ex instanceof BatchUpdateException) {
            kdbe.setUpdateCounts(((BatchUpdateException)ex).getUpdateCounts());
        } else {
            kdbe.setUpdateCounts((int[])null);
        }

        List<Exception> exceptions = new ArrayList();
        SQLException nextException = ex.getNextException();

        for(SQLException oldException = null; nextException != null && oldException != nextException; nextException = nextException.getNextException()) {
            exceptions.add(nextException);
            oldException = nextException;
        }

        kdbe.setExceptionsList(exceptions);
        return kdbe;
    }

    /** @deprecated */
    @Deprecated
    public void insertFinished(PreparedStatement ps, boolean batch) throws KettleDatabaseException {
        boolean isBatchUpdate = false;

        try {
            if(ps != null) {
                if(!this.isAutoCommit()) {
                    if(batch && this.getDatabaseMetaData().supportsBatchUpdates()) {
                        isBatchUpdate = true;
                        ps.executeBatch();
                        this.commit();
                    } else {
                        this.commit();
                    }
                }

                ps.close();
            }

        } catch (BatchUpdateException var5) {
            throw createKettleDatabaseBatchException("Error updating batch", var5);
        } catch (SQLException var6) {
            if(isBatchUpdate) {
                throw createKettleDatabaseBatchException("Error updating batch", var6);
            } else {
                throw new KettleDatabaseException("Unable to commit connection after having inserted rows.", var6);
            }
        }
    }

    public Result execStatement(String sql) throws KettleDatabaseException {
        return this.execStatement(sql, (RowMetaInterface)null, (Object[])null);
    }

    public Result execStatement(String rawsql, RowMetaInterface params, Object[] data) throws KettleDatabaseException {
        Result result = new Result();
        String sql = this.databaseMeta.getDatabaseInterface().createSqlScriptParser().removeComments(rawsql).trim();

        try {
            boolean resultSet;
            int count;
            String upperSql;
            if(params != null) {
                PreparedStatement prep_stmt = this.connection.prepareStatement(this.databaseMeta.stripCR(sql));
                this.setValues(params, data, prep_stmt);
                resultSet = prep_stmt.execute();
                count = prep_stmt.getUpdateCount();
                prep_stmt.close();
            } else {
                upperSql = this.databaseMeta.stripCR(sql);
                Statement stmt = this.connection.createStatement();
                resultSet = stmt.execute(upperSql);
                count = stmt.getUpdateCount();
                stmt.close();
            }

            upperSql = sql.toUpperCase();
            if(!resultSet && count > 0) {
                if(upperSql.startsWith("INSERT")) {
                    result.setNrLinesOutput((long)count);
                } else if(upperSql.startsWith("UPDATE")) {
                    result.setNrLinesUpdated((long)count);
                } else if(upperSql.startsWith("DELETE")) {
                    result.setNrLinesDeleted((long)count);
                }
            }

            if(upperSql.startsWith("ALTER TABLE") || upperSql.startsWith("DROP TABLE") || upperSql.startsWith("CREATE TABLE")) {
                DBCache.getInstance().clear(this.databaseMeta.getName());
            }

            return result;
        } catch (SQLException var10) {
            throw new KettleDatabaseException("Couldn't execute SQL: " + sql + Const.CR, var10);
        } catch (Exception var11) {
            throw new KettleDatabaseException("Unexpected error executing SQL: " + Const.CR, var11);
        }
    }

    public Result execStatements(String script) throws KettleDatabaseException {
        return this.execStatements(script, (RowMetaInterface)null, (Object[])null);
    }

    public Result execStatements(String script, RowMetaInterface params, Object[] data) throws KettleDatabaseException {
        Result result = new Result();
        SqlScriptParser sqlScriptParser = this.databaseMeta.getDatabaseInterface().createSqlScriptParser();
        List<String> statements = sqlScriptParser.split(script);
        int nrstats = 0;
        if(statements != null) {
            Iterator var8 = statements.iterator();

            label186:
            while(true) {
                while(true) {
                    String stat;
                    do {
                        if(!var8.hasNext()) {
                            break label186;
                        }

                        stat = (String)var8.next();
                        stat = sqlScriptParser.removeComments(stat);
                    } while(Const.onlySpaces(stat));

                    String sql = Const.trim(stat);
                    if(sql.toUpperCase().startsWith("SELECT")) {
                        if(this.log.isDetailed()) {
                            this.log.logDetailed("launch SELECT statement: " + Const.CR + sql);
                        }

                        ++nrstats;
                        ResultSet rs = null;

                        try {
                            rs = this.openQuery(sql, params, data);
                            if(rs != null) {
                                for(Object[] row = this.getRow(rs); row != null; row = this.getRow(rs)) {
                                    result.setNrLinesRead(result.getNrLinesRead() + 1L);
                                    if(this.log.isDetailed()) {
                                        this.log.logDetailed(this.rowMeta.getString(row));
                                    }
                                }
                            } else if(this.log.isDebug()) {
                                this.log.logDebug("Error executing query: " + Const.CR + sql);
                            }
                        } catch (KettleValueException var20) {
                            throw new KettleDatabaseException(var20);
                        } finally {
                            try {
                                if(rs != null) {
                                    rs.close();
                                }
                            } catch (SQLException var19) {
                                if(this.log.isDebug()) {
                                    this.log.logDebug("Error closing query: " + Const.CR + sql);
                                }
                            }

                        }
                    } else {
                        if(this.log.isDetailed()) {
                            this.log.logDetailed("launch DDL statement: " + Const.CR + sql);
                        }

                        ++nrstats;
                        Result res = this.execStatement(sql, params, data);
                        result.add(res);
                    }
                }
            }
        }

        if(this.log.isDetailed()) {
            this.log.logDetailed(nrstats + " statement" + (nrstats == 1?"":"s") + " executed");
        }

        return result;
    }

    public ResultSet openQuery(String sql) throws KettleDatabaseException {
        return this.openQuery((String)sql, (RowMetaInterface)null, (Object[])null);
    }

    public ResultSet openQuery(String sql, RowMetaInterface params, Object[] data) throws KettleDatabaseException {
        return this.openQuery(sql, params, data, 1000);
    }

    public ResultSet openQuery(String sql, RowMetaInterface params, Object[] data, int fetch_mode) throws KettleDatabaseException {
        return this.openQuery(sql, params, data, fetch_mode, false);
    }

    public ResultSet openQuery(String sql, RowMetaInterface params, Object[] data, int fetch_mode, boolean lazyConversion) throws KettleDatabaseException {
        ResultSet res;
        try {
            this.log.snap(Metrics.METRIC_DATABASE_OPEN_QUERY_START, this.databaseMeta.getName(), new long[0]);
            int fs;
            if(params != null) {
                this.log.snap(Metrics.METRIC_DATABASE_PREPARE_SQL_START, this.databaseMeta.getName(), new long[0]);
                this.pstmt = this.connection.prepareStatement(this.databaseMeta.stripCR(sql), 1003, 1007);
                this.log.snap(Metrics.METRIC_DATABASE_PREPARE_SQL_STOP, this.databaseMeta.getName(), new long[0]);
                this.log.snap(Metrics.METRIC_DATABASE_SQL_VALUES_START, this.databaseMeta.getName(), new long[0]);
                this.setValues(params, data);
                this.log.snap(Metrics.METRIC_DATABASE_SQL_VALUES_STOP, this.databaseMeta.getName(), new long[0]);
                if(this.canWeSetFetchSize(this.pstmt)) {
                    fs = this.pstmt.getMaxRows();
                     fs = 10000 <= fs?fs:10000;
                    if(this.databaseMeta.isMySQLVariant()) {
                        this.setMysqlFetchSize(this.pstmt, fs, fs);
                    } else {
                        this.pstmt.setFetchSize(fs);
                    }

                    this.pstmt.setFetchDirection(fetch_mode);
                }

                if(this.rowlimit > 0 && this.databaseMeta.supportsSetMaxRows()) {
                    this.pstmt.setMaxRows(this.rowlimit);
                }

                this.log.snap(Metrics.METRIC_DATABASE_EXECUTE_SQL_START, this.databaseMeta.getName(), new long[0]);
                res = this.pstmt.executeQuery();
                this.log.snap(Metrics.METRIC_DATABASE_EXECUTE_SQL_STOP, this.databaseMeta.getName(), new long[0]);
            } else {
                this.log.snap(Metrics.METRIC_DATABASE_CREATE_SQL_START, this.databaseMeta.getName(), new long[0]);
                this.sel_stmt = this.connection.createStatement();
                this.log.snap(Metrics.METRIC_DATABASE_CREATE_SQL_STOP, this.databaseMeta.getName(), new long[0]);
                if(this.canWeSetFetchSize(this.sel_stmt)) {
                    fs = 10000 <= this.sel_stmt.getMaxRows()?this.sel_stmt.getMaxRows():10000;
                    if(this.databaseMeta.getDatabaseInterface().isMySQLVariant() && this.databaseMeta.isStreamingResults()) {
                        this.sel_stmt.setFetchSize(-2147483648);
                    } else {
                        this.sel_stmt.setFetchSize(fs);
                    }

                    this.sel_stmt.setFetchDirection(fetch_mode);
                }

                if(this.rowlimit > 0 && this.databaseMeta.supportsSetMaxRows()) {
                    this.sel_stmt.setMaxRows(this.rowlimit);
                }

                this.log.snap(Metrics.METRIC_DATABASE_EXECUTE_SQL_START, this.databaseMeta.getName(), new long[0]);
                res = this.sel_stmt.executeQuery(this.databaseMeta.stripCR(sql));
                this.log.snap(Metrics.METRIC_DATABASE_EXECUTE_SQL_STOP, this.databaseMeta.getName(), new long[0]);
            }

            this.rowMeta = this.getRowInfo(res.getMetaData(), this.databaseMeta.isMySQLVariant(), lazyConversion);
        } catch (SQLException var13) {
            throw new KettleDatabaseException("An error occurred executing SQL: " + Const.CR + sql, var13);
        } catch (Exception var14) {
            throw new KettleDatabaseException("An error occurred executing SQL:" + Const.CR + sql, var14);
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_OPEN_QUERY_STOP, this.databaseMeta.getName(), new long[0]);
        }

        return res;
    }

    private boolean canWeSetFetchSize(Statement statement) throws SQLException {
        return this.databaseMeta.isFetchSizeSupported() && (statement.getMaxRows() > 0 || this.databaseMeta.getDatabaseInterface() instanceof PostgreSQLDatabaseMeta || this.databaseMeta.isMySQLVariant() && this.databaseMeta.isStreamingResults());
    }

    public ResultSet openQuery(PreparedStatement ps, RowMetaInterface params, Object[] data) throws KettleDatabaseException {
        ResultSet res;
        try {
            this.log.snap(Metrics.METRIC_DATABASE_OPEN_QUERY_START, this.databaseMeta.getName(), new long[0]);
            this.log.snap(Metrics.METRIC_DATABASE_SQL_VALUES_START, this.databaseMeta.getName(), new long[0]);
            this.setValues(params, data, ps);
            this.log.snap(Metrics.METRIC_DATABASE_SQL_VALUES_STOP, this.databaseMeta.getName(), new long[0]);
            if(this.canWeSetFetchSize(ps)) {
                int maxRows = ps.getMaxRows();
                int fs = 10000 <= maxRows?maxRows:10000;
                if(this.databaseMeta.isMySQLVariant()) {
                    this.setMysqlFetchSize(ps, fs, maxRows);
                } else {
                    ps.setFetchSize(fs);
                }

                ps.setFetchDirection(1000);
            }

            if(this.rowlimit > 0 && this.databaseMeta.supportsSetMaxRows()) {
                ps.setMaxRows(this.rowlimit);
            }

            this.log.snap(Metrics.METRIC_DATABASE_EXECUTE_SQL_START, this.databaseMeta.getName(), new long[0]);
            res = ps.executeQuery();
            this.log.snap(Metrics.METRIC_DATABASE_EXECUTE_SQL_STOP, this.databaseMeta.getName(), new long[0]);
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_META_START, this.databaseMeta.getName(), new long[0]);
            this.rowMeta = this.getRowInfo(res.getMetaData(), this.databaseMeta.isMySQLVariant(), false);
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_META_STOP, this.databaseMeta.getName(), new long[0]);
        } catch (SQLException var11) {
            throw new KettleDatabaseException("ERROR executing query", var11);
        } catch (Exception var12) {
            throw new KettleDatabaseException("ERROR executing query", var12);
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_OPEN_QUERY_STOP, this.databaseMeta.getName(), new long[0]);
        }

        return res;
    }

    void setMysqlFetchSize(PreparedStatement ps, int fs, int getMaxRows) throws SQLException, KettleDatabaseException {
        if(this.databaseMeta.isStreamingResults() && this.getDatabaseMetaData().getDriverMajorVersion() == 3) {
            ps.setFetchSize(-2147483648);
        } else if(fs <= getMaxRows) {
            ps.setFetchSize(fs);
        }

    }

    public RowMetaInterface getTableFields(String tablename) throws KettleDatabaseException {
        return this.getQueryFields(this.databaseMeta.getSQLQueryFields(tablename), false);
    }

    public RowMetaInterface getQueryFields(String sql, boolean param) throws KettleDatabaseException {
        return this.getQueryFields(sql, param, (RowMetaInterface)null, (Object[])null);
    }

    /** @deprecated */
    public boolean checkTableExists(String tablename) throws KettleDatabaseException {
        try {
            if(this.log.isDebug()) {
                this.log.logDebug("Checking if table [" + tablename + "] exists!");
            }

            String sql = this.databaseMeta.getSQLTableExists(tablename);

            try {
                this.getOneRow(sql);
                return true;
            } catch (KettleDatabaseException var4) {
                return false;
            }
        } catch (Exception var5) {
            throw new KettleDatabaseException("Unable to check if table [" + tablename + "] exists on connection [" + this.databaseMeta.getName() + "]", var5);
        }
    }

    public boolean checkTableExists(String schema, String tablename) throws KettleDatabaseException {
        try {
            boolean exists = this.checkTableExistsByDbMeta(schema, tablename);
            return exists;
        } catch (KettleDatabaseException var4) {
            if(this.log.isDebug()) {
                this.log.logDebug("Failed to load metadata for " + schema + "." + tablename);
            }

            return this.checkTableExists(this.databaseMeta.getQuotedSchemaTableCombination(schema, tablename));
        }
    }

    /** @deprecated */
    public boolean checkTableExistsByDbMeta(String schema, String tablename) throws KettleDatabaseException {
        boolean isTableExist = false;
        if(this.log.isDebug()) {
            this.log.logDebug(BaseMessages.getString(PKG, "Database.Info.CheckingIfTableExistsInDbMetaData", new String[]{tablename}));
        }

        try {
            ResultSet resTables = this.getTableMetaData(schema, tablename);
            Throwable var5 = null;

            try {
                while(resTables.next()) {
                    String resTableName = resTables.getString("TABLE_NAME");
                    if(tablename.equalsIgnoreCase(resTableName)) {
                        if(this.log.isDebug()) {
                            this.log.logDebug(BaseMessages.getString(PKG, "Database.Info.TableFound", new String[]{tablename}));
                        }

                        isTableExist = true;
                        break;
                    }
                }
            } catch (Throwable var15) {
                var5 = var15;
                throw var15;
            } finally {
                if(resTables != null) {
                    if(var5 != null) {
                        try {
                            resTables.close();
                        } catch (Throwable var14) {
                            var5.addSuppressed(var14);
                        }
                    } else {
                        resTables.close();
                    }
                }

            }

            return isTableExist;
        } catch (SQLException var17) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToCheckExistingTable", new String[]{tablename, this.databaseMeta.getName()}), var17);
        }
    }

    private ResultSet getTableMetaData(String schema, String table) throws KettleDatabaseException {
        ResultSet tables = null;
        if(this.getDatabaseMetaData() == null) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToGetDbMeta", new String[0]));
        } else {
            try {
                tables = this.getDatabaseMetaData().getTables((String)null, schema, table, TABLE_TYPES_TO_GET);
            } catch (SQLException var5) {
                throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToGetTableNames", new String[0]), var5);
            }

            if(tables == null) {
                throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToGetTableNames", new String[0]));
            } else {
                return tables;
            }
        }
    }

    private ResultSet getColumnsMetaData(String schema, String table) throws KettleDatabaseException {
        ResultSet columns = null;
        if(this.getDatabaseMetaData() == null) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToGetDbMeta", new String[0]));
        } else {
            try {
                columns = this.getDatabaseMetaData().getColumns((String)null, schema, table, (String)null);
            } catch (SQLException var5) {
                throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToGetTableNames", new String[0]), var5);
            }

            if(columns == null) {
                throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Error.UnableToGetTableNames", new String[0]));
            } else {
                return columns;
            }
        }
    }

    public boolean checkColumnExists(String schemaname, String tablename, String columnname) throws KettleDatabaseException {
        if(this.log.isDebug()) {
            this.log.logDebug("Checking if column [" + columnname + "] exists in table [" + tablename + "] !");
        }

        try {
            ResultSet columns = this.getColumnsMetaData(schemaname, tablename);

            do {
                if(!columns.next()) {
                    return false;
                }
            } while(!columnname.equals(columns.getString("COLUMN_NAME")));

            return true;
        } catch (SQLException | KettleDatabaseException var5) {
            if(this.log.isDebug()) {
                this.log.logDebug("Metadata check failed. Fallback to statement check.");
            }

            return this.checkColumnExists(this.databaseMeta.quoteField(columnname), this.databaseMeta.getQuotedSchemaTableCombination(schemaname, tablename));
        }
    }

    /** @deprecated */
    public boolean checkColumnExists(String columnname, String tablename) throws KettleDatabaseException {
        try {
            if(this.log.isDebug()) {
                this.log.logDebug("Checking if column [" + columnname + "] exists in table [" + tablename + "] !");
            }

            String sql = this.databaseMeta.getSQLColumnExists(columnname, tablename);

            try {
                this.getOneRow(sql);
                return true;
            } catch (KettleDatabaseException var5) {
                return false;
            }
        } catch (Exception var6) {
            throw new KettleDatabaseException("Unable to check if column [" + columnname + "] exists in table [" + tablename + "] on connection [" + this.databaseMeta.getName() + "]", var6);
        }
    }

    public boolean checkSequenceExists(String sequenceName) throws KettleDatabaseException {
        return this.checkSequenceExists((String)null, sequenceName);
    }

    public boolean checkSequenceExists(String schemaName, String sequenceName) throws KettleDatabaseException {
        boolean retval = false;
        if(!this.databaseMeta.supportsSequences()) {
            return retval;
        } else {
            String schemaSequence = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, sequenceName);

            try {
                String sql = this.databaseMeta.getSQLSequenceExists(schemaSequence);
                ResultSet res = this.openQuery(sql);
                if(res != null) {
                    Object[] row = this.getRow(res);
                    if(row != null) {
                        retval = true;
                    }

                    this.closeQuery(res);
                }

                return retval;
            } catch (Exception var8) {
                throw new KettleDatabaseException("Unexpected error checking whether or not sequence [" + schemaSequence + "] exists", var8);
            }
        }
    }

    public boolean checkIndexExists(String tableName, String[] idx_fields) throws KettleDatabaseException {
        return this.checkIndexExists((String)null, tableName, idx_fields);
    }

    public boolean checkIndexExists(String schemaName, String tableName, String[] idx_fields) throws KettleDatabaseException {
        String tablename = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
        if(!this.checkTableExists(tablename)) {
            return false;
        } else {
            if(this.log.isDebug()) {
                this.log.logDebug("CheckIndexExists() tablename = " + tablename + " type = " + this.databaseMeta.getPluginId());
            }

            return this.databaseMeta.getDatabaseInterface().checkIndexExists(this, schemaName, tableName, idx_fields);
        }
    }

    public String getCreateIndexStatement(String tablename, String indexname, String[] idx_fields, boolean tk, boolean unique, boolean bitmap, boolean semi_colon) {
        return this.getCreateIndexStatement((String)null, tablename, indexname, idx_fields, tk, unique, bitmap, semi_colon);
    }

    public String getCreateIndexStatement(String schemaname, String tablename, String indexname, String[] idx_fields, boolean tk, boolean unique, boolean bitmap, boolean semi_colon) {
        String cr_index = "";
        DatabaseInterface databaseInterface = this.databaseMeta.getDatabaseInterface();
        if(databaseInterface instanceof Exasol4DatabaseMeta) {
            return "";
        } else {
            cr_index = cr_index + "CREATE ";
            if(unique || tk && databaseInterface instanceof SybaseDatabaseMeta) {
                cr_index = cr_index + "UNIQUE ";
            }

            if(bitmap && this.databaseMeta.supportsBitmapIndex()) {
                cr_index = cr_index + "BITMAP ";
            }

            cr_index = cr_index + "INDEX " + this.databaseMeta.quoteField(indexname) + " ";
            cr_index = cr_index + "ON ";
            cr_index = cr_index + tablename;
            cr_index = cr_index + "(";

            for(int i = 0; i < idx_fields.length; ++i) {
                if(i > 0) {
                    cr_index = cr_index + ", ";
                }

                cr_index = cr_index + this.databaseMeta.quoteField(idx_fields[i]);
            }

            cr_index = cr_index + ")" + Const.CR;
            cr_index = cr_index + databaseInterface.getIndexTablespaceDDL(this.variables, this.databaseMeta);
            if(semi_colon) {
                cr_index = cr_index + ";" + Const.CR;
            }

            return cr_index;
        }
    }

    public String getCreateSequenceStatement(String sequence, long start_at, long increment_by, long max_value, boolean semi_colon) {
        return this.getCreateSequenceStatement((String)null, sequence, Long.toString(start_at), Long.toString(increment_by), Long.toString(max_value), semi_colon);
    }

    public String getCreateSequenceStatement(String sequence, String start_at, String increment_by, String max_value, boolean semi_colon) {
        return this.getCreateSequenceStatement((String)null, sequence, start_at, increment_by, max_value, semi_colon);
    }

    public String getCreateSequenceStatement(String schemaName, String sequence, long start_at, long increment_by, long max_value, boolean semi_colon) {
        return this.getCreateSequenceStatement(schemaName, sequence, Long.toString(start_at), Long.toString(increment_by), Long.toString(max_value), semi_colon);
    }

    public String getCreateSequenceStatement(String schemaName, String sequenceName, String start_at, String increment_by, String max_value, boolean semi_colon) {
        String cr_seq = "";
        if(Utils.isEmpty(sequenceName)) {
            return cr_seq;
        } else {
            if(this.databaseMeta.supportsSequences()) {
                String schemaSequence = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, sequenceName);
                cr_seq = cr_seq + "CREATE SEQUENCE " + schemaSequence + " " + Const.CR;
                cr_seq = cr_seq + "START WITH " + start_at + " " + Const.CR;
                cr_seq = cr_seq + "INCREMENT BY " + increment_by + " " + Const.CR;
                if(max_value != null) {
                    if(this.databaseMeta.supportsSequenceNoMaxValueOption() && max_value.trim().equals("-1")) {
                        DatabaseInterface databaseInterface = this.databaseMeta.getDatabaseInterface();
                        cr_seq = cr_seq + databaseInterface.getSequenceNoMaxValueOption() + Const.CR;
                    } else {
                        cr_seq = cr_seq + "MAXVALUE " + max_value + Const.CR;
                    }
                }

                if(semi_colon) {
                    cr_seq = cr_seq + ";" + Const.CR;
                }
            }

            return cr_seq;
        }
    }

    public RowMetaInterface getTableFieldsMeta(String schemaName, String tableName) throws KettleDatabaseException {
        try {
            if("".equals(schemaName)) {
                schemaName = null;
            }

            if("".equals(tableName)) {
                tableName = null;
            }

            RowMetaInterface fields = null;
            DBCache dbcache = DBCache.getInstance();
            DBCacheEntry entry = null;
            if(dbcache != null) {
                entry = new DBCacheEntry(this.databaseMeta.getName(), "LIGHTWEIGHT_SALT".concat(schemaName == null?"nullSchema":schemaName).concat(tableName == null?"nullTable":tableName));
                fields = dbcache.get(entry);
                if(fields != null) {
                    return (RowMetaInterface)fields;
                }
            }

            if(this.connection == null) {
                return null;
            } else {
                ValueMetaInterface valueMeta;
                for(ResultSet rm = this.connection.getMetaData().getColumns((String)null, schemaName, tableName, (String)null); rm.next(); ((RowMetaInterface)fields).addValueMeta(valueMeta)) {
                    valueMeta = null;
                    Iterator var8 = valueMetaPluginClasses.iterator();

                    while(var8.hasNext()) {
                        ValueMetaInterface valueMetaClass = (ValueMetaInterface)var8.next();

                        try {
                            ValueMetaInterface v = valueMetaClass.getMetadataPreview(this.databaseMeta, rm);
                            if(v != null) {
                                valueMeta = v;
                                break;
                            }
                        } catch (KettleDatabaseException var11) {
                            if(this.log.isDebug()) {
                                this.log.logDebug("Skipping ValueMetaInterface:" + valueMetaClass.getClass().getName(), new Object[]{var11});
                            }
                        }
                    }

                    if(fields == null) {
                        fields = new RowMeta();
                    }
                }

                if(dbcache != null && entry != null && fields != null) {
                    dbcache.put(entry, (RowMetaInterface)fields);
                }

                return (RowMetaInterface)fields;
            }
        } catch (Exception var12) {
            if(this.log.isDebug()) {
                this.log.logDebug("Failed to fetch fields from jdbc meta ", new Object[]{var12});
            }

            return this.getQueryFields(this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName), false);
        }
    }

    public RowMetaInterface getQueryFields(String sql, boolean param, RowMetaInterface inform, Object[] data) throws KettleDatabaseException {
        DBCache dbcache = DBCache.getInstance();
        DBCacheEntry entry = null;
        RowMetaInterface fields;
        if(dbcache != null) {
            entry = new DBCacheEntry(this.databaseMeta.getName(), sql);
            fields = dbcache.get(entry);
            if(fields != null) {
                return fields;
            }
        }

        if(this.connection == null) {
            return null;
        } else {
            try {
                if(this.databaseMeta.supportsPreparedStatementMetadataRetrieval()) {
                    fields = this.getQueryFieldsFromPreparedStatement(sql);
                } else {
                    fields = this.getQueryFieldsFromDatabaseMetaData();
                }
            } catch (Exception var9) {
                fields = this.getQueryFieldsFallback(sql, param, inform, data);
            }

            if(dbcache != null && entry != null && fields != null) {
                dbcache.put(entry, fields);
            }

            return fields;
        }
    }

    public RowMetaInterface getQueryFieldsFromPreparedStatement(String sql) throws Exception {
        PreparedStatement preparedStatement = null;

        RowMetaInterface var4;
        try {
            preparedStatement = this.connection.prepareStatement(this.databaseMeta.stripCR(sql), 1003, 1007);
            preparedStatement.setMaxRows(1);
            ResultSetMetaData rsmd = preparedStatement.getMetaData();
            var4 = this.getRowInfo(rsmd, false, false);
        } catch (Exception var13) {
            throw new Exception(var13);
        } finally {
            if(preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException var12) {
                    throw new KettleDatabaseException("Unable to close prepared statement after determining SQL layout", var12);
                }
            }

        }

        return var4;
    }

    public RowMetaInterface getQueryFieldsFromDatabaseMetaData() throws Exception {
        ResultSet columns = this.connection.getMetaData().getColumns("", "", this.databaseMeta.getName(), "");
        RowMeta rowMeta = new RowMeta();

        while(columns.next()) {
            ValueMetaInterface valueMeta = null;
            String name = columns.getString("COLUMN_NAME");
            String type = columns.getString("SOURCE_DATA_TYPE");
            int size = columns.getInt("COLUMN_SIZE");
            if(!type.equals("Integer") && !type.equals("Long")) {
                if(!type.equals("BigDecimal") && !type.equals("BigNumber")) {
                    if(!type.equals("Double") && !type.equals("Number")) {
                        if(type.equals("String")) {
                            valueMeta = new ValueMetaString();
                        } else if(type.equals("Date")) {
                            valueMeta = new ValueMetaDate();
                        } else if(type.equals("Boolean")) {
                            valueMeta = new ValueMetaBoolean();
                        } else if(type.equals("Binary")) {
                            valueMeta = new ValueMetaBinary();
                        } else if(type.equals("Timestamp")) {
                            valueMeta = new ValueMetaTimestamp();
                        } else if(type.equals("Internet Address")) {
                            valueMeta = new ValueMetaInternetAddress();
                        }
                    } else {
                        valueMeta = new ValueMetaNumber();
                    }
                } else {
                    valueMeta = new ValueMetaBigNumber();
                }
            } else {
                valueMeta = new ValueMetaInteger();
            }

            if(valueMeta == null) {
                this.log.logBasic("Database.getQueryFields() ValueMetaInterface mapping not resolved for the column " + name);
                rowMeta = null;
                break;
            }

            ((ValueMetaInterface)valueMeta).setName(name);
            ((ValueMetaInterface)valueMeta).setComments(name);
            ((ValueMetaInterface)valueMeta).setLength(size);
            ((ValueMetaInterface)valueMeta).setOriginalColumnTypeName(type);
            ((ValueMetaInterface)valueMeta).setConversionMask(columns.getString("SOURCE_MASK"));
            ((ValueMetaInterface)valueMeta).setDecimalSymbol(columns.getString("SOURCE_DECIMAL_SYMBOL"));
            ((ValueMetaInterface)valueMeta).setGroupingSymbol(columns.getString("SOURCE_GROUPING_SYMBOL"));
            ((ValueMetaInterface)valueMeta).setCurrencySymbol(columns.getString("SOURCE_CURRENCY_SYMBOL"));
            rowMeta.addValueMeta((ValueMetaInterface)valueMeta);
        }

        if(rowMeta != null && !rowMeta.isEmpty()) {
            return rowMeta;
        } else {
            throw new Exception("Error in Database.getQueryFields()");
        }
    }

    public RowMetaInterface getQueryFieldsFallback(String sql, boolean param, RowMetaInterface inform, Object[] data) throws KettleDatabaseException {
        try {
            RowMetaInterface fields;
            if((inform != null || !(this.databaseMeta.getDatabaseInterface() instanceof MSSQLServerDatabaseMeta)) && !this.databaseMeta.getDatabaseInterface().supportsResultSetMetadataRetrievalOnly()) {
                PreparedStatement ps = this.connection.prepareStatement(this.databaseMeta.stripCR(sql));

                try {
                    if(param) {
                        RowMetaInterface par = inform;
                        if(inform == null || inform.isEmpty()) {
                            par = this.getParameterMetaData(ps);
                        }

                        if(par == null || par.isEmpty()) {
                            par = this.getParameterMetaData(sql, inform, data);
                        }

                        this.setValues(par, data, ps);
                    }

                    ResultSet r = ps.executeQuery();

                    try {
                        ResultSetMetaData metadata = r.getMetaData();
                        fields = this.getRowInfo(metadata, false, false);
                    } finally {
                        r.close();
                    }
                } finally {
                    ps.close();
                }
            } else {
                this.sel_stmt = this.connection.createStatement(1003, 1007);

                try {
                    if(this.databaseMeta.isFetchSizeSupported() && this.sel_stmt.getMaxRows() >= 1) {
                        if(this.databaseMeta.getDatabaseInterface().isMySQLVariant()) {
                            this.sel_stmt.setFetchSize(-2147483648);
                        } else {
                            this.sel_stmt.setFetchSize(1);
                        }
                    }

                    if(this.databaseMeta.supportsSetMaxRows()) {
                        this.sel_stmt.setMaxRows(1);
                    }

                    ResultSet r = this.sel_stmt.executeQuery(this.databaseMeta.stripCR(sql));

                    try {
                        fields = this.getRowInfo(r.getMetaData(), false, false);
                    } finally {
                        r.close();
                    }
                } finally {
                    this.sel_stmt.close();
                    this.sel_stmt = null;
                }
            }

            return fields;
        } catch (Exception var35) {
            throw new KettleDatabaseException("Couldn't get field info from [" + sql + "]" + Const.CR, var35);
        }
    }

    public void closeQuery(ResultSet res) throws KettleDatabaseException {
        try {
            if(res != null) {
                res.close();
            }

            if(this.sel_stmt != null) {
                this.sel_stmt.close();
                this.sel_stmt = null;
            }

            if(this.pstmt != null) {
                this.pstmt.close();
                this.pstmt = null;
            }

        } catch (SQLException var3) {
            throw new KettleDatabaseException("Couldn't close query: resultset or prepared statements", var3);
        }
    }

    private RowMetaInterface getRowInfo(ResultSetMetaData rm, boolean ignoreLength, boolean lazyConversion) throws KettleDatabaseException {
        try {
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_META_START, this.databaseMeta.getName(), new long[0]);
            if(rm == null) {
                throw new KettleDatabaseException("No result set metadata available to retrieve row metadata!");
            } else {
                RowMeta rowMeta = new RowMeta();

                try {
                    int nrcols = rm.getColumnCount();

                    for(int i = 1; i <= nrcols; ++i) {
                        ValueMetaInterface valueMeta = this.getValueFromSQLType(rm, i, ignoreLength, lazyConversion);
                        rowMeta.addValueMeta(valueMeta);
                    }

                    RowMeta var13 = rowMeta;
                    return var13;
                } catch (SQLException var11) {
                    throw new KettleDatabaseException("Error getting row information from database: ", var11);
                }
            }
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_META_STOP, this.databaseMeta.getName(), new long[0]);
        }
    }

    private ValueMetaInterface getValueFromSQLType(ResultSetMetaData rm, int i, boolean ignoreLength, boolean lazyConversion) throws KettleDatabaseException, SQLException {
        String name;
        if(this.databaseMeta.isMySQLVariant() && this.getDatabaseMetaData().getDriverMajorVersion() > 3) {
            name = new String(rm.getColumnLabel(i));
        } else {
            name = new String(rm.getColumnName(i));
        }

        if(Utils.isEmpty(name) || Const.onlySpaces(name)) {
            name = "Field" + (i + 1);
        }

        ValueMetaInterface valueMeta = null;
        Iterator var7 = valueMetaPluginClasses.iterator();

        while(var7.hasNext()) {
            ValueMetaInterface valueMetaClass = (ValueMetaInterface)var7.next();
            ValueMetaInterface v = valueMetaClass.getValueFromSQLType(this.databaseMeta, name, rm, i, ignoreLength, lazyConversion);
            if(v != null) {
                valueMeta = v;
                break;
            }
        }

        if(valueMeta != null) {
            return valueMeta;
        } else {
            throw new KettleDatabaseException("Unable to handle database column '" + name + "', on column index " + i + " : not a handled data type");
        }
    }

    public boolean absolute(ResultSet rs, int position) throws KettleDatabaseException {
        try {
            return rs.absolute(position);
        } catch (SQLException var4) {
            throw new KettleDatabaseException("Unable to move resultset to position " + position, var4);
        }
    }

    public boolean relative(ResultSet rs, int rows) throws KettleDatabaseException {
        try {
            return rs.relative(rows);
        } catch (SQLException var4) {
            throw new KettleDatabaseException("Unable to move the resultset forward " + rows + " rows", var4);
        }
    }

    public void afterLast(ResultSet rs) throws KettleDatabaseException {
        try {
            rs.afterLast();
        } catch (SQLException var3) {
            throw new KettleDatabaseException("Unable to move resultset to after the last position", var3);
        }
    }

    public void first(ResultSet rs) throws KettleDatabaseException {
        try {
            rs.first();
        } catch (SQLException var3) {
            throw new KettleDatabaseException("Unable to move resultset to the first position", var3);
        }
    }

    public Object[] getRow(ResultSet rs) throws KettleDatabaseException {
        return this.getRow(rs, false);
    }

    public Object[] getRow(ResultSet rs, boolean lazyConversion) throws KettleDatabaseException {
        if(this.rowMeta == null) {
            ResultSetMetaData rsmd = null;

            try {
                rsmd = rs.getMetaData();
            } catch (SQLException var5) {
                throw new KettleDatabaseException("Unable to retrieve metadata from resultset", var5);
            }

            this.rowMeta = this.getRowInfo(rsmd, false, lazyConversion);
        }

        return this.getRow(rs, (ResultSetMetaData)null, this.rowMeta);
    }

    public Object[] getRow(ResultSet rs, ResultSetMetaData dummy, RowMetaInterface rowInfo) throws KettleDatabaseException {
        long startTime = System.currentTimeMillis();
        boolean var16 = false;

        Object[] var19;
        try {
            var16 = true;
            int nrcols = rowInfo.size();
            Object[] data = RowDataUtil.allocateRowData(nrcols);
            if(rs.next()) {
                for(int i = 0; i < nrcols; ++i) {
                    ValueMetaInterface val = rowInfo.getValueMeta(i);
                    data[i] = this.databaseMeta.getValueFromResultSet(rs, val, i);
                }
            } else {
                data = null;
            }

            var19 = data;
            var16 = false;
        } catch (Exception var17) {
            throw new KettleDatabaseException("Couldn't get row from result set", var17);
        } finally {
            if(var16) {
                if(this.log.isGatheringMetrics()) {
                    long time = System.currentTimeMillis() - startTime;
                    this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_SUM_TIME, this.databaseMeta.getName(), new long[]{time});
                    this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_MIN_TIME, this.databaseMeta.getName(), new long[]{time});
                    this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_MAX_TIME, this.databaseMeta.getName(), new long[]{time});
                    this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_COUNT, this.databaseMeta.getName(), new long[0]);
                }

            }
        }

        if(this.log.isGatheringMetrics()) {
            long time = System.currentTimeMillis() - startTime;
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_SUM_TIME, this.databaseMeta.getName(), new long[]{time});
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_MIN_TIME, this.databaseMeta.getName(), new long[]{time});
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_MAX_TIME, this.databaseMeta.getName(), new long[]{time});
            this.log.snap(Metrics.METRIC_DATABASE_GET_ROW_COUNT, this.databaseMeta.getName(), new long[0]);
        }

        return var19;
    }

    public void printSQLException(SQLException ex) {
        this.log.logError("==> SQLException: ");

        while(ex != null) {
            this.log.logError("Message:   " + ex.getMessage());
            this.log.logError("SQLState:  " + ex.getSQLState());
            this.log.logError("ErrorCode: " + ex.getErrorCode());
            ex = ex.getNextException();
            this.log.logError("");
        }

    }

    public void setLookup(String table, String[] codes, String[] condition, String[] gets, String[] rename, String orderby) throws KettleDatabaseException {
        this.setLookup(table, codes, condition, gets, rename, orderby, false);
    }

    public void setLookup(String schema, String table, String[] codes, String[] condition, String[] gets, String[] rename, String orderby) throws KettleDatabaseException {
        this.setLookup(schema, table, codes, condition, gets, rename, orderby, false);
    }

    public void setLookup(String tableName, String[] codes, String[] condition, String[] gets, String[] rename, String orderby, boolean checkForMultipleResults) throws KettleDatabaseException {
        this.setLookup((String)null, tableName, codes, condition, gets, rename, orderby, checkForMultipleResults);
    }

    public void setLookup(String schemaName, String tableName, String[] codes, String[] condition, String[] gets, String[] rename, String orderby, boolean checkForMultipleResults) throws KettleDatabaseException {
        try {
            this.log.snap(Metrics.METRIC_DATABASE_SET_LOOKUP_START, this.databaseMeta.getName(), new long[0]);
            String table = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
            String sql = "SELECT ";

            int i;
            for(i = 0; i < gets.length; ++i) {
                if(i != 0) {
                    sql = sql + ", ";
                }

                sql = sql + this.databaseMeta.quoteField(gets[i]);
                if(rename != null && rename[i] != null && !gets[i].equalsIgnoreCase(rename[i])) {
                    sql = sql + " AS " + this.databaseMeta.quoteField(rename[i]);
                }
            }

            sql = sql + " FROM " + table + " WHERE ";

            for(i = 0; i < codes.length; ++i) {
                if(i != 0) {
                    sql = sql + " AND ";
                }

                sql = sql + this.databaseMeta.quoteField(codes[i]);
                if("BETWEEN".equalsIgnoreCase(condition[i])) {
                    sql = sql + " BETWEEN ? AND ? ";
                } else if(!"IS NULL".equalsIgnoreCase(condition[i]) && !"IS NOT NULL".equalsIgnoreCase(condition[i])) {
                    sql = sql + " " + condition[i] + " ? ";
                } else {
                    sql = sql + " " + condition[i] + " ";
                }
            }

            if(orderby != null && orderby.length() != 0) {
                sql = sql + " ORDER BY " + orderby;
            }

            try {
                if(this.log.isDetailed()) {
                    this.log.logDetailed("Setting preparedStatement to [" + sql + "]");
                }

                this.prepStatementLookup = this.connection.prepareStatement(this.databaseMeta.stripCR(sql));
                if(!checkForMultipleResults && this.databaseMeta.supportsSetMaxRows()) {
                    this.prepStatementLookup.setMaxRows(1);
                }
            } catch (SQLException var15) {
                throw new KettleDatabaseException("Unable to prepare statement for update [" + sql + "]", var15);
            }
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_SET_LOOKUP_STOP, this.databaseMeta.getName(), new long[0]);
        }

    }

    public boolean prepareUpdate(String table, String[] codes, String[] condition, String[] sets) {
        return this.prepareUpdate((String)null, table, codes, condition, sets);
    }

    public boolean prepareUpdate(String schemaName, String tableName, String[] codes, String[] condition, String[] sets) {
        try {
            this.log.snap(Metrics.METRIC_DATABASE_PREPARE_UPDATE_START, this.databaseMeta.getName(), new long[0]);
            StringBuilder sql = new StringBuilder(128);
            String schemaTable = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
            sql.append("UPDATE ").append(schemaTable).append(Const.CR).append("SET ");

            int i;
            for(i = 0; i < sets.length; ++i) {
                if(i != 0) {
                    sql.append(",   ");
                }

                sql.append(this.databaseMeta.quoteField(sets[i]));
                sql.append(" = ?").append(Const.CR);
            }

            sql.append("WHERE ");

            for(i = 0; i < codes.length; ++i) {
                if(i != 0) {
                    sql.append("AND   ");
                }

                sql.append(this.databaseMeta.quoteField(codes[i]));
                if("BETWEEN".equalsIgnoreCase(condition[i])) {
                    sql.append(" BETWEEN ? AND ? ");
                } else if(!"IS NULL".equalsIgnoreCase(condition[i]) && !"IS NOT NULL".equalsIgnoreCase(condition[i])) {
                    sql.append(' ').append(condition[i]).append(" ? ");
                } else {
                    sql.append(' ').append(condition[i]).append(' ');
                }
            }

            try {
                String s = sql.toString();
                if(this.log.isDetailed()) {
                    this.log.logDetailed("Setting update preparedStatement to [" + s + "]");
                }

                this.prepStatementUpdate = this.connection.prepareStatement(this.databaseMeta.stripCR(s));
            } catch (SQLException var13) {
                this.printSQLException(var13);
                boolean var9 = false;
                return var9;
            }

            boolean var16 = true;
            return var16;
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_PREPARE_UPDATE_STOP, this.databaseMeta.getName(), new long[0]);
        }
    }

    public boolean prepareDelete(String table, String[] codes, String[] condition) {
        return this.prepareDelete((String)null, table, codes, condition);
    }

    public boolean prepareDelete(String schemaName, String tableName, String[] codes, String[] condition) {
        try {
            this.log.snap(Metrics.METRIC_DATABASE_PREPARE_DELETE_START, this.databaseMeta.getName(), new long[0]);
            String table = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
            String sql = "DELETE FROM " + table + Const.CR;
            sql = sql + "WHERE ";

            for(int i = 0; i < codes.length; ++i) {
                if(i != 0) {
                    sql = sql + "AND   ";
                }

                sql = sql + codes[i];
                if("BETWEEN".equalsIgnoreCase(condition[i])) {
                    sql = sql + " BETWEEN ? AND ? ";
                } else if(!"IS NULL".equalsIgnoreCase(condition[i]) && !"IS NOT NULL".equalsIgnoreCase(condition[i])) {
                    sql = sql + " " + condition[i] + " ? ";
                } else {
                    sql = sql + " " + condition[i] + " ";
                }
            }

            try {
                if(this.log.isDetailed()) {
                    this.log.logDetailed("Setting update preparedStatement to [" + sql + "]");
                }

                this.prepStatementUpdate = this.connection.prepareStatement(this.databaseMeta.stripCR(sql));
            } catch (SQLException var12) {
                this.printSQLException(var12);
                boolean var8 = false;
                return var8;
            }

            boolean var14 = true;
            return var14;
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_PREPARE_DELETE_STOP, this.databaseMeta.getName(), new long[0]);
        }
    }

    public void setProcLookup(String proc, String[] arg, String[] argdir, int[] argtype, String returnvalue, int returntype) throws KettleDatabaseException {
        try {
            this.log.snap(Metrics.METRIC_DATABASE_PREPARE_DBPROC_START, this.databaseMeta.getName(), new long[0]);
            boolean pos = false;
            String sql = "{ ";
            if(returnvalue != null && returnvalue.length() != 0) {
                sql = sql + "? = ";
            }

            sql = sql + "call " + proc + " ";
            if(arg.length > 0) {
                sql = sql + "(";
            }

            int i;
            for(i = 0; i < arg.length; ++i) {
                if(i != 0) {
                    sql = sql + ", ";
                }

                sql = sql + " ?";
            }

            if(arg.length > 0) {
                sql = sql + ")";
            }

            sql = sql + "}";

            try {
                if(this.log.isDetailed()) {
                    this.log.logDetailed("DBA setting callableStatement to [" + sql + "]");
                }

                this.cstmt = this.connection.prepareCall(sql);
                int pos2 = 1;
                if(!Utils.isEmpty(returnvalue)) {
                    switch(returntype) {
                        case 1:
                            this.cstmt.registerOutParameter(pos2, 8);
                            break;
                        case 2:
                            this.cstmt.registerOutParameter(pos2, 12);
                            break;
                        case 3:
                            this.cstmt.registerOutParameter(pos2, 93);
                            break;
                        case 4:
                            this.cstmt.registerOutParameter(pos2, 16);
                            break;
                        case 5:
                            this.cstmt.registerOutParameter(pos2, -5);
                            break;
                        case 6:
                            this.cstmt.registerOutParameter(pos2, 3);
                    }

                    ++pos2;
                }

                for(i = 0; i < arg.length; ++i) {
                    if(argdir[i].equalsIgnoreCase("OUT") || argdir[i].equalsIgnoreCase("INOUT")) {
                        switch(argtype[i]) {
                            case 1:
                                this.cstmt.registerOutParameter(i + pos2, 8);
                                break;
                            case 2:
                                this.cstmt.registerOutParameter(i + pos2, 12);
                                break;
                            case 3:
                                this.cstmt.registerOutParameter(i + pos2, 93);
                                break;
                            case 4:
                                this.cstmt.registerOutParameter(i + pos2, 16);
                                break;
                            case 5:
                                this.cstmt.registerOutParameter(i + pos2, -5);
                                break;
                            case 6:
                                this.cstmt.registerOutParameter(i + pos2, 3);
                        }
                    }
                }
            } catch (SQLException var13) {
                throw new KettleDatabaseException("Unable to prepare database procedure call", var13);
            }
        } finally {
            this.log.snap(Metrics.METRIC_DATABASE_PREPARE_DBPROC_STOP, this.databaseMeta.getName(), new long[0]);
        }

    }

    public Object[] getLookup() throws KettleDatabaseException {
        return this.getLookup(this.prepStatementLookup, false);
    }

    public Object[] getLookup(boolean failOnMultipleResults) throws KettleDatabaseException {
        return this.getLookup(failOnMultipleResults, false);
    }

    public Object[] getLookup(boolean failOnMultipleResults, boolean lazyConversion) throws KettleDatabaseException {
        return this.getLookup(this.prepStatementLookup, failOnMultipleResults, lazyConversion);
    }

    public Object[] getLookup(PreparedStatement ps) throws KettleDatabaseException {
        this.rowMeta = null;
        return this.getLookup(ps, false);
    }

    public Object[] getLookup(PreparedStatement ps, boolean failOnMultipleResults) throws KettleDatabaseException {
        return this.getLookup(ps, failOnMultipleResults, false);
    }

    public Object[] getLookup(PreparedStatement ps, boolean failOnMultipleResults, boolean lazyConversion) throws KettleDatabaseException {
        ResultSet res = null;

        Object[] var6;
        try {
            this.log.snap(Metrics.METRIC_DATABASE_GET_LOOKUP_START, this.databaseMeta.getName(), new long[0]);
            res = ps.executeQuery();
            Object[] ret = this.getRow(res, lazyConversion);
            if(failOnMultipleResults && ret != null && res.next()) {
                throw new KettleDatabaseException("Only 1 row was expected as a result of a lookup, and at least 2 were found!");
            }

            var6 = ret;
        } catch (SQLException var32) {
            throw new KettleDatabaseException("Error looking up row in database", var32);
        } finally {
            try {
                if(res != null) {
                    res.close();
                }
            } catch (SQLException var30) {
                throw new KettleDatabaseException("Unable to close resultset after looking up data", var30);
            } finally {
                this.log.snap(Metrics.METRIC_DATABASE_GET_LOOKUP_STOP, this.databaseMeta.getName(), new long[0]);
            }

        }

        return var6;
    }

    public DatabaseMetaData getDatabaseMetaData() throws KettleDatabaseException {
        if(this.dbmd == null) {
            try {
                this.log.snap(Metrics.METRIC_DATABASE_GET_DBMETA_START, this.databaseMeta.getName(), new long[0]);
                this.dbmd = this.connection.getMetaData();
            } catch (Exception var5) {
                throw new KettleDatabaseException("Unable to get database metadata from this database connection", var5);
            } finally {
                this.log.snap(Metrics.METRIC_DATABASE_GET_DBMETA_STOP, this.databaseMeta.getName(), new long[0]);
            }
        }

        return this.dbmd;
    }

    public String getDDL(String tablename, RowMetaInterface fields) throws KettleDatabaseException {
        return this.getDDL(tablename, fields, (String)null, false, (String)null, true);
    }

    public String getDDL(String tablename, RowMetaInterface fields, String tk, boolean use_autoinc, String pk) throws KettleDatabaseException {
        return this.getDDL(tablename, fields, tk, use_autoinc, pk, true);
    }

    public String getDDL(String tableName, RowMetaInterface fields, String tk, boolean use_autoinc, String pk, boolean semicolon) throws KettleDatabaseException {
        this.databaseMeta.quoteReservedWords(fields);
        String quotedTk = tk != null?this.databaseMeta.quoteField(tk):null;
        String retval;
        if(this.checkTableExists(tableName)) {
            retval = this.getAlterTableStatement(tableName, fields, quotedTk, use_autoinc, pk, semicolon);
        } else {
            retval = this.getCreateTableStatement(tableName, fields, quotedTk, use_autoinc, pk, semicolon);
        }

        return retval;
    }

    public String getCreateTableStatement(String tableName, RowMetaInterface fields, String tk, boolean use_autoinc, String pk, boolean semicolon) {
        StringBuilder retval = new StringBuilder();
        DatabaseInterface databaseInterface = this.databaseMeta.getDatabaseInterface();
        retval.append(databaseInterface.getCreateTableStatement());
        retval.append(tableName + Const.CR);
        retval.append("(").append(Const.CR);

        for(int i = 0; i < fields.size(); ++i) {
            if(i > 0) {
                retval.append(", ");
            } else {
                retval.append("  ");
            }

            ValueMetaInterface v = fields.getValueMeta(i);
            retval.append(this.databaseMeta.getFieldDefinition(v, tk, pk, use_autoinc));
        }

        if(tk != null && this.databaseMeta.requiresCreateTablePrimaryKeyAppend()) {
            retval.append(", PRIMARY KEY (").append(tk).append(")").append(Const.CR);
        }

        if(pk != null && this.databaseMeta.requiresCreateTablePrimaryKeyAppend()) {
            retval.append(", PRIMARY KEY (").append(pk).append(")").append(Const.CR);
        }

        retval.append(")").append(Const.CR);
        retval.append(this.databaseMeta.getDatabaseInterface().getDataTablespaceDDL(this.variables, this.databaseMeta));
        if(pk == null && tk == null && this.databaseMeta.getDatabaseInterface() instanceof NeoviewDatabaseMeta) {
            retval.append("NO PARTITION");
        }

        if(semicolon) {
            retval.append(";");
        }

        return retval.toString();
    }

    public String getAlterTableStatement(String tableName, RowMetaInterface fields, String tk, boolean use_autoinc, String pk, boolean semicolon) throws KettleDatabaseException {
        String retval = "";
        RowMetaInterface tabFields = this.getTableFields(tableName);
        this.databaseMeta.quoteReservedWords(tabFields);
        RowMetaInterface missing = new RowMeta();

        int i;
        ValueMetaInterface v;
        for(i = 0; i < fields.size(); ++i) {
            v = fields.getValueMeta(i);
            if(tabFields.searchValueMeta(v.getName()) == null) {
                missing.addValueMeta(v);
            }
        }

        if(missing.size() != 0) {
            for(i = 0; i < missing.size(); ++i) {
                v = missing.getValueMeta(i);
                retval = retval + this.databaseMeta.getAddColumnStatement(tableName, v, tk, use_autoinc, pk, true);
            }
        }

        RowMetaInterface surplus = new RowMeta();

        for(i = 0; i < tabFields.size(); ++i) {
            v = tabFields.getValueMeta(i);
            if(fields.searchValueMeta(v.getName()) == null) {
                surplus.addValueMeta(v);
            }
        }

        if(surplus.size() != 0) {
            for(i = 0; i < surplus.size(); ++i) {
                v = surplus.getValueMeta(i);
                retval = retval + this.databaseMeta.getDropColumnStatement(tableName, v, tk, use_autoinc, pk, true);
            }
        }

        RowMetaInterface modify = new RowMeta();

        for(i = 0; i < fields.size(); ++i) {
            v = fields.getValueMeta(i);
            ValueMetaInterface currentField = tabFields.searchValueMeta(v.getName());
            if(v != null && currentField != null) {
                String desiredDDL = this.databaseMeta.getFieldDefinition(v, tk, pk, use_autoinc);
                String currentDDL = this.databaseMeta.getFieldDefinition(currentField, tk, pk, use_autoinc);
                boolean mod = !desiredDDL.equalsIgnoreCase(currentDDL);
                if(mod) {
                    modify.addValueMeta(v);
                }
            }
        }

        if(modify.size() > 0) {
            for(i = 0; i < modify.size(); ++i) {
                v = modify.getValueMeta(i);
                retval = retval + this.databaseMeta.getModifyColumnStatement(tableName, v, tk, use_autoinc, pk, true);
            }
        }

        return retval;
    }

    public void truncateTable(String tablename) throws KettleDatabaseException {
        if(Utils.isEmpty(this.connectionGroup)) {
            String truncateStatement = this.databaseMeta.getTruncateTableStatement((String)null, tablename);
            if(truncateStatement == null) {
                throw new KettleDatabaseException("Truncate table not supported by " + this.databaseMeta.getDatabaseInterface().getPluginName());
            }

            this.execStatement(truncateStatement);
        } else {
            this.execStatement("DELETE FROM " + this.databaseMeta.quoteField(tablename));
        }

    }

    public void truncateTable(String schema, String tablename) throws KettleDatabaseException {
        if(Utils.isEmpty(this.connectionGroup)) {
            String truncateStatement = this.databaseMeta.getTruncateTableStatement(schema, tablename);
            if(truncateStatement == null) {
                throw new KettleDatabaseException("Truncate table not supported by " + this.databaseMeta.getDatabaseInterface().getPluginName());
            }

            this.execStatement(truncateStatement);
        } else {
            this.execStatement("DELETE FROM " + this.databaseMeta.getQuotedSchemaTableCombination(schema, tablename));
        }

    }

    public RowMetaAndData getOneRow(String sql) throws KettleDatabaseException {
        ResultSet rs = this.openQuery(sql);
        if(rs != null) {
            Object[] row = this.getRow(rs);

            try {
                rs.close();
            } catch (Exception var7) {
                throw new KettleDatabaseException("Unable to close resultset", var7);
            }

            if(this.pstmt != null) {
                try {
                    this.pstmt.close();
                } catch (Exception var6) {
                    throw new KettleDatabaseException("Unable to close prepared statement pstmt", var6);
                }

                this.pstmt = null;
            }

            if(this.sel_stmt != null) {
                try {
                    this.sel_stmt.close();
                } catch (Exception var5) {
                    throw new KettleDatabaseException("Unable to close prepared statement sel_stmt", var5);
                }

                this.sel_stmt = null;
            }

            return new RowMetaAndData(this.rowMeta, row);
        } else {
            throw new KettleDatabaseException("error opening resultset for query: " + sql);
        }
    }

    public RowMeta getMetaFromRow(Object[] row, ResultSetMetaData md) throws SQLException, KettleDatabaseException {
        RowMeta meta = new RowMeta();

        for(int i = 0; i < md.getColumnCount(); ++i) {
            ValueMetaInterface valueMeta = this.getValueFromSQLType(md, i + 1, true, false);
            meta.addValueMeta(valueMeta);
        }

        return meta;
    }

    public RowMetaAndData getOneRow(String sql, RowMetaInterface param, Object[] data) throws KettleDatabaseException {
        ResultSet rs = this.openQuery(sql, param, data);
        if(rs != null) {
            Object[] row = this.getRow(rs);
            this.rowMeta = null;
            RowMeta tmpMeta = null;

            try {
                ResultSetMetaData md = rs.getMetaData();
                tmpMeta = this.getMetaFromRow(row, md);
            } catch (Exception var24) {
                var24.printStackTrace();
            } finally {
                try {
                    rs.close();
                } catch (Exception var23) {
                    throw new KettleDatabaseException("Unable to close resultset", var23);
                }

                if(this.pstmt != null) {
                    try {
                        this.pstmt.close();
                    } catch (Exception var22) {
                        throw new KettleDatabaseException("Unable to close prepared statement pstmt", var22);
                    }

                    this.pstmt = null;
                }

                if(this.sel_stmt != null) {
                    try {
                        this.sel_stmt.close();
                    } catch (Exception var21) {
                        throw new KettleDatabaseException("Unable to close prepared statement sel_stmt", var21);
                    }

                    this.sel_stmt = null;
                }

            }

            return new RowMetaAndData(tmpMeta, row);
        } else {
            return null;
        }
    }

    public RowMetaInterface getParameterMetaData(PreparedStatement ps) {
        RowMeta par = new RowMeta();

        try {
            ParameterMetaData pmd = ps.getParameterMetaData();

            for(int i = 1; i <= pmd.getParameterCount(); ++i) {
                String name = "par" + i;
                int sqltype = pmd.getParameterType(i);
                int length = pmd.getPrecision(i);
                int precision = pmd.getScale(i);
                Object val;
                switch(sqltype) {
                    case -7:
                    case 16:
                        val = new ValueMetaBoolean(name);
                        break;
                    case -6:
                    case -5:
                    case 2:
                    case 4:
                    case 5:
                        val = new ValueMetaInteger(name);
                        break;
                    case 1:
                    case 12:
                        val = new ValueMetaString(name);
                        break;
                    case 3:
                    case 6:
                    case 7:
                    case 8:
                        val = new ValueMetaNumber(name);
                        break;
                    case 91:
                    case 92:
                    case 93:
                        val = new ValueMetaDate(name);
                        break;
                    default:
                        val = new ValueMetaNone(name);
                }

                if(((ValueMetaInterface)val).isNumeric() && (length > 18 || precision > 18)) {
                    val = new ValueMetaBigNumber(name);
                }

                par.addValueMeta((ValueMetaInterface)val);
            }

            return par;
        } catch (AbstractMethodError var10) {
            return null;
        } catch (SQLException var11) {
            return null;
        } catch (Exception var12) {
            return null;
        }
    }

    public int countParameters(String sql) {
        int q = 0;
        boolean quote_opened = false;
        boolean dquote_opened = false;

        for(int x = 0; x < sql.length(); ++x) {
            char c = sql.charAt(x);
            switch(c) {
                case '"':
                    dquote_opened = !dquote_opened;
                    break;
                case '\'':
                    quote_opened = !quote_opened;
                    break;
                case '?':
                    if(!quote_opened && !dquote_opened) {
                        ++q;
                    }
            }
        }

        return q;
    }

    public RowMetaInterface getParameterMetaData(String sql, RowMetaInterface inform, Object[] data) {
        int q = this.countParameters(sql);
        RowMetaInterface par = new RowMeta();
        int i;
        if(inform != null && q == inform.size()) {
            for(i = 0; i < q; ++i) {
                ValueMetaInterface inf = inform.getValueMeta(i);
                ValueMetaInterface v = inf.clone();
                par.addValueMeta(v);
            }
        } else {
            for(i = 0; i < q; ++i) {
                ValueMetaInterface v = new ValueMetaNumber("name" + i);
                par.addValueMeta(v);
            }
        }

        return par;
    }

    public void writeLogRecord(LogTableCoreInterface logTable, LogStatus status, Object subject, Object parent) throws KettleDatabaseException {
        try {
            RowMetaAndData logRecord = logTable.getLogRecord(status, subject, parent);
            if(logRecord == null) {
                return;
            }

            boolean update = logTable.getKeyField() != null && !status.equals(LogStatus.START);
            String schemaTable = this.databaseMeta.getQuotedSchemaTableCombination(this.environmentSubstitute(logTable.getActualSchemaName()), this.environmentSubstitute(logTable.getActualTableName()));
            RowMetaInterface rowMeta = logRecord.getRowMeta();
            Object[] rowData = logRecord.getData();
            if(update) {
                RowMetaInterface updateRowMeta = new RowMeta();
                Object[] updateRowData = new Object[rowMeta.size()];
                ValueMetaInterface keyValueMeta = rowMeta.getValueMeta(0);
                StringBuilder sqlBuff = new StringBuilder(250);
                sqlBuff.append("UPDATE ").append(schemaTable).append(" SET ");

                for(int i = 1; i < rowMeta.size(); ++i) {
                    ValueMetaInterface valueMeta = rowMeta.getValueMeta(i);
                    if(i > 1) {
                        sqlBuff.append(", ");
                    }

                    sqlBuff.append(this.databaseMeta.quoteField(valueMeta.getName())).append("=? ");
                    updateRowMeta.addValueMeta(valueMeta);
                    updateRowData[i - 1] = rowData[i];
                }

                sqlBuff.append("WHERE ").append(this.databaseMeta.quoteField(keyValueMeta.getName())).append("=? ");
                updateRowMeta.addValueMeta(keyValueMeta);
                updateRowData[rowMeta.size() - 1] = rowData[0];
                String sql = sqlBuff.toString();
                this.execStatement(sql, updateRowMeta, updateRowData);
            } else {
                this.insertRow(this.environmentSubstitute(logTable.getActualSchemaName()), this.environmentSubstitute(logTable.getActualTableName()), logRecord.getRowMeta(), logRecord.getData());
            }
        } catch (Exception var16) {
            DatabaseLogExceptionFactory.getExceptionStrategy(logTable, var16).registerException(this.log, var16, PKG, "Database.Error.WriteLogTable", new String[]{this.environmentSubstitute(logTable.getActualTableName())});
        }

    }

    public void cleanupLogRecords(LogTableCoreInterface logTable) throws KettleDatabaseException {
        double timeout = Const.toDouble(Const.trim(this.environmentSubstitute(logTable.getTimeoutInDays())), 0.0D);
        if(timeout >= 1.0E-6D) {
            String schemaTable = this.databaseMeta.getQuotedSchemaTableCombination(this.environmentSubstitute(logTable.getActualSchemaName()), this.environmentSubstitute(logTable.getActualTableName()));
            if(schemaTable.isEmpty()) {
                DatabaseLogExceptionFactory.getExceptionStrategy(logTable).registerException(this.log, PKG, "DatabaseMeta.Error.LogTableNameNotFound", new String[0]);
            }

            LogTableField logField = logTable.getLogDateField();
            if(logField == null) {
                DatabaseLogExceptionFactory.getExceptionStrategy(logTable).registerException(this.log, PKG, "Database.Exception.LogTimeoutDefinedOnTableWithoutLogField", new String[0]);
            }

            String sql = "DELETE FROM " + schemaTable + " WHERE " + this.databaseMeta.quoteField(logField.getFieldName()) + " < ?";
            long now = System.currentTimeMillis();
            long limit = now - Math.round(timeout * 24.0D * 60.0D * 60.0D * 1000.0D);
            RowMetaAndData row = new RowMetaAndData();
            row.addValue(logField.getFieldName(), 3, new Date(limit));

            try {
                this.execStatement(sql, row.getRowMeta(), row.getData());
            } catch (Exception var13) {
                DatabaseLogExceptionFactory.getExceptionStrategy(logTable).registerException(this.log, PKG, "Database.Exception.UnableToCleanUpOlderRecordsFromLogTable", new String[]{this.environmentSubstitute(logTable.getActualTableName())});
            }

        }
    }

    public Object[] getLastLogDate(String logtable, String name, boolean job, LogStatus status) throws KettleDatabaseException {
        Object[] row = null;
        String jobtrans = job?this.databaseMeta.quoteField("JOBNAME"):this.databaseMeta.quoteField("TRANSNAME");
        String sql = "";
        sql = sql + " SELECT " + this.databaseMeta.quoteField("ENDDATE") + ", " + this.databaseMeta.quoteField("DEPDATE") + ", " + this.databaseMeta.quoteField("STARTDATE");
        sql = sql + " FROM " + logtable;
        sql = sql + " WHERE  " + this.databaseMeta.quoteField("ERRORS") + "    = 0";
        sql = sql + " AND    " + this.databaseMeta.quoteField("STATUS") + "    = 'end'";
        sql = sql + " AND    " + jobtrans + " = ?";
        sql = sql + " ORDER BY " + this.databaseMeta.quoteField("LOGDATE") + " DESC, " + this.databaseMeta.quoteField("ENDDATE") + " DESC";

        try {
            this.pstmt = this.connection.prepareStatement(this.databaseMeta.stripCR(sql));
            RowMetaInterface r = new RowMeta();
            r.addValueMeta(new ValueMetaString("TRANSNAME", 255, -1));
            this.setValues((RowMetaInterface)r, (Object[])(new Object[]{name}));
            ResultSet res = this.pstmt.executeQuery();
            if(res != null) {
                this.rowMeta = this.getRowInfo(res.getMetaData(), false, false);
                row = this.getRow(res);
                res.close();
            }

            this.pstmt.close();
            this.pstmt = null;
            return row;
        } catch (SQLException var10) {
            throw new KettleDatabaseException("Unable to obtain last logdate from table " + logtable, var10);
        }
    }

    public synchronized Long getNextValue(Hashtable<String, Counter> counters, String tableName, String val_key) throws KettleDatabaseException {
        return this.getNextValue(counters, (String)null, tableName, val_key);
    }

    public synchronized Long getNextValue(Hashtable<String, Counter> counters, String schemaName, String tableName, String val_key) throws KettleDatabaseException {
        Long nextValue = null;
        String schemaTable = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
        String lookup = schemaTable + "." + this.databaseMeta.quoteField(val_key);
        Counter counter = null;
        if(counters != null) {
            counter = (Counter)counters.get(lookup);
        }

        if(counter == null) {
            RowMetaAndData rmad = this.getOneRow("SELECT MAX(" + this.databaseMeta.quoteField(val_key) + ") FROM " + schemaTable);
            if(rmad == null) {
                throw new KettleDatabaseException("Couldn't find maximum key value from table " + schemaTable);
            }

            long previous;
            try {
                Long tmp = rmad.getRowMeta().getInteger(rmad.getData(), 0);
                if(tmp != null) {
                    previous = tmp.longValue();
                } else {
                    previous = 0L;
                }
            } catch (KettleValueException var13) {
                throw new KettleDatabaseException("Error getting the first long value from the max value returned from table : " + schemaTable);
            }

            counter = new Counter(previous + 1L, 1L);
            nextValue = Long.valueOf(counter.next());
            if(counters != null) {
                counters.put(lookup, counter);
            }
        } else {
            nextValue = Long.valueOf(counter.next());
        }

        return nextValue;
    }

    public String toString() {
        return this.databaseMeta != null?this.databaseMeta.getName():"-";
    }

    public boolean isSystemTable(String table_name) {
        return this.databaseMeta.isSystemTable(table_name);
    }

    public List<Object[]> getRows(String sql, int limit) throws KettleDatabaseException {
        return this.getRows((String)sql, limit, (ProgressMonitorListener)null);
    }

    public List<Object[]> getRows(String sql, int limit, ProgressMonitorListener monitor) throws KettleDatabaseException {
        return this.getRows(sql, (RowMetaInterface)null, (Object[])null, 1000, false, limit, monitor);
    }

    public List<Object[]> getRows(String sql, RowMetaInterface params, Object[] data, int fetch_mode, boolean lazyConversion, int limit, ProgressMonitorListener monitor) throws KettleDatabaseException {
        if(monitor != null) {
            monitor.setTaskName("Opening query...");
        }

        ResultSet rset = this.openQuery(sql, params, data, fetch_mode, lazyConversion);
        return this.getRows(rset, limit, monitor);
    }

    public List<Object[]> getRows(ResultSet rset, int limit, ProgressMonitorListener monitor) throws KettleDatabaseException {
        try {
            List<Object[]> result = new ArrayList();
            boolean stop = false;
            int i = 0;
            if(rset != null) {
                if(monitor != null && limit > 0) {
                    monitor.beginTask("Reading rows...", limit);
                }

                while((limit <= 0 || i < limit) && !stop) {
                    Object[] row = this.getRow(rset);
                    if(row != null) {
                        result.add(row);
                        ++i;
                    } else {
                        stop = true;
                    }

                    if(monitor != null && limit > 0) {
                        monitor.worked(1);
                    }

                    if(monitor != null && monitor.isCanceled()) {
                        break;
                    }
                }

                this.closeQuery(rset);
                if(monitor != null) {
                    monitor.done();
                }
            }

            return result;
        } catch (Exception var8) {
            throw new KettleDatabaseException("Unable to get list of rows from ResultSet : ", var8);
        }
    }

    public List<Object[]> getFirstRows(String table_name, int limit) throws KettleDatabaseException {
        return this.getFirstRows(table_name, limit, (ProgressMonitorListener)null);
    }

    public List<Object[]> getFirstRows(String table_name, int limit, ProgressMonitorListener monitor) throws KettleDatabaseException {
        String sql = "SELECT";
        if(this.databaseMeta.getDatabaseInterface() instanceof NeoviewDatabaseMeta) {
            sql = sql + " [FIRST " + limit + "]";
        } else if(this.databaseMeta.getDatabaseInterface() instanceof SybaseIQDatabaseMeta) {
            sql = sql + " TOP " + limit + " ";
        }

        sql = sql + " * FROM " + table_name;
        if(limit > 0) {
            sql = sql + this.databaseMeta.getLimitClause(limit);
        }

        return this.getRows(sql, limit, monitor);
    }

    public RowMetaInterface getReturnRowMeta() {
        return this.rowMeta;
    }

    public String[] getTableTypes() throws KettleDatabaseException {
        try {
            ArrayList<String> types = new ArrayList();
            ResultSet rstt = this.getDatabaseMetaData().getTableTypes();

            while(rstt.next()) {
                String ttype = rstt.getString("TABLE_TYPE");
                types.add(ttype);
            }

            return (String[])types.toArray(new String[types.size()]);
        } catch (SQLException var4) {
            throw new KettleDatabaseException("Unable to get table types from database!", var4);
        }
    }

    public String[] getTablenames() throws KettleDatabaseException {
        return this.getTablenames(false);
    }

    public String[] getTablenames(boolean includeSchema) throws KettleDatabaseException {
        return this.getTablenames((String)null, includeSchema);
    }

    public String[] getTablenames(String schemanamein, boolean includeSchema) throws KettleDatabaseException {
        return this.getTablenames(schemanamein, includeSchema, (Map)null);
    }

    public String[] getTablenames(String schemanamein, boolean includeSchema, Map<String, String> props) throws KettleDatabaseException {
        Map<String, Collection<String>> tableMap = this.getTableMap(schemanamein, props);
        List<String> res = new ArrayList();
        Iterator var6 = tableMap.keySet().iterator();

        while(var6.hasNext()) {
            String schema = (String)var6.next();
            Collection<String> tables = (Collection)tableMap.get(schema);
            Iterator var9 = tables.iterator();

            while(var9.hasNext()) {
                String table = (String)var9.next();
                if(includeSchema) {
                    res.add(this.databaseMeta.getQuotedSchemaTableCombination(schema, table));
                } else {
                    res.add(this.databaseMeta.getQuotedSchemaTableCombination((String)null, table));
                }
            }
        }

        return (String[])res.toArray(new String[res.size()]);
    }

    public Map<String, Collection<String>> getTableMap() throws KettleDatabaseException {
        return this.getTableMap((String)null);
    }

    public Map<String, Collection<String>> getTableMap(String schemanamein) throws KettleDatabaseException {
        return this.getTableMap(schemanamein, (Map)null);
    }

    public Map<String, Collection<String>> getTableMap(String schemanamein, Map<String, String> props) throws KettleDatabaseException {
        String schemaname = schemanamein;
        if(schemanamein == null && this.databaseMeta.useSchemaNameForTableList()) {
            schemaname = this.environmentSubstitute(this.databaseMeta.getUsername()).toUpperCase();
        }

        Map<String, Collection<String>> tableMap = new HashMap();
        ResultSet alltables = null;

        try {
            alltables = this.getDatabaseMetaData().getTables((String)null, schemaname, (String)null, this.databaseMeta.getTableTypes());

            label207:
            while(true) {
                while(true) {
                    if(!alltables.next()) {
                        break label207;
                    }

                    String cat = "";

                    try {
                        cat = alltables.getString("TABLE_CAT");
                    } catch (Exception var25) {
                        if(this.log.isDebug()) {
                            this.log.logDebug("Error getting tables for field TABLE_CAT (ignored): " + var25.toString());
                        }
                    }

                    String schema = "";

                    try {
                        schema = alltables.getString("TABLE_SCHEM");
                    } catch (Exception var24) {
                        if(this.log.isDebug()) {
                            this.log.logDebug("Error getting tables for field TABLE_SCHEM (ignored): " + var24.toString());
                        }
                    }

                    if(Utils.isEmpty(schema)) {
                        schema = cat;
                    }

                    String table = alltables.getString("TABLE_NAME");
                    if(this.log.isRowLevel()) {
                        this.log.logRowlevel(this.toString(), new Object[]{"got table from meta-data: " + this.databaseMeta.getQuotedSchemaTableCombination(schema, table)});
                    }

                    if(props != null && !props.isEmpty()) {
                        Iterator var9 = props.entrySet().iterator();

                        while(var9.hasNext()) {
                            Entry<String, String> prop = (Entry)var9.next();
                            String propName = (String)prop.getKey();
                            String tableProperty = alltables.getString(propName);
                            if(tableProperty != null) {
                                String propValue = (String)prop.getValue();
                                if(tableProperty.equals(propValue)) {
                                    this.multimapPut(schema, table, tableMap);
                                }
                            }
                        }
                    } else {
                        this.multimapPut(schema, table, tableMap);
                    }
                }
            }
        } catch (SQLException var26) {
            this.log.logError("Error getting tablenames from schema [" + schemaname + "]");
        } finally {
            try {
                if(alltables != null) {
                    alltables.close();
                }
            } catch (SQLException var23) {
                throw new KettleDatabaseException("Error closing resultset after getting views from schema [" + schemaname + "]", var23);
            }

        }

        if(this.log.isDetailed()) {
            this.log.logDetailed("read :" + this.multimapSize(tableMap) + " table names from db meta-data.");
        }

        return tableMap;
    }

    public String[] getViews() throws KettleDatabaseException {
        return this.getViews(false);
    }

    public String[] getViews(boolean includeSchema) throws KettleDatabaseException {
        return this.getViews((String)null, includeSchema);
    }

    public String[] getViews(String schemanamein, boolean includeSchema) throws KettleDatabaseException {
        Map<String, Collection<String>> viewMap = this.getViewMap(schemanamein);
        List<String> res = new ArrayList();
        Iterator var5 = viewMap.keySet().iterator();

        while(var5.hasNext()) {
            String schema = (String)var5.next();
            Collection<String> views = (Collection)viewMap.get(schema);
            Iterator var8 = views.iterator();

            while(var8.hasNext()) {
                String view = (String)var8.next();
                if(includeSchema) {
                    res.add(this.databaseMeta.getQuotedSchemaTableCombination(schema, view));
                } else {
                    res.add(view);
                }
            }
        }

        return (String[])res.toArray(new String[res.size()]);
    }

    public Map<String, Collection<String>> getViewMap() throws KettleDatabaseException {
        return this.getViewMap((String)null);
    }

    public Map<String, Collection<String>> getViewMap(String schemanamein) throws KettleDatabaseException {
        if(!this.databaseMeta.supportsViews()) {
            return Collections.emptyMap();
        } else {
            String schemaname = schemanamein;
            if(schemanamein == null && this.databaseMeta.useSchemaNameForTableList()) {
                schemaname = this.environmentSubstitute(this.databaseMeta.getUsername()).toUpperCase();
            }

            Map<String, Collection<String>> viewMap = new HashMap();
            ResultSet allviews = null;

            try {
                String schema;
                String table;
                try {
                    for(allviews = this.getDatabaseMetaData().getTables((String)null, schemaname, (String)null, this.databaseMeta.getViewTypes()); allviews.next(); this.multimapPut(schema, table, viewMap)) {
                        String cat = "";

                        try {
                            cat = allviews.getString("TABLE_CAT");
                        } catch (Exception var18) {
                            if(this.log.isDebug()) {
                                this.log.logDebug("Error getting views for field TABLE_CAT (ignored): " + var18.toString());
                            }
                        }

                        schema = "";

                        try {
                            schema = allviews.getString("TABLE_SCHEM");
                        } catch (Exception var17) {
                            if(this.log.isDebug()) {
                                this.log.logDebug("Error getting views for field TABLE_SCHEM (ignored): " + var17.toString());
                            }
                        }

                        if(Utils.isEmpty(schema)) {
                            schema = cat;
                        }

                        table = allviews.getString("TABLE_NAME");
                        if(this.log.isRowLevel()) {
                            this.log.logRowlevel(this.toString(), new Object[]{"got view from meta-data: " + this.databaseMeta.getQuotedSchemaTableCombination(schema, table)});
                        }
                    }
                } catch (SQLException var19) {
                    throw new KettleDatabaseException("Error getting views from schema [" + schemaname + "]", var19);
                }
            } finally {
                try {
                    if(allviews != null) {
                        allviews.close();
                    }
                } catch (SQLException var16) {
                    throw new KettleDatabaseException("Error closing resultset after getting views from schema [" + schemaname + "]", var16);
                }

            }

            if(this.log.isDetailed()) {
                this.log.logDetailed("read :" + this.multimapSize(viewMap) + " views from db meta-data.");
            }

            return viewMap;
        }
    }

    public String[] getSynonyms() throws KettleDatabaseException {
        return this.getSynonyms(false);
    }

    public String[] getSynonyms(boolean includeSchema) throws KettleDatabaseException {
        return this.getSynonyms((String)null, includeSchema);
    }

    public String[] getSynonyms(String schemanamein, boolean includeSchema) throws KettleDatabaseException {
        Map<String, Collection<String>> synonymMap = this.getSynonymMap(schemanamein);
        List<String> res = new ArrayList();
        Iterator var5 = synonymMap.keySet().iterator();

        while(var5.hasNext()) {
            String schema = (String)var5.next();
            Collection<String> synonyms = (Collection)synonymMap.get(schema);
            Iterator var8 = synonyms.iterator();

            while(var8.hasNext()) {
                String synonym = (String)var8.next();
                if(includeSchema) {
                    res.add(this.databaseMeta.getQuotedSchemaTableCombination(schema, synonym));
                } else {
                    res.add(synonym);
                }
            }
        }

        return (String[])res.toArray(new String[res.size()]);
    }

    public Map<String, Collection<String>> getSynonymMap() throws KettleDatabaseException {
        return this.getSynonymMap((String)null);
    }

    public Map<String, Collection<String>> getSynonymMap(String schemanamein) throws KettleDatabaseException {
        if(!this.databaseMeta.supportsSynonyms()) {
            return Collections.emptyMap();
        } else {
            String schemaname = schemanamein;
            if(schemanamein == null && this.databaseMeta.useSchemaNameForTableList()) {
                schemaname = this.environmentSubstitute(this.databaseMeta.getUsername()).toUpperCase();
            }

            Map<String, Collection<String>> synonymMap = new HashMap();
            ResultSet alltables = null;

            try {
                String schema;
                String table;
                try {
                    for(alltables = this.getDatabaseMetaData().getTables((String)null, schemaname, (String)null, this.databaseMeta.getSynonymTypes()); alltables.next(); this.multimapPut(schema, table, synonymMap)) {
                        String cat = "";

                        try {
                            cat = alltables.getString("TABLE_CAT");
                        } catch (Exception var18) {
                            if(this.log.isDebug()) {
                                this.log.logDebug("Error getting synonyms for field TABLE_CAT (ignored): " + var18.toString());
                            }
                        }

                        schema = "";

                        try {
                            schema = alltables.getString("TABLE_SCHEM");
                        } catch (Exception var17) {
                            if(this.log.isDebug()) {
                                this.log.logDebug("Error getting synonyms for field TABLE_SCHEM (ignored): " + var17.toString());
                            }
                        }

                        if(Utils.isEmpty(schema)) {
                            schema = cat;
                        }

                        table = alltables.getString("TABLE_NAME");
                        if(this.log.isRowLevel()) {
                            this.log.logRowlevel(this.toString(), new Object[]{"got synonym from meta-data: " + this.databaseMeta.getQuotedSchemaTableCombination(schema, table)});
                        }
                    }
                } catch (SQLException var19) {
                    throw new KettleDatabaseException("Error getting synonyms from schema [" + schemaname + "]", var19);
                }
            } finally {
                try {
                    if(alltables != null) {
                        alltables.close();
                    }
                } catch (SQLException var16) {
                    throw new KettleDatabaseException("Error closing resultset after getting synonyms from schema [" + schemaname + "]", var16);
                }

            }

            if(this.log.isDetailed()) {
                this.log.logDetailed("read :" + this.multimapSize(synonymMap) + " synonyms from db meta-data.");
            }

            return synonymMap;
        }
    }

    private <K, V> void multimapPut(K key, V value, Map<K, Collection<V>> map) {
        Collection<V> valueCollection = (Collection)map.get(key);
        if(valueCollection == null) {
            valueCollection = new HashSet();
        }

        ((Collection)valueCollection).add(value);
        map.put(key, valueCollection);
    }

    private <K, V> int multimapSize(Map<K, Collection<V>> map) {
        int count = 0;

        Collection valueCollection;
        for(Iterator var3 = map.values().iterator(); var3.hasNext(); count += valueCollection.size()) {
            valueCollection = (Collection)var3.next();
        }

        return count;
    }

    public String[] getSchemas() throws KettleDatabaseException {
        ArrayList<String> catalogList = new ArrayList();
        ResultSet catalogResultSet = null;

        try {
            catalogResultSet = this.getDatabaseMetaData().getSchemas();

            while(catalogResultSet != null && catalogResultSet.next()) {
                catalogList.add(catalogResultSet.getString(1));
            }
        } catch (SQLException var11) {
            throw new KettleDatabaseException("Error getting schemas!", var11);
        } finally {
            try {
                if(catalogResultSet != null) {
                    catalogResultSet.close();
                }
            } catch (SQLException var10) {
                throw new KettleDatabaseException("Error closing resultset after getting schemas!", var10);
            }

        }

        if(this.log.isDetailed()) {
            this.log.logDetailed("read :" + catalogList.size() + " schemas from db meta-data.");
        }

        return (String[])catalogList.toArray(new String[catalogList.size()]);
    }

    public String[] getCatalogs() throws KettleDatabaseException {
        ArrayList<String> catalogList = new ArrayList();
        ResultSet catalogResultSet = null;

        try {
            catalogResultSet = this.getDatabaseMetaData().getCatalogs();

            while(catalogResultSet != null && catalogResultSet.next()) {
                catalogList.add(catalogResultSet.getString(1));
            }
        } catch (SQLException var11) {
            throw new KettleDatabaseException("Error getting catalogs!", var11);
        } finally {
            try {
                if(catalogResultSet != null) {
                    catalogResultSet.close();
                }
            } catch (SQLException var10) {
                throw new KettleDatabaseException("Error closing resultset after getting catalogs!", var10);
            }

        }

        if(this.log.isDetailed()) {
            this.log.logDetailed("read :" + catalogList.size() + " catalogs from db meta-data.");
        }

        return (String[])catalogList.toArray(new String[catalogList.size()]);
    }

    public String[] getProcedures() throws KettleDatabaseException {
        String sql = this.databaseMeta.getSQLListOfProcedures();
        if(sql != null) {
            List<Object[]> procs = this.getRows(sql, 1000);
            String[] str = new String[procs.size()];

            for(int i = 0; i < procs.size(); ++i) {
                str[i] = ((Object[])procs.get(i))[0].toString();
            }

            return str;
        } else {
            ResultSet rs = null;

            String[] var24;
            try {
                DatabaseMetaData dbmd = this.getDatabaseMetaData();
                rs = dbmd.getProcedures((String)null, (String)null, (String)null);
                List<Object[]> rows = this.getRows((ResultSet)rs, 0, (ProgressMonitorListener)null);
                String[] result = new String[rows.size()];

                for(int i = 0; i < rows.size(); ++i) {
                    Object[] row = (Object[])rows.get(i);
                    String procCatalog = this.rowMeta.getString(row, "PROCEDURE_CAT", (String)null);
                    String procSchema = this.rowMeta.getString(row, "PROCEDURE_SCHEM", (String)null);
                    String procName = this.rowMeta.getString(row, "PROCEDURE_NAME", "");
                    StringBuilder name = new StringBuilder("");
                    if(procCatalog != null) {
                        name.append(procCatalog).append(".");
                    }

                    if(procSchema != null) {
                        name.append(procSchema).append(".");
                    }

                    name.append(procName);
                    result[i] = name.toString();
                }

                var24 = result;
            } catch (Exception var19) {
                throw new KettleDatabaseException("Unable to get list of procedures from database meta-data: ", var19);
            } finally {
                if(rs != null) {
                    try {
                        rs.close();
                    } catch (Exception var18) {
                        ;
                    }
                }

            }

            return var24;
        }
    }

    public boolean isAutoCommit() {
        return this.commitsize <= 0;
    }

    public DatabaseMeta getDatabaseMeta() {
        return this.databaseMeta;
    }

    public void lockTables(String[] tableNames) throws KettleDatabaseException {
        if(!Utils.isEmpty(tableNames)) {
            String sql = this.databaseMeta.getSQLLockTables(tableNames);
            if(sql != null) {
                this.execStatements(sql);
            }

        }
    }

    public void unlockTables(String[] tableNames) throws KettleDatabaseException {
        if(!Utils.isEmpty(tableNames)) {
            String[] quotedTableNames = new String[tableNames.length];

            for(int i = 0; i < tableNames.length; ++i) {
                quotedTableNames[i] = this.databaseMeta.getQuotedSchemaTableCombination((String)null, tableNames[i]);
            }

            String sql = this.databaseMeta.getSQLUnlockTables(quotedTableNames);
            if(sql != null) {
                this.execStatement(sql);
            }

        }
    }

    public int getOpened() {
        return this.opened;
    }

    public synchronized void setOpened(int opened) {
        this.opened = opened;
    }

    public String getConnectionGroup() {
        return this.connectionGroup;
    }

    public void setConnectionGroup(String connectionGroup) {
        this.connectionGroup = connectionGroup;
    }

    public String getPartitionId() {
        return this.partitionId;
    }

    public void setPartitionId(String partitionId) {
        this.partitionId = partitionId;
    }

    public int getCopy() {
        return this.copy;
    }

    public synchronized void setCopy(int copy) {
        this.copy = copy;
    }

    public void copyVariablesFrom(VariableSpace space) {
        this.variables.copyVariablesFrom(space);
    }

    public String environmentSubstitute(String aString) {
        return this.variables.environmentSubstitute(aString);
    }

    public String[] environmentSubstitute(String[] aString) {
        return this.variables.environmentSubstitute(aString);
    }

    public String fieldSubstitute(String aString, RowMetaInterface rowMeta, Object[] rowData) throws KettleValueException {
        return this.variables.fieldSubstitute(aString, rowMeta, rowData);
    }

    public VariableSpace getParentVariableSpace() {
        return this.variables.getParentVariableSpace();
    }

    public void setParentVariableSpace(VariableSpace parent) {
        this.variables.setParentVariableSpace(parent);
    }

    public String getVariable(String variableName, String defaultValue) {
        return this.variables.getVariable(variableName, defaultValue);
    }

    public String getVariable(String variableName) {
        return this.variables.getVariable(variableName);
    }

    public boolean getBooleanValueOfVariable(String variableName, boolean defaultValue) {
        if(!Utils.isEmpty(variableName)) {
            String value = this.environmentSubstitute(variableName);
            if(!Utils.isEmpty(value)) {
                return ValueMetaBase.convertStringToBoolean(value).booleanValue();
            }
        }

        return defaultValue;
    }

    public void initializeVariablesFrom(VariableSpace parent) {
        this.variables.initializeVariablesFrom(parent);
    }

    public String[] listVariables() {
        return this.variables.listVariables();
    }

    public void setVariable(String variableName, String variableValue) {
        this.variables.setVariable(variableName, variableValue);
    }

    public void shareVariablesWith(VariableSpace space) {
        this.variables = space;
        if(space != this.databaseMeta) {
            this.databaseMeta.shareVariablesWith(space);
        }

    }

    public void injectVariables(Map<String, String> prop) {
        this.variables.injectVariables(prop);
    }

    public RowMetaAndData callProcedure(String[] arg, String[] argdir, int[] argtype, String resultname, int resulttype) throws KettleDatabaseException {
        try {
            boolean moreResults = this.cstmt.execute();
            RowMetaAndData ret = new RowMetaAndData();
            int pos = 1;
            ValueMetaInterface vMeta;
            if(resultname != null && resultname.length() != 0) {
                vMeta = new ValueMeta(resultname, resulttype);
                Object v = null;
                switch(resulttype) {
                    case 1:
                        v = new Double(this.cstmt.getDouble(pos));
                        break;
                    case 2:
                        v = this.cstmt.getString(pos);
                        break;
                    case 3:
                        if(this.databaseMeta.supportsTimeStampToDateConversion()) {
                            v = this.cstmt.getTimestamp(pos);
                        } else {
                            v = this.cstmt.getDate(pos);
                        }
                        break;
                    case 4:
                        v = Boolean.valueOf(this.cstmt.getBoolean(pos));
                        break;
                    case 5:
                        v = Long.valueOf(this.cstmt.getLong(pos));
                        break;
                    case 6:
                        v = this.cstmt.getBigDecimal(pos);
                    case 7:
                    default:
                        break;
                    case 8:
                        if(this.databaseMeta.supportsGetBlob()) {
                            Blob blob = this.cstmt.getBlob(pos);
                            if(blob != null) {
                                v = blob.getBytes(1L, (int)blob.length());
                            } else {
                                v = null;
                            }
                        } else {
                            v = this.cstmt.getBytes(pos);
                        }
                }

                ret.addValue(vMeta, v);
                ++pos;
            }

            for(int i = 0; i < arg.length; ++i) {
                if(argdir[i].equalsIgnoreCase("OUT") || argdir[i].equalsIgnoreCase("INOUT")) {
                    vMeta = ValueMetaFactory.createValueMeta(arg[i], argtype[i]);
                    Object v = null;
                    switch(argtype[i]) {
                        case 1:
                            v = new Double(this.cstmt.getDouble(pos + i));
                            break;
                        case 2:
                            v = this.cstmt.getString(pos + i);
                            break;
                        case 3:
                            if(this.databaseMeta.supportsTimeStampToDateConversion()) {
                                v = this.cstmt.getTimestamp(pos + i);
                            } else {
                                v = this.cstmt.getDate(pos + i);
                            }
                            break;
                        case 4:
                            v = Boolean.valueOf(this.cstmt.getBoolean(pos + i));
                            break;
                        case 5:
                            v = Long.valueOf(this.cstmt.getLong(pos + i));
                            break;
                        case 6:
                            v = this.cstmt.getBigDecimal(pos + i);
                        case 7:
                        default:
                            break;
                        case 8:
                            if(this.databaseMeta.supportsGetBlob()) {
                                Blob blob = this.cstmt.getBlob(pos + i);
                                if(blob != null) {
                                    v = blob.getBytes(1L, (int)blob.length());
                                } else {
                                    v = null;
                                }
                            } else {
                                v = this.cstmt.getBytes(pos + i);
                            }
                    }

                    ret.addValue(vMeta, v);
                }
            }

            vMeta = null;
            int updateCount = -1;

            do {
                ResultSet rs = null;

                try {
                    if(moreResults) {
                        rs = this.cstmt.getResultSet();
                    } else {
                        updateCount = this.cstmt.getUpdateCount();
                    }

                    moreResults = this.cstmt.getMoreResults();
                } finally {
                    if(rs != null) {
                        rs.close();
                        vMeta = null;
                    }

                }
            } while(moreResults || updateCount > -1);

            return ret;
        } catch (Exception var17) {
            throw new KettleDatabaseException("Unable to call procedure", var17);
        }
    }

    public void closeProcedureStatement() throws KettleDatabaseException {
        try {
            if(this.cstmt != null) {
                this.cstmt.close();
                this.cstmt = null;
            }

        } catch (SQLException var2) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.ErrorClosingCallableStatement", new String[0]), var2);
        }
    }

    public String getDDLCreationTable(String tableName, RowMetaInterface fields) throws KettleDatabaseException {
        this.databaseMeta.quoteReservedWords(fields);
        String quotedTk = this.databaseMeta.quoteField((String)null);
        String retval = this.getCreateTableStatement(tableName, fields, quotedTk, false, (String)null, true);
        return retval;
    }

    public String getDDLTruncateTable(String schema, String tablename) throws KettleDatabaseException {
        if(Utils.isEmpty(this.connectionGroup)) {
            String truncateStatement = this.databaseMeta.getTruncateTableStatement(schema, tablename);
            if(truncateStatement == null) {
                throw new KettleDatabaseException("Truncate table not supported by " + this.databaseMeta.getDatabaseInterface().getPluginName());
            } else {
                return truncateStatement;
            }
        } else {
            return "DELETE FROM " + this.databaseMeta.getQuotedSchemaTableCombination(schema, tablename);
        }
    }

    public String getSQLOutput(String schemaName, String tableName, RowMetaInterface fields, Object[] r, String dateFormat) throws KettleDatabaseException {
        StringBuilder ins = new StringBuilder(128);

        try {
            String schemaTable = this.databaseMeta.getQuotedSchemaTableCombination(schemaName, tableName);
            ins.append("INSERT INTO ").append(schemaTable).append('(');

            for(int i = 0; i < fields.size(); ++i) {
                if(i > 0) {
                    ins.append(", ");
                }

                String name = fields.getValueMeta(i).getName();
                ins.append(this.databaseMeta.quoteField(name));
            }

            ins.append(") VALUES (");
            SimpleDateFormat[] fieldDateFormatters = new SimpleDateFormat[fields.size()];

            for(int i = 0; i < fields.size(); ++i) {
                ValueMetaInterface valueMeta = fields.getValueMeta(i);
                Object valueData = r[i];
                if(i > 0) {
                    ins.append(",");
                }

                if(valueMeta.isNull(valueData)) {
                    ins.append("null");
                } else {
                    switch(valueMeta.getType()) {
                        case 2:
                        case 4:
                            String string = valueMeta.getString(valueData);
                            string = this.databaseMeta.quoteSQLString(string);
                            ins.append(string);
                            break;
                        case 3:
                            Date date = fields.getDate(r, i);
                            if(Utils.isEmpty(dateFormat)) {
                                if(this.databaseMeta.getDatabaseInterface() instanceof OracleDatabaseMeta) {
                                    if(fieldDateFormatters[i] == null) {
                                        fieldDateFormatters[i] = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                                    }

                                    ins.append("TO_DATE('").append(fieldDateFormatters[i].format(date)).append("', 'YYYY/MM/DD HH24:MI:SS')");
                                } else {
                                    ins.append("'" + fields.getString(r, i) + "'");
                                }
                            } else {
                                try {
                                    SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
                                    ins.append("'" + formatter.format(fields.getDate(r, i)) + "'");
                                } catch (Exception var15) {
                                    throw new KettleDatabaseException("Error : ", var15);
                                }
                            }
                            break;
                        default:
                            ins.append(fields.getString(r, i));
                    }
                }
            }

            ins.append(')');
        } catch (Exception var16) {
            throw new KettleDatabaseException(var16);
        }

        return ins.toString();
    }

    public Savepoint setSavepoint() throws KettleDatabaseException {
        try {
            return this.connection.setSavepoint();
        } catch (SQLException var2) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToSetSavepoint", new String[0]), var2);
        }
    }

    public Savepoint setSavepoint(String savePointName) throws KettleDatabaseException {
        try {
            return this.connection.setSavepoint(savePointName);
        } catch (SQLException var3) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToSetSavepointName", new String[]{savePointName}), var3);
        }
    }

    public void releaseSavepoint(Savepoint savepoint) throws KettleDatabaseException {
        try {
            this.connection.releaseSavepoint(savepoint);
        } catch (SQLException var3) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToReleaseSavepoint", new String[0]), var3);
        }
    }

    public void rollback(Savepoint savepoint) throws KettleDatabaseException {
        try {
            this.connection.rollback(savepoint);
        } catch (SQLException var3) {
            throw new KettleDatabaseException(BaseMessages.getString(PKG, "Database.Exception.UnableToRollbackToSavepoint", new String[0]), var3);
        }
    }

    public Object getParentObject() {
        return this.parentLoggingObject;
    }

    public String[] getPrimaryKeyColumnNames(String tablename) throws KettleDatabaseException {
        List<String> names = new ArrayList();
        ResultSet allkeys = null;

        try {
            allkeys = this.getDatabaseMetaData().getPrimaryKeys((String)null, (String)null, tablename);

            while(allkeys.next()) {
                String keyname = allkeys.getString("PK_NAME");
                String col_name = allkeys.getString("COLUMN_NAME");
                if(!names.contains(col_name)) {
                    names.add(col_name);
                }

                if(this.log.isRowLevel()) {
                    this.log.logRowlevel(this.toString(), new Object[]{"getting key : " + keyname + " on column " + col_name});
                }
            }
        } catch (SQLException var14) {
            this.log.logError(this.toString(), new Object[]{"Error getting primary keys columns from table [" + tablename + "]"});
        } finally {
            try {
                if(allkeys != null) {
                    allkeys.close();
                }
            } catch (SQLException var13) {
                throw new KettleDatabaseException("Error closing connection while searching primary keys in table [" + tablename + "]", var13);
            }

        }

        return (String[])names.toArray(new String[names.size()]);
    }

    public String[] getSequences() throws KettleDatabaseException {
        if(!this.databaseMeta.supportsSequences()) {
            throw new KettleDatabaseException("Sequences are only available for Oracle databases.");
        } else {
            String sql = this.databaseMeta.getSQLListOfSequences();
            if(sql == null) {
                return null;
            } else {
                List<Object[]> seqs = this.getRows(sql, 0);
                String[] str = new String[seqs.size()];

                for(int i = 0; i < seqs.size(); ++i) {
                    str[i] = ((Object[])seqs.get(i))[0].toString();
                }

                return str;
            }
        }
    }

    public String getFilename() {
        return null;
    }

    public String getLogChannelId() {
        return this.log.getLogChannelId();
    }

    public String getObjectName() {
        return this.databaseMeta.getName();
    }

    public String getObjectCopy() {
        return null;
    }

    public ObjectId getObjectId() {
        return this.databaseMeta.getObjectId();
    }

    public ObjectRevision getObjectRevision() {
        return this.databaseMeta.getObjectRevision();
    }

    public LoggingObjectType getObjectType() {
        return LoggingObjectType.DATABASE;
    }

    public LoggingObjectInterface getParent() {
        return this.parentLoggingObject;
    }

    public RepositoryDirectory getRepositoryDirectory() {
        return null;
    }

    public LogLevel getLogLevel() {
        return this.logLevel;
    }

    public void setLogLevel(LogLevel logLevel) {
        this.logLevel = logLevel;
        this.log.setLogLevel(logLevel);
    }

    public String getContainerObjectId() {
        return this.containerObjectId;
    }

    public void setContainerObjectId(String containerObjectId) {
        this.containerObjectId = containerObjectId;
    }

    public Date getRegistrationDate() {
        return null;
    }

    public int getNrExecutedCommits() {
        return this.nrExecutedCommits;
    }

    public void setNrExecutedCommits(int nrExecutedCommits) {
        this.nrExecutedCommits = nrExecutedCommits;
    }

    public Result execStatementsFromFile(String filename, boolean sendSinglestatement) throws KettleException {
        FileObject sqlFile = null;
        InputStream is = null;
        InputStreamReader bis = null;

        Result var10;
        try {
            if(Utils.isEmpty(filename)) {
                throw new KettleException("Filename is missing!");
            }

            sqlFile = KettleVFS.getFileObject(filename);
            if(!sqlFile.exists()) {
                throw new KettleException("We can not find file [" + filename + "]!");
            }

            is = KettleVFS.getInputStream(sqlFile);
            bis = new InputStreamReader(new BufferedInputStream(is, 500));
            StringBuilder lineStringBuilder = new StringBuilder(256);
            lineStringBuilder.setLength(0);
            BufferedReader buff = new BufferedReader(bis);
            String sLine = null;
            String sql = Const.CR;

            while((sLine = buff.readLine()) != null) {
                if(Utils.isEmpty(sLine)) {
                    sql = sql + Const.CR;
                } else {
                    sql = sql + Const.CR + sLine;
                }
            }

            if(sendSinglestatement) {
                var10 = this.execStatement(sql);
                return var10;
            }

            var10 = this.execStatements(sql);
        } catch (Exception var20) {
            throw new KettleException(var20);
        } finally {
            try {
                if(sqlFile != null) {
                    sqlFile.close();
                }

                if(is != null) {
                    is.close();
                }

                if(bis != null) {
                    bis.close();
                }
            } catch (Exception var19) {
                ;
            }

        }

        return var10;
    }

    public boolean isGatheringMetrics() {
        return this.log != null && this.log.isGatheringMetrics();
    }

    public void setGatheringMetrics(boolean gatheringMetrics) {
        if(this.log != null) {
            this.log.setGatheringMetrics(gatheringMetrics);
        }

    }

    public boolean isForcingSeparateLogging() {
        return this.log != null && this.log.isForcingSeparateLogging();
    }

    public void setForcingSeparateLogging(boolean forcingSeparateLogging) {
        if(this.log != null) {
            this.log.setForcingSeparateLogging(forcingSeparateLogging);
        }

    }

    static {
        try {
            valueMetaPluginClasses = ValueMetaFactory.getValueMetaPluginClasses();
            Collections.sort(valueMetaPluginClasses, new Comparator<ValueMetaInterface>() {
                public int compare(ValueMetaInterface o1, ValueMetaInterface o2) {
                    return Integer.valueOf(o1.getType()).compareTo(Integer.valueOf(o2.getType())) * -1;
                }
            });
        } catch (Exception var1) {
            throw new RuntimeException("Unable to get list of instantiated value meta plugin classes", var1);
        }
    }
}
