<commit_before>package liquibase.statement;

import liquibase.Scope;
import liquibase.change.ColumnConfig;
import liquibase.changelog.ChangeSet;
import liquibase.database.Database;
import liquibase.database.PreparedStatementFactory;
import liquibase.database.core.PostgresDatabase;
import liquibase.datatype.DataTypeFactory;
import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.DatabaseException;
import liquibase.exception.LiquibaseException;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.listener.SqlListener;
import liquibase.logging.Logger;
import liquibase.resource.InputStreamList;
import liquibase.resource.ResourceAccessor;
import liquibase.util.JdbcUtil;
import liquibase.util.StreamUtil;
import liquibase.util.FilenameUtil;

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.*;
import java.util.*;

import static java.util.ResourceBundle.getBundle;
import liquibase.change.core.LoadDataChange;

public abstract class ExecutablePreparedStatementBase implements ExecutablePreparedStatement {

    private static ResourceBundle coreBundle = getBundle("liquibase/i18n/liquibase-core");

    protected Database database;
    private String catalogName;
    private String schemaName;
    private String tableName;
    private List<? extends ColumnConfig> columns;
    private ChangeSet changeSet;

    private Set<Closeable> closeables;

    private ResourceAccessor resourceAccessor;

    protected ExecutablePreparedStatementBase(Database database, String catalogName, String schemaName, String
            tableName, List<? extends ColumnConfig> columns, ChangeSet changeSet, ResourceAccessor resourceAccessor) {
        this.database = database;
        this.changeSet = changeSet;
        this.catalogName = catalogName;
        this.schemaName = schemaName;
        this.tableName = tableName;
        this.columns = columns;
        this.changeSet = changeSet;
        this.closeables = new HashSet<>();
        this.resourceAccessor = resourceAccessor;
    }

    private static InputStream createStream(InputStream in) {
        return (in instanceof BufferedInputStream) ? in : new BufferedInputStream(in);
    }

    @Override
    public void execute(PreparedStatementFactory factory) throws DatabaseException {

        // build the sql statement
        List<ColumnConfig> cols = new ArrayList<>(getColumns().size());

        String sql = generateSql(cols);
        for (SqlListener listener : Scope.getCurrentScope().getListeners(SqlListener.class)) {
            listener.writeSqlWillRun(sql);
        }
        Scope.getCurrentScope().getLog(getClass()).fine("Number of columns = " + cols.size());

        // create prepared statement
        PreparedStatement stmt = factory.create(sql);

        try {
            attachParams(cols, stmt);
            // trigger execution
            executePreparedStatement(stmt);
        } catch (SQLException e) {
            throw new DatabaseException(e);
        } finally {
            for (Closeable closeable : closeables) {
                try {
                    closeable.close();
                } catch (IOException ignore) {
                }
            }
            JdbcUtil.closeStatement(stmt);
        }
    }

    protected void executePreparedStatement(PreparedStatement stmt) throws SQLException {
        stmt.execute();
    }

    /**
     * Sets the list of bind variables for the execution of a DML statement
     * @param cols a list of columns with their designated values
     * @param stmt the PreparedStatement to which the values are to be attached
     * @throws SQLException if JDBC objects to a setting (non-existent bind number, wrong column type etc.)
     * @throws DatabaseException if an I/O error occurs during the read of LOB values
     */
    protected void attachParams(List<? extends ColumnConfig> cols, PreparedStatement stmt)
            throws SQLException, DatabaseException {
        int i = 1;  // index starts from 1
        for (ColumnConfig col : cols) {
            Scope.getCurrentScope().getLog(getClass()).fine("Applying column parameter = " + i + " for column " + col.getName());
            applyColumnParameter(stmt, i, col);
            i++;
        }
    }

    protected abstract String generateSql(List<ColumnConfig> cols);

