// Path: src/main/java/com/github/pgasync/PgColumn.java
// public class PgColumn {
// 
//     private final int index;
//     private final String name;
//     private final Oid type;
// 
//     public PgColumn(int index, String name, Oid type) {
//         this.index = index;
//         this.name = name;
//         this.type = type;
//     }
// 
//     public Oid getType() {
//         return type;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public int at() {
//         return index;
//     }
// }
// 
// Path: src/main/java/com/github/pgasync/PgResultSet.java
// public class PgResultSet implements ResultSet {
// 
//     private final List<Row> rows;
//     private final Map<String, PgColumn> columnsByName;
//     private final List<PgColumn> orderedColumns;
//     private final int affectedRows;
// 
//     public PgResultSet(Map<String, PgColumn> columnsByName, List<PgColumn> orderedColumns, List<Row> rows, int affectedRows) {
//         this.columnsByName = columnsByName;
//         this.orderedColumns = orderedColumns;
//         this.rows = rows;
//         this.affectedRows = affectedRows;
//     }
// 
//     @Override
//     public Map<String, PgColumn> getColumnsByName() {
//         return columnsByName != null ? columnsByName : Map.of();
//     }
// 
//     @Override
//     public List<PgColumn> getOrderedColumns() {
//         return orderedColumns;
//     }
// 
//     @Override
//     public Iterator<Row> iterator() {
//         return rows != null ? rows.iterator() : Collections.emptyIterator();
//     }
// 
//     @Override
//     public Row at(int index) {
//         if (rows == null) {
//             throw new IndexOutOfBoundsException();
//         }
//         return rows.get(index);
//     }
// 
//     @Override
//     public int size() {
//         return rows != null ? rows.size() : 0;
//     }
// 
//     @Override
//     public int affectedRows() {
//         return affectedRows;
//     }
// 
// }


import com.github.pgasync.PgColumn;
import com.github.pgasync.PgResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
package com.pgasync;



/**
 * QueryExecutor submits SQL for execution.
 *
 * @author Antti Laisi
 */
public interface QueryExecutor {

    /**
     * Begins a transaction.
     */
    CompletableFuture<Transaction> begin();

    /**
     * Sends parameter less query script. The script may be multi query. Queries are separated with semicolons.
     * Accumulates fetched columns, rows and affected rows counts into memory and transforms them into a ResultSet when each {@link ResultSet} is fetched.
     * Completes returned {@link CompletableFuture} when the whole process of multiple {@link ResultSet}s fetching ends.
     *
     * @param sql Sql Script text.
     * @return CompletableFuture that is completed with a collection of fetched {@link ResultSet}s.
     */
    default CompletableFuture<Collection<ResultSet>> completeScript(String sql) {
        List<ResultSet> results = new ArrayList<>();
        class ResultSetAssembly {
            private Map<String, PgColumn> columnsByName;
            private PgColumn[] orderedColumns;
            private List<Row> rows;

            private void reset() {
                columnsByName = null;
                orderedColumns = null;
                rows = null;
            }
        }
        ResultSetAssembly assembly = new ResultSetAssembly();
        return script(
                (columnsByName, orderedColumns) -> {
                    assembly.columnsByName = columnsByName;
                    assembly.orderedColumns = orderedColumns;
                    assembly.rows = new ArrayList<>();
                },
                row -> assembly.rows.add(row),
                affected -> {
// Path: src/main/java/com/github/pgasync/PgColumn.java
// public class PgColumn {
// 
//     private final int index;
//     private final String name;
//     private final Oid type;
// 
//     public PgColumn(int index, String name, Oid type) {
//         this.index = index;
//         this.name = name;
//         this.type = type;
//     }
// 
//     public Oid getType() {
//         return type;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public int at() {
//         return index;
//     }
// }
// 
// Path: src/main/java/com/github/pgasync/PgResultSet.java
// public class PgResultSet implements ResultSet {
// 
//     private final List<Row> rows;
//     private final Map<String, PgColumn> columnsByName;
//     private final List<PgColumn> orderedColumns;
//     private final int affectedRows;
// 
//     public PgResultSet(Map<String, PgColumn> columnsByName, List<PgColumn> orderedColumns, List<Row> rows, int affectedRows) {
//         this.columnsByName = columnsByName;
//         this.orderedColumns = orderedColumns;
//         this.rows = rows;
//         this.affectedRows = affectedRows;
//     }
// 
//     @Override
//     public Map<String, PgColumn> getColumnsByName() {
//         return columnsByName != null ? columnsByName : Map.of();
//     }
// 
//     @Override
//     public List<PgColumn> getOrderedColumns() {
//         return orderedColumns;
//     }
// 
//     @Override
//     public Iterator<Row> iterator() {
//         return rows != null ? rows.iterator() : Collections.emptyIterator();
//     }
// 
//     @Override
//     public Row at(int index) {
//         if (rows == null) {
//             throw new IndexOutOfBoundsException();
//         }
//         return rows.get(index);
//     }
// 
//     @Override
//     public int size() {
//         return rows != null ? rows.size() : 0;
//     }
// 
//     @Override
//     public int affectedRows() {
//         return affectedRows;
//     }
// 
// }


// Path: src/main/java/com/pgasync/QueryExecutor.java
import com.github.pgasync.PgColumn;
import com.github.pgasync.PgResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

package com.pgasync;



/**
 * QueryExecutor submits SQL for execution.
 *
 * @author Antti Laisi
 */
public interface QueryExecutor {

    /**
     * Begins a transaction.
     */
    CompletableFuture<Transaction> begin();

    /**
     * Sends parameter less query script. The script may be multi query. Queries are separated with semicolons.
     * Accumulates fetched columns, rows and affected rows counts into memory and transforms them into a ResultSet when each {@link ResultSet} is fetched.
     * Completes returned {@link CompletableFuture} when the whole process of multiple {@link ResultSet}s fetching ends.
     *
     * @param sql Sql Script text.
     * @return CompletableFuture that is completed with a collection of fetched {@link ResultSet}s.
     */
    default CompletableFuture<Collection<ResultSet>> completeScript(String sql) {
        List<ResultSet> results = new ArrayList<>();
        class ResultSetAssembly {
            private Map<String, PgColumn> columnsByName;
            private PgColumn[] orderedColumns;
            private List<Row> rows;

            private void reset() {
                columnsByName = null;
                orderedColumns = null;
                rows = null;
            }
        }
        ResultSetAssembly assembly = new ResultSetAssembly();
        return script(
                (columnsByName, orderedColumns) -> {
                    assembly.columnsByName = columnsByName;
                    assembly.orderedColumns = orderedColumns;
                    assembly.rows = new ArrayList<>();
                },
                row -> assembly.rows.add(row),
                affected -> {
                    results.add(new PgResultSet(