// Path: dalesbred/src/main/java/org/dalesbred/dialect/Dialect.java
// public abstract class Dialect {
// 
//     private static final String SERIALIZATION_FAILURE = "40001";
// 
//     private static final Logger log = LoggerFactory.getLogger(Dialect.class);
// 
//     public @NotNull Object valueToDatabase(@NotNull Object value) {
//         return value;
//     }
// 
//     public @NotNull <T extends Enum<T>, K> TypeConversionPair<Object,T> createNativeEnumConversions(@NotNull Class<T> enumType, @NotNull String typeName, @NotNull Function<T,K> keyFunction) {
//         throw new UnsupportedOperationException("native enums are not supported by " + getClass().getName());
//     }
// 
//     @Override
//     public @NotNull String toString() {
//         return getClass().getName();
//     }
// 
//     public static @NotNull Dialect detect(@NotNull DataSource dataSource) {
//         return detect(new DataSourceConnectionProvider(dataSource));
//     }
// 
//     public static @NotNull Dialect detect(@NotNull TransactionManager transactionManager) {
//         return transactionManager.withTransaction(new TransactionSettings(),
//                 tx -> detect(tx.getConnection()), new DefaultDialect());
//     }
// 
//     public static @NotNull Dialect detect(@NotNull ConnectionProvider connectionProvider) {
//         try {
//             Connection connection = connectionProvider.getConnection();
//             try {
//                 return detect(connection);
//             } finally {
//                 connectionProvider.releaseConnection(connection);
//             }
//         } catch (SQLException e) {
//             throw new DatabaseSQLException("Failed to auto-detect database dialect: " + e, e);
//         }
//     }
// 
//     public static @NotNull Dialect detect(@NotNull Connection connection) {
//         try {
//             String productName = connection.getMetaData().getDatabaseProductName();
// 
//             switch (productName) {
//                 case "PostgreSQL":
//                     log.debug("Automatically detected dialect PostgreSQL.");
//                     return new PostgreSQLDialect();
// 
//                 case "HSQL Database Engine":
//                     log.debug("Automatically detected dialect HSQLDB.");
//                     return new HsqldbDialect();
// 
//                 case "H2":
//                     log.debug("Automatically detected dialect H2.");
//                     return new H2Dialect();
// 
//                 case "MySQL":
//                     log.debug("Automatically detected dialect MySQL.");
//                     return new MySQLDialect();
// 
//                 case "Oracle":
//                     log.debug("Automatically detected dialect Oracle.");
//                     return new OracleDialect();
// 
//                 case "Microsoft SQL Server":
//                     log.debug("Automatically detected dialect SQLServer.");
//                     return new SQLServerDialect();
// 
//                 default:
//                     log.info("Could not detect dialect for product name '{}', falling back to default.", productName);
//                     return new DefaultDialect();
//             }
//         } catch (SQLException e) {
//             throw new DatabaseSQLException("Failed to auto-detect database dialect: " + e, e);
//         }
//     }
// 
//     public @NotNull DatabaseException convertException(@NotNull SQLException e) {
//         String sqlState = e.getSQLState();
//         if (sqlState == null)
//             return new DatabaseSQLException(e);
// 
//         if (sqlState.equals(SERIALIZATION_FAILURE))
//             return new TransactionSerializationException(e);
//         else if (sqlState.startsWith("40"))
//             return new TransactionRollbackException(e);
//         else
//             return new DatabaseSQLException(e);
//     }
// 
//     public void registerTypeConversions(@NotNull TypeConversionRegistry typeConversionRegistry) {
// 
//     }
// 
//     /**
//      * Bind object to {@link PreparedStatement}. Can be overridden by subclasses to
//      * implement custom argument binding.
//      *
//      * @param ps    statement to bind object to
//      * @param index index of the parameter
//      * @param value to bind
//      * @throws SQLException if something fails
//      */
//     public void bindArgument(@NotNull PreparedStatement ps, int index, @Nullable Object value) throws SQLException {
//         ArgumentBinder.bindArgument(ps, index, value);
//     }
// }
// 
// Path: dalesbred/src/main/java/org/dalesbred/internal/utils/Throwables.java
// public final class Throwables {
// 
//     private Throwables() { }
// 
//     public static @NotNull RuntimeException propagate(@NotNull Throwable e) {
//         if (e instanceof Error)
//             throw (Error) e;
//         else if (e instanceof RuntimeException)
//             return (RuntimeException) e;
//         else
//             return new WrappedCheckedException(e);
//     }
// 
//     public static @NotNull <T extends Exception> T propagate(@NotNull Throwable e, @NotNull Class<T> allowed) {
//         if (allowed.isInstance(e))
//             return allowed.cast(e);
//         else
//             throw propagate(e);
//     }
// }


