public final class CallableResultSet1<T1> {

    private final List<Object> outs;
    private final Flowable<T1> results;

    public CallableResultSet1(List<Object> outs, Flowable<T1> results) {
        this.outs = outs;
        this.results = results;
    }

    public Flowable<T1> results() {
        return results;
    }

    public List<Object> outs() {
        return outs;
    }

} public final class CallableResultSet2<T1, T2> {

    private final List<Object> outs;
    private final Flowable<T1> results1;
    private final Flowable<T2> results2;

    public CallableResultSet2(List<Object> outs, Flowable<T1> results1, Flowable<T2> results2) {
        this.outs = outs;
        this.results1 = results1;
        this.results2 = results2;
    }

    public Flowable<T1> results1() {
        return results1;
    }

    public Flowable<T2> results2() {
        return results2;
    }

    public List<Object> outs() {
        return outs;
    }
} public final class CallableResultSet3<T1, T2, T3> {

    private final List<Object> outs;
    private final Flowable<T1> results1;
    private final Flowable<T2> results2;
    private final Flowable<T3> results3;

    public CallableResultSet3(List<Object> outs, Flowable<T1> query1, Flowable<T2> query2, Flowable<T3> query3) {
        this.outs = outs;
        this.results1 = query1;
        this.results2 = query2;
        this.results3 = query3;
    }

    public Flowable<T1> results1() {
        return results1;
    }

    public Flowable<T2> results2() {
        return results2;
    }

    public Flowable<T3> results3() {
        return results3;
    }

    public List<Object> outs() {
        return outs;
    }
} public final class CallableResultSet4<T1, T2, T3, T4> {

    private final List<Object> outs;
    private final Flowable<T1> results1;
    private final Flowable<T2> results2;
    private final Flowable<T3> results3;
    private final Flowable<T4> results4;

    public CallableResultSet4(List<Object> outs, Flowable<T1> query1, Flowable<T2> query2, Flowable<T3> query3,
            Flowable<T4> query4) {
        this.outs = outs;
        this.results1 = query1;
        this.results2 = query2;
        this.results3 = query3;
        this.results4 = query4;
    }

    public Flowable<T1> results1() {
        return results1;
    }

    public Flowable<T2> results2() {
        return results2;
    }

    public Flowable<T3> results3() {
        return results3;
    }

    public Flowable<T4> results4() {
        return results4;
    }

    public List<Object> outs() {
        return outs;
    }
} public final class CallableResultSetN {

    private final List<Object> outs;
    private final List<Flowable<?>> flowables;

    public CallableResultSetN(List<Object> outs, List<Flowable<?>> flowables) {
        this.outs = outs;
        this.flowables = flowables;
    }

    public List<Flowable<?>> results() {
        return flowables;
    }

    public Flowable<?> results(int index) {
        return flowables.get(index);
    }

    public List<Object> outs() {
        return outs;
    }
} public interface InParameterPlaceholder extends ParameterPlaceholder {
} public interface OutParameterPlaceholder extends ParameterPlaceholder {
    Type type();
} public interface ParameterPlaceholder {
} public class Tuple2<T1, T2> {

    private final T1 value1;
    private final T2 value2;

    /**
     * Constructor.
     * 
     * @param value1
     *            first element
     * @param value2
     *            second element
     */
    public Tuple2(T1 value1, T2 value2) {
        this.value1 = value1;
        this.value2 = value2;
    }

    /**
     * Returns a new instance.
     * 
     * @param r
     *            first element
     * @param s
     *            second element 
     * @param <R> type of first element
     * @param <S>
     *            type of second element
     * 
     * @return tuple
     */
    public static <R, S> Tuple2<R, S> create(R r, S s) {
        return new Tuple2<R, S>(r, s);
    }

    /**
     * Returns the first element of the tuple.
     * 
     * @return first element
     */
    public T1 value1() {
        return value1;
    }

    /**
     * Returns the first element of the tuple.
     * 
     * @return first element
     */
    public T1 _1() {
        return value1;
    }

    /**
     * Returns the 2nd element of the tuple.
     * 
     * @return second element
     */
    public T2 value2() {
        return value2;
    }

    /**
     * Returns the 2nd element of the tuple.
     * 
     * @return second element
     */
    public T2 _2() {
        return value2;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value1 == null) ? 0 : value1.hashCode());
        result = prime * result + ((value2 == null) ? 0 : value2.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Tuple2<?, ?> other = (Tuple2<?, ?>) obj;
        if (value1 == null) {
            if (other.value1 != null)
                return false;
        } else if (!value1.equals(other.value1))
            return false;
        if (value2 == null) {
            if (other.value2 != null)
                return false;
        } else if (!value2.equals(other.value2))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Tuple2 [value1=" + value1 + ", value2=" + value2 + "]";
    }

} public class Tuple3<T1, T2, T3> {

    private final T1 value1;
    private final T2 value2;
    private final T3 value3;

    /**
     * Constructor.
     * 
     * @param value1 first element 
     * @param value2 second element
     * @param value3 third element
     */
    public Tuple3(T1 value1, T2 value2, T3 value3) {
        this.value1 = value1;
        this.value2 = value2;
        this.value3 = value3;
    }
    
    public static <T1,T2,T3> Tuple3<T1,T2,T3> create(T1 value1, T2 value2, T3 value3) {
        return new Tuple3<T1,T2,T3>(value1, value2, value3);
    }

    public T1 value1() {
        return value1;
    }

    public T2 value2() {
        return value2;
    }

    public T3 value3() {
        return value3;
    }

    public T1 _1() {
        return value1;
    }

    public T2 _2() {
        return value2;
    }

    public T3 _3() {
        return value3;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value1 == null) ? 0 : value1.hashCode());
        result = prime * result + ((value2 == null) ? 0 : value2.hashCode());
        result = prime * result + ((value3 == null) ? 0 : value3.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Tuple3<?, ?, ?> other = (Tuple3<?, ?, ?>) obj;
        if (value1 == null) {
            if (other.value1 != null)
                return false;
        } else if (!value1.equals(other.value1))
            return false;
        if (value2 == null) {
            if (other.value2 != null)
                return false;
        } else if (!value2.equals(other.value2))
            return false;
        if (value3 == null) {
            if (other.value3 != null)
                return false;
        } else if (!value3.equals(other.value3))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Tuple3 [value1=" + value1 + ", value2=" + value2 + ", value3=" + value3 + "]";
    }

} public class Tuple4<T1, T2, T3, T4> {

    private final T1 value1;
    private final T2 value2;
    private final T3 value3;
    private final T4 value4;

    /**
     * Constructor.
     * 
     * @param value1 first element
     * @param value2 second element
     * @param value3 third element
     * @param value4 fourth element
     */
    public Tuple4(T1 value1, T2 value2, T3 value3, T4 value4) {
        this.value1 = value1;
        this.value2 = value2;
        this.value3 = value3;
        this.value4 = value4;
    }

    public static <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> create(T1 value1, T2 value2, T3 value3, T4 value4) {
        return new Tuple4<T1, T2, T3, T4>(value1, value2, value3, value4);
    }

    public T1 value1() {
        return value1;
    }

    public T2 value2() {
        return value2;
    }

    public T3 value3() {
        return value3;
    }

    public T4 value4() {
        return value4;
    }

    public T1 _1() {
        return value1;
    }

    public T2 _2() {
        return value2;
    }

    public T3 _3() {
        return value3;
    }

    public T4 _4() {
        return value4;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value1 == null) ? 0 : value1.hashCode());
        result = prime * result + ((value2 == null) ? 0 : value2.hashCode());
        result = prime * result + ((value3 == null) ? 0 : value3.hashCode());
        result = prime * result + ((value4 == null) ? 0 : value4.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Tuple4<?, ?, ?, ?> other = (Tuple4<?, ?, ?, ?>) obj;
        if (value1 == null) {
            if (other.value1 != null)
                return false;
        } else if (!value1.equals(other.value1))
            return false;
        if (value2 == null) {
            if (other.value2 != null)
                return false;
        } else if (!value2.equals(other.value2))
            return false;
        if (value3 == null) {
            if (other.value3 != null)
                return false;
        } else if (!value3.equals(other.value3))
            return false;
        if (value4 == null) {
            if (other.value4 != null)
                return false;
        } else if (!value4.equals(other.value4))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Tuple4 [value1=" + value1 + ", value2=" + value2 + ", value3=" + value3 + ", value4=" + value4 + "]";
    }

} public class TupleN<T> {

    private final List<T> list;

    /**
     * Constructor.
     * 
     * @param list
     *            values of the elements in the tuple
     */
    public TupleN(List<T> list) {
        this.list = list;
    }

    @SafeVarargs
    public static <T> TupleN<T> create(T... array) {
        return new TupleN<T>(Arrays.asList(array));
    }

    public List<T> values() {
        // defensive copy
        return new ArrayList<T>(list);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((list == null) ? 0 : list.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        TupleN<?> other = (TupleN<?>) obj;
        if (list == null) {
            if (other.list != null)
                return false;
        } else if (!list.equals(other.list))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "TupleN [values=" + list + "]";
    }

}
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import org.davidmoten.rx.jdbc.callable.CallableResultSet1;
import org.davidmoten.rx.jdbc.callable.CallableResultSet2;
import org.davidmoten.rx.jdbc.callable.CallableResultSet3;
import org.davidmoten.rx.jdbc.callable.CallableResultSet4;
import org.davidmoten.rx.jdbc.callable.CallableResultSetN;
import org.davidmoten.rx.jdbc.callable.internal.InParameterPlaceholder;
import org.davidmoten.rx.jdbc.callable.internal.OutParameterPlaceholder;
import org.davidmoten.rx.jdbc.callable.internal.ParameterPlaceholder;
import org.davidmoten.rx.jdbc.tuple.Tuple2;
import org.davidmoten.rx.jdbc.tuple.Tuple3;
import org.davidmoten.rx.jdbc.tuple.Tuple4;
import org.davidmoten.rx.jdbc.tuple.TupleN;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.davidmoten.guavamini.Lists;
import io.reactivex.Emitter;
import io.reactivex.Flowable;
import io.reactivex.Notification;
import io.reactivex.Single;
import io.reactivex.functions.BiConsumer;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
package org.davidmoten.rx.jdbc;





final class Call {

    private static final Logger log = LoggerFactory.getLogger(Call.class);

    private Call() {
        // prevent instantiation
    }

    /////////////////////////
    // No Parameters
    /////////////////////////

    static Flowable<Integer> createWithZeroOutParameters(Single<Connection> connection, String sql,
            Flowable<List<Object>> parameterGroups, List<ParameterPlaceholder> parameterPlaceholders) {
        return connection.toFlowable()
                .flatMap(con -> Call.<Integer>createWithParameters(con, sql, parameterGroups, parameterPlaceholders,
                        (stmt, parameters) -> createWithZeroOutParameters(stmt, parameters, parameterPlaceholders)))
                .dematerialize();
    }

    private static Single<Integer> createWithZeroOutParameters(NamedCallableStatement stmt, List<Object> parameters,
            List<ParameterPlaceholder> parameterPlaceholders) {
        return Single.fromCallable(() -> {
            CallableStatement st = stmt.stmt;
            execute(stmt, parameters, parameterPlaceholders, 0, st);
            return 1;
        });
    }

    /////////////////////////
    // One Out Parameter
    /////////////////////////

    static <T1> Flowable<Notification<T1>> createWithOneOutParameter(Single<Connection> connection, String sql,
            Flowable<List<Object>> parameterGroups, List<ParameterPlaceholder> parameterPlaceholders, Class<T1> cls) {
        return connection.toFlowable()
                .flatMap(con -> createWithParameters(con, sql, parameterGroups, parameterPlaceholders,
                        (stmt, parameters) -> createWithOneParameter(stmt, parameters, parameterPlaceholders, cls)));
    }

    private static <T> Single<T> createWithOneParameter(NamedCallableStatement stmt, List<Object> parameters,
            List<ParameterPlaceholder> parameterPlaceholders, Class<T> cls1) {
        return Single.fromCallable(() -> {
            CallableStatement st = stmt.stmt;
            List<PlaceAndType> outs = execute(stmt, parameters, parameterPlaceholders, 2, st);
            return Util.mapObject(st, cls1, outs.get(0).pos, outs.get(0).type);
        });
    }

    /////////////////////////
    // Two Out Parameters
    /////////////////////////

    static <T1, T2> Flowable<Notification<Tuple2<T1, T2>>> createWithTwoOutParameters(Single<Connection> connection,
            String sql, Flowable<List<Object>> parameterGroups, List<ParameterPlaceholder> parameterPlaceholders,
            Class<T1> cls1, Class<T2> cls2) {
        return connection.toFlowable().flatMap(con -> createWithParameters(con, sql, parameterGroups,
                parameterPlaceholders,
                (stmt, parameters) -> createWithTwoParameters(stmt, parameters, parameterPlaceholders, cls1, cls2)));
    }

    private static <T1, T2> Single<Tuple2<T1, T2>> createWithTwoParameters(NamedCallableStatement stmt,
            List<Object> parameters, List<ParameterPlaceholder> parameterPlaceholders, Class<T1> cls1, Class<T2> cls2) {
        return Single.fromCallable(() -> {
            CallableStatement st = stmt.stmt;
            List<PlaceAndType> outs = execute(stmt, parameters, parameterPlaceholders, 2, st);
            T1 o1 = Util.mapObject(st, cls1, outs.get(0).pos, outs.get(0).type);
            T2 o2 = Util.mapObject(st, cls2, outs.get(1).pos, outs.get(1).type);
            return Tuple2.create(o1, o2);
        });
    }

    private static final class PlaceAndType {
        final int pos;
        final Type type;

        PlaceAndType(int pos, Type type) {
            this.pos = pos;
            this.type = type;
        }

    }

    /////////////////////////
    // Three Out Parameters
    /////////////////////////

    static <T1, T2, T3> Flowable<Notification<Tuple3<T1, T2, T3>>> createWithThreeOutParameters(
            Single<Connection> connection, String sql, Flowable<List<Object>> parameterGroups,
            List<ParameterPlaceholder> parameterPlaceholders, Class<T1> cls1, Class<T2> cls2, Class<T3> cls3) {
        return connection.toFlowable()
                .flatMap(con -> createWithParameters(con, sql, parameterGroups, parameterPlaceholders,
                        (stmt, parameters) -> createWithThreeParameters(stmt, parameters, parameterPlaceholders, cls1,
                                cls2, cls3)));
    }

    private static <T1, T2, T3> Single<Tuple3<T1, T2, T3>> createWithThreeParameters(NamedCallableStatement stmt,
            List<Object> parameters, List<ParameterPlaceholder> parameterPlaceholders, Class<T1> cls1, Class<T2> cls2,
            Class<T3> cls3) {
        return Single.fromCallable(() -> {
            CallableStatement st = stmt.stmt;
            List<PlaceAndType> outs = execute(stmt, parameters, parameterPlaceholders, 3, st);
            T1 o1 = Util.mapObject(st, cls1, outs.get(0).pos, outs.get(0).type);
            T2 o2 = Util.mapObject(st, cls2, outs.get(1).pos, outs.get(1).type);
            T3 o3 = Util.mapObject(st, cls3, outs.get(2).pos, outs.get(2).type);
            return Tuple3.create(o1, o2, o3);
        });
    }

    /////////////////////////
    // Four Out Parameters
    /////////////////////////

    static <T1, T2, T3, T4> Flowable<Notification<Tuple4<T1, T2, T3, T4>>> createWithFourOutParameters(