/*

Derby - Class org.apache.derbyTesting.perf.clients.SingleRecordUpdateClient

Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

package org.apache.derbyTesting.perf.clients;

import java.io.ByteArrayInputStream;
import java.io.PrintStream;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Random;

/**
 * Client which updates a single record at a time on tables generated by
 * {@code SingleRecordFiller}. Each time the client's {@code doWork()} method
 * is called, it will pick one of the tables randomly, and update the text
 * column of one random record in that table.
 */
public class SingleRecordUpdateClient implements Client {

    private Connection conn;

    private final PreparedStatement[] pss;
    private final Random r;
    private final int tableSize;
    private final int dataType;
    private final boolean secondaryIndex;
    private final boolean noIndex;

    /**
     * Construct a new single-record update client.
     *
     * @param records the number of records in each table in the test
     * @param tables the number of tables in the test
     */
    public SingleRecordUpdateClient(int records, int tables) {
        this(records, tables, Types.VARCHAR, false, false);
    }

    /**
     * Construct a new single-record update client.
     *
     * @param records the number of records in each table in the test
     * @param tables the number of tables in the test
     */
    public SingleRecordUpdateClient(int records, int tables, int type,
                                    boolean secIndex, boolean nonIndexed) {
        tableSize = records;
        r = new Random();
        pss = new PreparedStatement[tables];
        dataType = type;
        if (secIndex && nonIndexed) {
            throw new IllegalArgumentException(
                "Cannot select on both secondary index and non-index column");
        }
        secondaryIndex = secIndex;
        noIndex = nonIndexed;
    }

    public void init(Connection c) throws SQLException {
        for (int i = 0; i < pss.length; i++) {
            String tableName =
                SingleRecordFiller.getTableName(tableSize, i, dataType,
                                                secondaryIndex, noIndex);
            String column = "ID";
            if (secondaryIndex) {
                column = "SEC";
            } else if (noIndex) {
                column = "NI";
            }
            String sql = "UPDATE " + tableName + " SET TEXT = ? WHERE " +
                    column + " = ?";
            pss[i] = c.prepareStatement(sql);
        }
        c.setAutoCommit(false);
        conn = c;
    }

    public void doWork() throws SQLException {
        PreparedStatement ps = pss[r.nextInt(pss.length)];
        int seed = r.nextInt();
        if (dataType == Types.VARCHAR) {
            ps.setString(1, SingleRecordFiller.randomString(seed));
        } else if (dataType == Types.BLOB) {
            byte[] bytes = SingleRecordFiller.randomBytes(seed);
            ps.setBinaryStream(1, new ByteArrayInputStream(bytes),
                               SingleRecordFiller.TEXT_SIZE);
        } else if (dataType == Types.CLOB) {
            String string = SingleRecordFiller.randomString(seed);
            ps.setCharacterStream(1, new StringReader(string),
                                  SingleRecordFiller.TEXT_SIZE);
        } else {
            throw new IllegalArgumentException();
        }
        ps.setInt(2, r.nextInt(tableSize));
        ps.executeUpdate();
        conn.commit();
    }

    public void printReport(PrintStream out) {}
    
}