    /**
     * Sets a single bind variable for a statement to its designated value
     * @param stmt the PreparedStatement whose parameter is to be set
     * @param i the parameter index (first bind variable is 1)
     * @param col a ColumnConfig with information about the column, its type, and the desired value
     * @throws SQLException if JDBC objects to a setting (non-existent bind number, wrong column type etc.)
     * @throws DatabaseException if an I/O error occurs during the read of LOB values
     */
    private void applyColumnParameter(PreparedStatement stmt, int i, ColumnConfig col) throws SQLException,
            DatabaseException {

        final Logger LOG = Scope.getCurrentScope().getLog(getClass());
        if (col.getValue() != null) {
            LOG.fine("value is string/UUID/blob = " + col.getValue());
            if (col.getType() != null && col.getType().equalsIgnoreCase(LoadDataChange.LOAD_DATA_TYPE.UUID.name())) {
                stmt.setObject(i, UUID.fromString(col.getValue()));
            } else if (col.getType() != null && col.getType().equalsIgnoreCase(LoadDataChange.LOAD_DATA_TYPE.OTHER.name())) {
                stmt.setObject(i, col.getValue(), Types.OTHER);
            } else if (LoadDataChange.LOAD_DATA_TYPE.BLOB.name().equalsIgnoreCase(col.getType())) {
                stmt.setBlob(i, new ByteArrayInputStream(Base64.getDecoder().decode(col.getValue())));
            } else if (!(database instanceof PostgresDatabase) && LoadDataChange.LOAD_DATA_TYPE.CLOB.name().equalsIgnoreCase(col.getType())) {
                // PostgreSQL's JDBC driver does not have the .createClob() call implemented yet
                Clob clobValue = stmt.getConnection().createClob();
                clobValue.setString(1, col.getValue());
                stmt.setClob(i, clobValue);
            } else {
                stmt.setString(i, col.getValue());<commit_msg>Fixed bug in handling of clobs for sqlite introduced in #1465<commit_after>package liquibase.statement;

import liquibase.Scope;
import liquibase.change.ColumnConfig;
import liquibase.changelog.ChangeSet;
import liquibase.database.Database;
import liquibase.database.PreparedStatementFactory;
import liquibase.database.core.PostgresDatabase;
import liquibase.database.core.SQLiteDatabase;
import liquibase.datatype.DataTypeFactory;
import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.DatabaseException;
import liquibase.exception.LiquibaseException;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.listener.SqlListener;
import liquibase.logging.Logger;
import liquibase.resource.InputStreamList;
import liquibase.resource.ResourceAccessor;
import liquibase.util.JdbcUtil;
import liquibase.util.StreamUtil;
import liquibase.util.FilenameUtil;

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.*;
import java.util.*;

import static java.util.ResourceBundle.getBundle;
import liquibase.change.core.LoadDataChange;

public abstract class ExecutablePreparedStatementBase implements ExecutablePreparedStatement {

    private static ResourceBundle coreBundle = getBundle("liquibase/i18n/liquibase-core");

    protected Database database;
    private String catalogName;
    private String schemaName;
    private String tableName;
    private List<? extends ColumnConfig> columns;
    private ChangeSet changeSet;

    private Set<Closeable> closeables;

    private ResourceAccessor resourceAccessor;

    protected ExecutablePreparedStatementBase(Database database, String catalogName, String schemaName, String
            tableName, List<? extends ColumnConfig> columns, ChangeSet changeSet, ResourceAccessor resourceAccessor) {
        this.database = database;
        this.changeSet = changeSet;
        this.catalogName = catalogName;
        this.schemaName = schemaName;
        this.tableName = tableName;
        this.columns = columns;
        this.changeSet = changeSet;
        this.closeables = new HashSet<>();
        this.resourceAccessor = resourceAccessor;
    }

    private static InputStream createStream(InputStream in) {
        return (in instanceof BufferedInputStream) ? in : new BufferedInputStream(in);
    }

    @Override
    public void execute(PreparedStatementFactory factory) throws DatabaseException {

        // build the sql statement
        List<ColumnConfig> cols = new ArrayList<>(getColumns().size());

        String sql = generateSql(cols);
        for (SqlListener listener : Scope.getCurrentScope().getListeners(SqlListener.class)) {
            listener.writeSqlWillRun(sql);
        }
        Scope.getCurrentScope().getLog(getClass()).fine("Number of columns = " + cols.size());

        // create prepared statement
        PreparedStatement stmt = factory.create(sql);

        try {
            attachParams(cols, stmt);
            // trigger execution
            executePreparedStatement(stmt);
        } catch (SQLException e) {
            throw new DatabaseException(e);
        } finally {
            for (Closeable closeable : closeables) {
                try {
                    closeable.close();
                } catch (IOException ignore) {
                }
            }
            JdbcUtil.closeStatement(stmt);
        }
    }

    protected void executePreparedStatement(PreparedStatement stmt) throws SQLException {
        stmt.execute();
    }

    /**
     * Sets the list of bind variables for the execution of a DML statement
     * @param cols a list of columns with their designated values
     * @param stmt the PreparedStatement to which the values are to be attached
     * @throws SQLException if JDBC objects to a setting (non-existent bind number, wrong column type etc.)
     * @throws DatabaseException if an I/O error occurs during the read of LOB values
     */
    protected void attachParams(List<? extends ColumnConfig> cols, PreparedStatement stmt)
            throws SQLException, DatabaseException {
        int i = 1;  // index starts from 1
        for (ColumnConfig col : cols) {
            Scope.getCurrentScope().getLog(getClass()).fine("Applying column parameter = " + i + " for column " + col.getName());
            applyColumnParameter(stmt, i, col);
            i++;
        }
    }

    protected abstract String generateSql(List<ColumnConfig> cols);

    /**
     * Sets a single bind variable for a statement to its designated value
     * @param stmt the PreparedStatement whose parameter is to be set
     * @param i the parameter index (first bind variable is 1)
     * @param col a ColumnConfig with information about the column, its type, and the desired value
     * @throws SQLException if JDBC objects to a setting (non-existent bind number, wrong column type etc.)
     * @throws DatabaseException if an I/O error occurs during the read of LOB values
     */
    private void applyColumnParameter(PreparedStatement stmt, int i, ColumnConfig col) throws SQLException,
            DatabaseException {

        final Logger LOG = Scope.getCurrentScope().getLog(getClass());
        if (col.getValue() != null) {
            LOG.fine("value is string/UUID/blob = " + col.getValue());
            if (col.getType() != null && col.getType().equalsIgnoreCase(LoadDataChange.LOAD_DATA_TYPE.UUID.name())) {
                stmt.setObject(i, UUID.fromString(col.getValue()));
            } else if (col.getType() != null && col.getType().equalsIgnoreCase(LoadDataChange.LOAD_DATA_TYPE.OTHER.name())) {
                stmt.setObject(i, col.getValue(), Types.OTHER);
            } else if (LoadDataChange.LOAD_DATA_TYPE.BLOB.name().equalsIgnoreCase(col.getType())) {
                stmt.setBlob(i, new ByteArrayInputStream(Base64.getDecoder().decode(col.getValue())));
            } else if (LoadDataChange.LOAD_DATA_TYPE.CLOB.name().equalsIgnoreCase(col.getType())) {
                try {
                    if (database instanceof PostgresDatabase || database instanceof SQLiteDatabase) {
                        // JDBC driver does not have the .createClob() call implemented yet
                        stmt.setString(i, col.getValue());
                    } else {
                        Clob clobValue = stmt.getConnection().createClob();
                        clobValue.setString(1, col.getValue());
                        stmt.setClob(i, clobValue);
                    }
                } catch (SQLFeatureNotSupportedException e) {
                    stmt.setString(i, col.getValue());
                }
            } else {
                stmt.setString(i, col.getValue());
{'fraction_non_alphanumeric': 0.08952572223080488, 'fraction_numerical': 0.001544878727019929, 'mean_word_length': 2.9328675577156744, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6991458', 'n_tokens_mistral': 3342, 'n_tokens_neox': 3208, 'n_words': 915}