import java.sql.Savepoint;
import static java.util.Objects.requireNonNull;
import org.dalesbred.dialect.Dialect;
import org.dalesbred.internal.utils.Throwables;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.SQLException;
/*
 * Copyright (c) 2017 Evident Solutions Oy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.dalesbred.transaction;




final class DefaultTransaction {

    private final @NotNull Connection connection;

    private static final @NotNull Logger log = LoggerFactory.getLogger(DefaultTransaction.class);

    DefaultTransaction(@NotNull Connection connection) {
        this.connection = requireNonNull(connection);
    }

    <T> T execute(@NotNull TransactionCallback<T> callback, @NotNull Dialect dialect) {
// Path: dalesbred/src/main/java/org/dalesbred/dialect/Dialect.java
// public abstract class Dialect {
// 
//     private static final String SERIALIZATION_FAILURE = "40001";
// 
//     private static final Logger log = LoggerFactory.getLogger(Dialect.class);
// 
//     public @NotNull Object valueToDatabase(@NotNull Object value) {
//         return value;
//     }
// 
//     public @NotNull <T extends Enum<T>, K> TypeConversionPair<Object,T> createNativeEnumConversions(@NotNull Class<T> enumType, @NotNull String typeName, @NotNull Function<T,K> keyFunction) {
//         throw new UnsupportedOperationException("native enums are not supported by " + getClass().getName());
//     }
// 
//     @Override
//     public @NotNull String toString() {
//         return getClass().getName();
//     }
// 
//     public static @NotNull Dialect detect(@NotNull DataSource dataSource) {
//         return detect(new DataSourceConnectionProvider(dataSource));
//     }
// 
//     public static @NotNull Dialect detect(@NotNull TransactionManager transactionManager) {
//         return transactionManager.withTransaction(new TransactionSettings(),
//                 tx -> detect(tx.getConnection()), new DefaultDialect());
//     }
// 
//     public static @NotNull Dialect detect(@NotNull ConnectionProvider connectionProvider) {
//         try {
//             Connection connection = connectionProvider.getConnection();
//             try {
//                 return detect(connection);
//             } finally {
//                 connectionProvider.releaseConnection(connection);
//             }
//         } catch (SQLException e) {
//             throw new DatabaseSQLException("Failed to auto-detect database dialect: " + e, e);
//         }
//     }
// 
//     public static @NotNull Dialect detect(@NotNull Connection connection) {
//         try {
//             String productName = connection.getMetaData().getDatabaseProductName();
// 
//             switch (productName) {
//                 case "PostgreSQL":
//                     log.debug("Automatically detected dialect PostgreSQL.");
//                     return new PostgreSQLDialect();
// 
//                 case "HSQL Database Engine":
//                     log.debug("Automatically detected dialect HSQLDB.");
//                     return new HsqldbDialect();
// 
//                 case "H2":
//                     log.debug("Automatically detected dialect H2.");
//                     return new H2Dialect();
// 
//                 case "MySQL":
//                     log.debug("Automatically detected dialect MySQL.");
//                     return new MySQLDialect();
// 
//                 case "Oracle":
//                     log.debug("Automatically detected dialect Oracle.");
//                     return new OracleDialect();
// 
//                 case "Microsoft SQL Server":
//                     log.debug("Automatically detected dialect SQLServer.");
//                     return new SQLServerDialect();
// 
//                 default:
//                     log.info("Could not detect dialect for product name '{}', falling back to default.", productName);
//                     return new DefaultDialect();
//             }
//         } catch (SQLException e) {
//             throw new DatabaseSQLException("Failed to auto-detect database dialect: " + e, e);
//         }
//     }
// 
//     public @NotNull DatabaseException convertException(@NotNull SQLException e) {
//         String sqlState = e.getSQLState();
//         if (sqlState == null)
//             return new DatabaseSQLException(e);
// 
//         if (sqlState.equals(SERIALIZATION_FAILURE))
//             return new TransactionSerializationException(e);
//         else if (sqlState.startsWith("40"))
//             return new TransactionRollbackException(e);
//         else
//             return new DatabaseSQLException(e);
//     }
// 
//     public void registerTypeConversions(@NotNull TypeConversionRegistry typeConversionRegistry) {
// 
//     }
// 
//     /**
//      * Bind object to {@link PreparedStatement}. Can be overridden by subclasses to
//      * implement custom argument binding.
//      *
//      * @param ps    statement to bind object to
//      * @param index index of the parameter
//      * @param value to bind
//      * @throws SQLException if something fails
//      */
//     public void bindArgument(@NotNull PreparedStatement ps, int index, @Nullable Object value) throws SQLException {
//         ArgumentBinder.bindArgument(ps, index, value);
//     }
// }
// 
// Path: dalesbred/src/main/java/org/dalesbred/internal/utils/Throwables.java
// public final class Throwables {
// 
//     private Throwables() { }
// 
//     public static @NotNull RuntimeException propagate(@NotNull Throwable e) {
//         if (e instanceof Error)
//             throw (Error) e;
//         else if (e instanceof RuntimeException)
//             return (RuntimeException) e;
//         else
//             return new WrappedCheckedException(e);
//     }
// 
//     public static @NotNull <T extends Exception> T propagate(@NotNull Throwable e, @NotNull Class<T> allowed) {
//         if (allowed.isInstance(e))
//             return allowed.cast(e);
//         else
//             throw propagate(e);
//     }
// }


// Path: dalesbred/src/main/java/org/dalesbred/transaction/DefaultTransaction.java
import java.sql.Savepoint;
import static java.util.Objects.requireNonNull;
import org.dalesbred.dialect.Dialect;
import org.dalesbred.internal.utils.Throwables;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.SQLException;

/*
 * Copyright (c) 2017 Evident Solutions Oy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.dalesbred.transaction;




final class DefaultTransaction {

    private final @NotNull Connection connection;

    private static final @NotNull Logger log = LoggerFactory.getLogger(DefaultTransaction.class);

    DefaultTransaction(@NotNull Connection connection) {
        this.connection = requireNonNull(connection);
    }

    <T> T execute(@NotNull TransactionCallback<T> callback, @NotNull Dialect dialect) {
        try {