Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2015, Haiyang Li.
*
* Licensed 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 com.landawn.abacus.jdbc;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.cache.Cache;
import com.landawn.abacus.exception.UncheckedSQLException;
import com.landawn.abacus.jdbc.Jdbc.BiParametersSetter;
import com.landawn.abacus.jdbc.Jdbc.BiResultExtractor;
import com.landawn.abacus.jdbc.Jdbc.BiRowFilter;
import com.landawn.abacus.jdbc.Jdbc.BiRowMapper;
import com.landawn.abacus.jdbc.Jdbc.OutParam;
import com.landawn.abacus.jdbc.Jdbc.OutParamResult;
import com.landawn.abacus.jdbc.Jdbc.ResultExtractor;
import com.landawn.abacus.jdbc.Jdbc.RowExtractor;
import com.landawn.abacus.jdbc.Jdbc.RowFilter;
import com.landawn.abacus.jdbc.Jdbc.RowMapper;
import com.landawn.abacus.jdbc.SQLTransaction.CreatedBy;
import com.landawn.abacus.jdbc.dao.CrudDao;
import com.landawn.abacus.jdbc.dao.Dao;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.BeanInfo;
import com.landawn.abacus.parser.ParserUtil.PropInfo;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.AsyncExecutor;
import com.landawn.abacus.util.Charsets;
import com.landawn.abacus.util.CheckedStream;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.ContinuableFuture;
import com.landawn.abacus.util.DataSet;
import com.landawn.abacus.util.EntityId;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Fn.BiConsumers;
import com.landawn.abacus.util.Holder;
import com.landawn.abacus.util.IOUtil;
import com.landawn.abacus.util.ImmutableMap;
import com.landawn.abacus.util.InternalUtil;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.NamingPolicy;
import com.landawn.abacus.util.ObjectPool;
import com.landawn.abacus.util.ParsedSql;
import com.landawn.abacus.util.QueryUtil;
import com.landawn.abacus.util.RowDataSet;
import com.landawn.abacus.util.SQLBuilder;
import com.landawn.abacus.util.SQLBuilder.SP;
import com.landawn.abacus.util.SQLMapper;
import com.landawn.abacus.util.SQLOperation;
import com.landawn.abacus.util.Seid;
import com.landawn.abacus.util.Splitter;
import com.landawn.abacus.util.Strings;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.Tuple;
import com.landawn.abacus.util.Tuple.Tuple2;
import com.landawn.abacus.util.Tuple.Tuple3;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.function.TriConsumer;
import com.landawn.abacus.util.stream.EntryStream;
import com.landawn.abacus.util.stream.Stream;
import com.landawn.abacus.util.stream.Stream.StreamEx;
/**
*
* Performance Tips:
*
Avoid unnecessary/repeated database calls.
*
Only fetch the columns you need or update the columns you want.
*
Index is the key point in a lot of database performance issues.
*
*
*
* @see {@link com.landawn.abacus.condition .ConditionFactory}
* @see {@link com.landawn.abacus.condition.ConditionFactory.CF}
* @see {@link com.landawn.abacus.annotation.ReadOnly}
* @see {@link com.landawn.abacus.annotation.ReadOnlyId}
* @see {@link com.landawn.abacus.annotation.NonUpdatable}
* @see {@link com.landawn.abacus.annotation.Transient}
* @see {@link com.landawn.abacus.annotation.Table}
* @see {@link com.landawn.abacus.annotation.Column}
*
* @see Connection
* @see Statement
* @see PreparedStatement
* @see ResultSet
*/
@SuppressWarnings({ "java:S1192", "java:S6539" })
public final class JdbcUtil {
static final Logger logger = LoggerFactory.getLogger(JdbcUtil.class);
static final Logger sqlLogger = LoggerFactory.getLogger("com.landawn.abacus.SQL");
static final char CHAR_ZERO = 0;
public static final int DEFAULT_BATCH_SIZE = 200;
// static final int MAX_BATCH_SIZE = 1000;
public static final int DEFAULT_FETCH_SIZE_FOR_BIG_RESULT = 1000;
public static final int DEFAULT_FETCH_SIZE_FOR_STREAM = 100;
public static final Throwables.Function DEFAULT_SQL_EXTRACTOR = stmt -> {
Statement stmtToUse = stmt;
String clsName = stmtToUse.getClass().getName();
if ((clsName.startsWith("com.zaxxer.hikari") || clsName.startsWith("com.mchange.v2.c3p0")) && stmt.isWrapperFor(Statement.class)) {
stmtToUse = stmt.unwrap(Statement.class);
clsName = stmtToUse.getClass().getName();
}
if (clsName.startsWith("oracle.jdbc") && (stmtToUse instanceof oracle.jdbc.internal.OraclePreparedStatement)) { //NOSONAR
try {
return ((oracle.jdbc.internal.OraclePreparedStatement) stmtToUse).getOriginalSql();
} catch (final SQLException e) {
// ignore.
}
}
return stmtToUse.toString();
};
static Throwables.Function _sqlExtractor = DEFAULT_SQL_EXTRACTOR; //NOSONAR
// TODO is it right to do it?
// static final KeyedObjectPool> stmtPoolForSql = PoolFactory.createKeyedObjectPool(1000, 3000);
// ...
static final String CURRENT_DIR_PATH = "./";
static final AsyncExecutor asyncExecutor = new AsyncExecutor(//
N.max(64, IOUtil.CPU_CORES * 8), // coreThreadPoolSize
N.max(128, IOUtil.CPU_CORES * 16), // maxThreadPoolSize
180L, TimeUnit.SECONDS);
static final BiParametersSetter super PreparedQuery, ? super Object[]> DEFAULT_STMT_SETTER = (stmt, parameters) -> {
for (int i = 0, len = parameters.length; i < len; i++) {
stmt.setObject(i + 1, parameters[i]);
}
};
private static final Set sqlStateForTableNotExists = N.newHashSet();
static {
sqlStateForTableNotExists.add("42S02"); // for MySQCF.
sqlStateForTableNotExists.add("42P01"); // for PostgreSQCF.
sqlStateForTableNotExists.add("42501"); // for HSQLDB.
}
private JdbcUtil() {
// singleton
}
/**
* Retrieves the database product information from the given DataSource.
*
* @param ds The DataSource from which to retrieve the database product information.
* @return The database product information.
* @throws UncheckedSQLException If a SQL exception occurs while retrieving the database product information.
*/
public static DBProductInfo getDBProductInfo(final javax.sql.DataSource ds) throws UncheckedSQLException {
Connection conn = null;
try {
conn = ds.getConnection();
return getDBProductInfo(conn);
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
} finally {
JdbcUtil.releaseConnection(conn, ds);
}
}
/**
* Retrieves the database product information from the given connection.
*
* @param conn The connection to the database.
* @return The database product information.
* @throws UncheckedSQLException If a SQL exception occurs while retrieving the database product information.
*/
public static DBProductInfo getDBProductInfo(final Connection conn) throws UncheckedSQLException {
try {
final DatabaseMetaData metaData = conn.getMetaData();
final String dbProudctName = metaData.getDatabaseProductName();
final String dbProudctVersion = metaData.getDatabaseProductVersion();
final String upperCaseProductName = dbProudctName.toUpperCase();
DBVersion dbVersion = DBVersion.OTHERS;
if (upperCaseProductName.contains("H2")) {
dbVersion = DBVersion.H2;
} else if (upperCaseProductName.contains("HSQL")) {
dbVersion = DBVersion.HSQLDB;
} else if (upperCaseProductName.contains("MYSQL")) {
if (dbProudctVersion.startsWith("5.5")) {
dbVersion = DBVersion.MYSQL_5_5;
} else if (dbProudctVersion.startsWith("5.6")) {
dbVersion = DBVersion.MYSQL_5_6;
} else if (dbProudctVersion.startsWith("5.7")) {
dbVersion = DBVersion.MYSQL_5_7;
} else if (dbProudctVersion.startsWith("5.8")) {
dbVersion = DBVersion.MYSQL_5_8;
} else if (dbProudctVersion.startsWith("5.9")) {
dbVersion = DBVersion.MYSQL_5_9;
} else if (dbProudctVersion.startsWith("6")) {
dbVersion = DBVersion.MYSQL_6;
} else if (dbProudctVersion.startsWith("7")) {
dbVersion = DBVersion.MYSQL_7;
} else if (dbProudctVersion.startsWith("8")) {
dbVersion = DBVersion.MYSQL_8;
} else if (dbProudctVersion.startsWith("9")) {
dbVersion = DBVersion.MYSQL_9;
} else if (dbProudctVersion.startsWith("10")) {
dbVersion = DBVersion.MYSQL_10;
} else {
dbVersion = DBVersion.MYSQL_OTHERS;
}
} else if (upperCaseProductName.contains("POSTGRESQL")) {
if (dbProudctVersion.startsWith("9.2")) {
dbVersion = DBVersion.POSTGRESQL_9_2;
} else if (dbProudctVersion.startsWith("9.3")) {
dbVersion = DBVersion.POSTGRESQL_9_3;
} else if (dbProudctVersion.startsWith("9.4")) {
dbVersion = DBVersion.POSTGRESQL_9_4;
} else if (dbProudctVersion.startsWith("9.5")) {
dbVersion = DBVersion.POSTGRESQL_9_5;
} else if (dbProudctVersion.startsWith("10")) {
dbVersion = DBVersion.POSTGRESQL_10;
} else if (dbProudctVersion.startsWith("11")) {
dbVersion = DBVersion.POSTGRESQL_11;
} else if (dbProudctVersion.startsWith("12")) {
dbVersion = DBVersion.POSTGRESQL_12;
} else {
dbVersion = DBVersion.POSTGRESQL_OTHERS;
}
} else if (upperCaseProductName.contains("ORACLE")) {
dbVersion = DBVersion.ORACLE;
} else if (upperCaseProductName.contains("DB2")) {
dbVersion = DBVersion.DB2;
} else if (upperCaseProductName.contains("SQL SERVER")) {
dbVersion = DBVersion.SQL_SERVER;
}
return new DBProductInfo(dbProudctName, dbProudctName, dbVersion);
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
}
}
/**
* Creates a HikariCP DataSource with the specified database connection details.
*
* @param url The JDBC URL for the database connection.
* @param user The username for the database connection.
* @param password The password for the database connection.
* @return A DataSource configured with the specified connection details.
*/
public static javax.sql.DataSource createHikariDataSource(final String url, final String user, final String password) {
try {
final com.zaxxer.hikari.HikariConfig config = new com.zaxxer.hikari.HikariConfig();
config.setJdbcUrl(url);
config.setUsername(user);
config.setPassword(password);
return new com.zaxxer.hikari.HikariDataSource(config);
} catch (final Exception e) {
throw N.toRuntimeException(e);
}
}
/**
* Creates a C3P0 DataSource with the specified database connection details.
*
* @param url The JDBC URL for the database connection.
* @param user The username for the database connection.
* @param password The password for the database connection.
* @return A DataSource configured with the specified connection details.
*/
@Beta
public static javax.sql.DataSource createC3p0DataSource(final String url, final String user, final String password) {
try {
final com.mchange.v2.c3p0.ComboPooledDataSource cpds = new com.mchange.v2.c3p0.ComboPooledDataSource();
cpds.setJdbcUrl(url);
cpds.setUser(user);
cpds.setPassword(password);
return cpds;
} catch (final Exception e) {
throw N.toRuntimeException(e);
}
}
/**
* Creates a connection to the database using the specified URL, username, and password.
*
* @param url The JDBC URL for the database connection.
* @param user The username for the database connection.
* @param password The password for the database connection.
* @return A Connection object that represents a connection to the database.
* @throws UncheckedSQLException If a SQL exception occurs while creating the connection.
*/
public static Connection createConnection(final String url, final String user, final String password) throws UncheckedSQLException {
return createConnection(getDriverClasssByUrl(url), url, user, password);
}
/**
* Creates a connection to the database using the specified driver class, URL, username, and password.
*
* @param driverClass The fully qualified name of the JDBC driver class.
* @param url The JDBC URL for the database connection.
* @param user The username for the database connection.
* @param password The password for the database connection.
* @return A Connection object that represents a connection to the database.
* @throws UncheckedSQLException If a SQL exception occurs while creating the connection.
*/
public static Connection createConnection(final String driverClass, final String url, final String user, final String password)
throws UncheckedSQLException {
final Class extends Driver> cls = ClassUtil.forClass(driverClass);
return createConnection(cls, url, user, password);
}
/**
* Creates a connection to the database using the specified driver class, URL, username, and password.
*
* @param driverClass The fully qualified name of the JDBC driver class.
* @param url The JDBC URL for the database connection.
* @param user The username for the database connection.
* @param password The password for the database connection.
* @return A Connection object that represents a connection to the database.
* @throws UncheckedSQLException If a SQL exception occurs while creating the connection.
*/
public static Connection createConnection(final Class extends Driver> driverClass, final String url, final String user, final String password)
throws UncheckedSQLException {
try {
DriverManager.registerDriver(N.newInstance(driverClass));
return DriverManager.getConnection(url, user, password);
} catch (final SQLException e) {
throw new UncheckedSQLException("Failed to close create connection", e);
}
}
/**
* Gets the driver classs by url.
*
* @param url
* @return
*/
private static Class extends Driver> getDriverClasssByUrl(final String url) {
N.checkArgNotEmpty(url, s.url);
Class extends Driver> driverClass = null;
// jdbc:mysql://localhost:3306/abacustest
if (Strings.indexOfIgnoreCase(url, "mysql") >= 0) {
driverClass = ClassUtil.forClass("com.mysql.Driver");
// jdbc:postgresql://localhost:5432/abacustest
} else if (Strings.indexOfIgnoreCase(url, "postgresql") >= 0) {
driverClass = ClassUtil.forClass("org.postgresql.Driver");
// jdbc:h2:hsql://:/
} else if (Strings.indexOfIgnoreCase(url, "h2") >= 0) {
driverClass = ClassUtil.forClass("org.h2.Driver");
// jdbc:hsqldb:hsql://localhost/abacustest
} else if (Strings.indexOfIgnoreCase(url, "hsqldb") >= 0) {
driverClass = ClassUtil.forClass("org.hsqldb.JDBCDriver");
// url=jdbc:oracle:thin:@localhost:1521:abacustest
} else if (Strings.indexOfIgnoreCase(url, "oracle") >= 0) {
driverClass = ClassUtil.forClass("oracle.driver.OracleDriver");
// url=jdbc:sqlserver://localhost:1433;Database=abacustest
} else if (Strings.indexOfIgnoreCase(url, "sqlserver") >= 0) {
driverClass = ClassUtil.forClass("com.microsoft.sqlserver.SQLServerDriver");
// jdbc:db2://localhost:50000/abacustest
} else if (Strings.indexOfIgnoreCase(url, "db2") >= 0) {
driverClass = ClassUtil.forClass("com.ibm.db2.jcc.DB2Driver");
} else {
throw new IllegalArgumentException(
"Can not identity the driver class by url: " + url + ". Only mysql, postgresql, hsqldb, sqlserver, oracle and db2 are supported currently");
}
return driverClass;
}
private static boolean isInSpring = true;
static {
try {
isInSpring = ClassUtil.forClass("org.springframework.datasource.DataSourceUtils") != null;
} catch (final Throwable e) {
isInSpring = false;
}
}
/**
* Retrieves a connection from the specified DataSource.
* If Spring transaction management is enabled and a transaction is active,
* it will return the connection associated with the current transaction.
* Otherwise, it will return a new connection from the DataSource.
*
* @param ds The DataSource from which to retrieve the connection.
* @return A Connection object that represents a connection to the database.
* @throws UncheckedSQLException If a SQL exception occurs while retrieving the connection.
*/
public static Connection getConnection(final javax.sql.DataSource ds) throws UncheckedSQLException {
if (isInSpring && !isSpringTransactionalDisabled_TL.get()) { //NOSONAR
try {
return org.springframework.jdbc.datasource.DataSourceUtils.getConnection(ds);
} catch (final NoClassDefFoundError e) {
isInSpring = false;
try {
return ds.getConnection();
} catch (final SQLException e1) {
throw new UncheckedSQLException(e1);
}
}
} else {
try {
return ds.getConnection();
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
/**
* Releases the given connection back to the DataSource.
* If Spring transaction management is enabled and a transaction is active,
* it will release the connection associated with the current transaction.
* Otherwise, it will close the connection directly.
*
* @param conn The Connection to be released.
* @param ds The DataSource from which the connection was obtained.
*/
public static void releaseConnection(final Connection conn, final javax.sql.DataSource ds) {
if (conn == null) {
return;
}
if (isInSpring && ds != null && !isSpringTransactionalDisabled_TL.get()) { //NOSONAR
try {
org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(conn, ds);
} catch (final NoClassDefFoundError e) {
isInSpring = false;
JdbcUtil.closeQuietly(conn);
}
} else {
JdbcUtil.closeQuietly(conn);
}
}
/**
* Creates the close handler.
*
* @param conn
* @param ds
* @return
*/
static Runnable createCloseHandler(final Connection conn, final javax.sql.DataSource ds) {
return () -> releaseConnection(conn, ds);
}
/**
*
* @param rs
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final ResultSet rs) throws UncheckedSQLException {
if (rs != null) {
try {
rs.close();
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
/**
*
* @param rs
* @param closeStatement
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final ResultSet rs, final boolean closeStatement) throws UncheckedSQLException {
close(rs, closeStatement, false);
}
/**
*
* @param rs
* @param closeStatement
* @param closeConnection
* @throws IllegalArgumentException if {@code closeStatement = false} while {@code closeConnection = true}.
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final ResultSet rs, final boolean closeStatement, final boolean closeConnection)
throws IllegalArgumentException, UncheckedSQLException {
if (closeConnection && !closeStatement) {
throw new IllegalArgumentException("'closeStatement' can't be false while 'closeConnection' is true");
}
if (rs == null) {
return;
}
Connection conn = null;
Statement stmt = null;
try {
if (closeStatement) {
stmt = rs.getStatement();
}
if (closeConnection && stmt != null) {
conn = stmt.getConnection();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
} finally {
close(rs, stmt, conn);
}
}
/**
*
* @param stmt
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final Statement stmt) throws UncheckedSQLException {
if (stmt != null) {
try {
stmt.close();
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
/**
*
* @param conn
* @throws UncheckedSQLException the unchecked SQL exception
* @deprecated consider using {@link #releaseConnection(Connection, javax.sql.DataSource)}
*/
@Deprecated
public static void close(final Connection conn) throws UncheckedSQLException {
if (conn != null) {
try {
conn.close();
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
/**
*
* @param rs
* @param stmt
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final ResultSet rs, final Statement stmt) throws UncheckedSQLException {
try {
if (rs != null) {
rs.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (stmt != null) {
stmt.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e); //NOSONAR
}
}
}
/**
*
* @param stmt
* @param conn
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final Statement stmt, final Connection conn) throws UncheckedSQLException {
try {
if (stmt != null) {
stmt.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e); //NOSONAR
}
}
}
/**
*
* @param rs
* @param stmt
* @param conn
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void close(final ResultSet rs, final Statement stmt, final Connection conn) throws UncheckedSQLException {
try {
if (rs != null) {
rs.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (stmt != null) {
stmt.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e); //NOSONAR
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (final SQLException e) {
throw new UncheckedSQLException(e); //NOSONAR
}
}
}
}
/**
* Unconditionally close an {@code ResultSet}.
*
* Equivalent to {@link ResultSet#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param rs
*/
public static void closeQuietly(final ResultSet rs) {
closeQuietly(rs, null, null);
}
/**
*
* @param rs
* @param closeStatement
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static void closeQuietly(final ResultSet rs, final boolean closeStatement) throws UncheckedSQLException {
closeQuietly(rs, closeStatement, false);
}
/**
*
* @param rs
* @param closeStatement
* @param closeConnection
* @throws IllegalArgumentException if {@code closeStatement = false} while {@code closeConnection = true}.
*/
public static void closeQuietly(final ResultSet rs, final boolean closeStatement, final boolean closeConnection) throws IllegalArgumentException {
if (closeConnection && !closeStatement) {
throw new IllegalArgumentException("'closeStatement' can't be false while 'closeConnection' is true");
}
if (rs == null) {
return;
}
Connection conn = null;
Statement stmt = null;
try {
if (closeStatement) {
stmt = rs.getStatement();
}
if (closeConnection && stmt != null) {
conn = stmt.getConnection();
}
} catch (final SQLException e) {
logger.error("Failed to get Statement or Connection by ResultSet", e);
} finally {
closeQuietly(rs, stmt, conn);
}
}
/**
* Unconditionally close an {@code Statement}.
*
* Equivalent to {@link Statement#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param stmt
*/
public static void closeQuietly(final Statement stmt) {
closeQuietly(null, stmt, null);
}
/**
* Unconditionally close an {@code Connection}.
*
* Equivalent to {@link Connection#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param conn
* @deprecated consider using {@link #releaseConnection(Connection, javax.sql.DataSource)}
*/
@Deprecated
public static void closeQuietly(final Connection conn) {
closeQuietly(null, null, conn);
}
/**
* Unconditionally close the ResultSet, Statement.
*
* Equivalent to {@link ResultSet#close()}, {@link Statement#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param rs
* @param stmt
*/
public static void closeQuietly(final ResultSet rs, final Statement stmt) {
closeQuietly(rs, stmt, null);
}
/**
* Unconditionally close the Statement, Connection.
*
* Equivalent to {@link Statement#close()}, {@link Connection#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param stmt
* @param conn
*/
public static void closeQuietly(final Statement stmt, final Connection conn) {
closeQuietly(null, stmt, conn);
}
/**
* Unconditionally close the ResultSet, Statement, Connection.
*
* Equivalent to {@link ResultSet#close()}, {@link Statement#close()}, {@link Connection#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param rs
* @param stmt
* @param conn
*/
public static void closeQuietly(final ResultSet rs, final Statement stmt, final Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (final Exception e) {
logger.error("Failed to close ResultSet", e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (final Exception e) {
logger.error("Failed to close Statement", e);
}
}
if (conn != null) {
try {
conn.close();
} catch (final Exception e) {
logger.error("Failed to close Connection", e);
}
}
}
/**
* Skips the specified number of rows in the given ResultSet.
*
* @param rs The ResultSet to skip rows in.
* @param n The number of rows to skip.
* @return The number of rows actually skipped.
* @throws SQLException If a SQL exception occurs while skipping rows.
*/
public static int skip(final ResultSet rs, final int n) throws SQLException {
return skip(rs, (long) n);
}
private static final Set> resultSetClassNotSupportAbsolute = ConcurrentHashMap.newKeySet();
/**
* Skips the specified number of rows in the given ResultSet.
*
* @param rs The ResultSet to skip rows in.
* @param n The number of rows to skip.
* @return The number of rows actually skipped.
* @throws SQLException If a SQL exception occurs while skipping rows.
* @see ResultSet#absolute(int)
*/
public static int skip(final ResultSet rs, long n) throws SQLException {
if (n <= 0) {
return 0;
} else if (n == 1) {
return rs.next() ? 1 : 0;
} else {
final int currentRow = rs.getRow();
if ((n > Integer.MAX_VALUE) || (n > Integer.MAX_VALUE - currentRow
|| (resultSetClassNotSupportAbsolute.size() > 0 && resultSetClassNotSupportAbsolute.contains(rs.getClass())))) {
while (n-- > 0L && rs.next()) {
// continue.
}
} else {
try {
rs.absolute((int) n + currentRow);
} catch (final SQLException e) {
while (n-- > 0L && rs.next()) {
// continue.
}
resultSetClassNotSupportAbsolute.add(rs.getClass());
}
}
return rs.getRow() - currentRow;
}
}
/**
* Gets the column count.
*
* @param rs
* @return
* @throws SQLException
*/
public static int getColumnCount(final ResultSet rs) throws SQLException {
return rs.getMetaData().getColumnCount();
}
/**
* Gets the column name list.
*
* @param conn
* @param tableName
* @return
* @throws SQLException
*/
public static List getColumnNameList(final Connection conn, final String tableName) throws SQLException {
final String query = "SELECT * FROM " + tableName + " WHERE 1 > 2";
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = prepareStatement(conn, query);
rs = executeQuery(stmt);
final ResultSetMetaData metaData = rs.getMetaData();
final int columnCount = metaData.getColumnCount();
final List columnNameList = new ArrayList<>(columnCount);
for (int i = 1, n = columnCount + 1; i < n; i++) {
columnNameList.add(metaData.getColumnName(i));
}
return columnNameList;
} finally {
closeQuietly(rs, stmt);
}
}
/**
*
*
* @param rs
* @return
* @throws SQLException
*/
public static List getColumnLabelList(final ResultSet rs) throws SQLException {
final ResultSetMetaData metaData = rs.getMetaData();
final int columnCount = metaData.getColumnCount();
final List labelList = new ArrayList<>(columnCount);
for (int i = 1, n = columnCount + 1; i < n; i++) {
labelList.add(getColumnLabel(metaData, i));
}
return labelList;
}
/**
* Gets the column label.
*
* @param rsmd
* @param columnIndex
* @return
* @throws SQLException
*/
public static String getColumnLabel(final ResultSetMetaData rsmd, final int columnIndex) throws SQLException {
final String result = rsmd.getColumnLabel(columnIndex);
return Strings.isEmpty(result) ? rsmd.getColumnName(columnIndex) : result;
}
/**
* Returns the column index starts with from 1, not 0.
*
* @param resultSet
* @param columnName
* @return
* @throws UncheckedSQLException the unchecked SQL exception
*/
public static int getColumnIndex(final ResultSet resultSet, final String columnName) throws UncheckedSQLException {
try {
return getColumnIndex(resultSet.getMetaData(), columnName);
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
}
}
/**
* Returns the column index starts with from 1, not 0.
*
* @param rsmd
* @param columnName
* @return
* @throws SQLException
*/
public static int getColumnIndex(final ResultSetMetaData rsmd, final String columnName) throws SQLException {
final int columnCount = rsmd.getColumnCount();
String columnLabel = null;
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
columnLabel = rsmd.getColumnLabel(columnIndex);
if (columnLabel != null && columnLabel.equalsIgnoreCase(columnName)) {
return columnIndex;
}
columnLabel = rsmd.getColumnName(columnIndex);
if (columnLabel != null && columnLabel.equalsIgnoreCase(columnName)) {
return columnIndex;
}
}
return -1;
}
@FunctionalInterface
interface ColumnConverterByIndex {
Object apply(ResultSet rs, int columnIndex, Object columnValue) throws SQLException;
}
@FunctionalInterface
interface ColumnConverterByLabel {
Object apply(ResultSet rs, String columnLabel, Object columnValue) throws SQLException;
}
private static final Throwables.Function
*
* It's incorrect to use flag to identity the transaction should be committed or rolled back.
* Don't write below code:
*
*
* public void doSomethingA() {
* ...
* final SQLTransaction tranA = JdbcUtil.beginTransaction(dataSource1, isolation);
* boolean flagToCommit = false;
* try {
* // do your work with the conn...
* ...
* flagToCommit = true;
* } finally {
* if (flagToCommit) {
* tranA.commit();
* } else {
* tranA.rollbackIfNotCommitted();
* }
* }
* }
*
*
*
* @param dataSource
* @param isolationLevel
* @param isForUpdateOnly
* @return
* @throws UncheckedSQLException the unchecked SQL exception
* @see {@link #getConnection(javax.sql.DataSource)}
* @see {@link #releaseConnection(Connection, javax.sql.DataSource)}
* @see SQLExecutor#beginTransaction(IsolationLevel, boolean, JdbcSettings)
*/
public static SQLTransaction beginTransaction(final javax.sql.DataSource dataSource, final IsolationLevel isolationLevel, final boolean isForUpdateOnly)
throws UncheckedSQLException {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(isolationLevel, s.isolationLevel);
SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
if (tran == null) {
Connection conn = null;
boolean noException = false;
try { //NOSONAR
conn = getConnection(dataSource);
tran = new SQLTransaction(dataSource, conn, isolationLevel, CreatedBy.JDBC_UTIL, true); //NOSONAR
tran.incrementAndGetRef(isolationLevel, isForUpdateOnly);
noException = true;
} catch (final SQLException e) {
throw new UncheckedSQLException(e);
} finally {
if (!noException) {
releaseConnection(conn, dataSource);
}
}
logger.info("Create a new SQLTransaction(id={})", tran.id());
SQLTransaction.putTransaction(tran);
} else {
logger.info("Reusing the existing SQLTransaction(id={})", tran.id());
tran.incrementAndGetRef(isolationLevel, isForUpdateOnly);
}
return tran;
}
/**
* Executes the given command within a transaction for the specified DataSource.
* If the command completes successfully, the transaction is committed.
* If an exception occurs, the transaction is rolled back.
*
* @param The type of the result returned by the command.
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to begin the transaction.
* @param cmd The command to execute within the transaction.
* @return The result of the command execution.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static T callInTransaction(final javax.sql.DataSource dataSource, final Throwables.Callable cmd)
throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
final SQLTransaction tran = JdbcUtil.beginTransaction(dataSource);
T result = null;
try {
result = cmd.call();
tran.commit();
} finally {
tran.rollbackIfNotCommitted();
}
return result;
}
/**
* Executes the given command within a transaction for the specified DataSource.
* If the command completes successfully, the transaction is committed.
* If an exception occurs, the transaction is rolled back.
*
* @param The type of the result returned by the command.
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to begin the transaction.
* @param cmd The command to execute within the transaction.
* @return The result of the command execution.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static T callInTransaction(final javax.sql.DataSource dataSource, final Throwables.Function cmd)
throws E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
final SQLTransaction tran = JdbcUtil.beginTransaction(dataSource);
T result = null;
try {
result = cmd.apply(tran.connection());
tran.commit();
} finally {
tran.rollbackIfNotCommitted();
}
return result;
}
/**
* Executes the given command within a transaction for the specified DataSource.
* If the command completes successfully, the transaction is committed.
* If an exception occurs, the transaction is rolled back.
*
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to begin the transaction.
* @param cmd The command to execute within the transaction.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static void runInTransaction(final javax.sql.DataSource dataSource, final Throwables.Runnable cmd)
throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
final SQLTransaction tran = JdbcUtil.beginTransaction(dataSource);
try {
cmd.run();
tran.commit();
} finally {
tran.rollbackIfNotCommitted();
}
}
/**
* Executes the given command within a transaction for the specified DataSource.
* If the command completes successfully, the transaction is committed.
* If an exception occurs, the transaction is rolled back.
*
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to begin the transaction.
* @param cmd The command to execute within the transaction.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static void runInTransaction(final javax.sql.DataSource dataSource, final Throwables.Consumer cmd)
throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
final SQLTransaction tran = JdbcUtil.beginTransaction(dataSource);
try {
cmd.accept(tran.connection());
tran.commit();
} finally {
tran.rollbackIfNotCommitted();
}
}
/**
* Executes the given command outside of any started transaction for the specified DataSource.
* If a transaction is already started in current thread, a new connection which is not used to started transaction will be used to execute the command.
*
* @param The type of the result returned by the command.
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to execute the command.
* @param cmd The command to execute outside of any started transaction.
* @return The result of the command execution.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static T callNotInStartedTransaction(final javax.sql.DataSource dataSource, final Throwables.Callable cmd)
throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
if (isInSpring && !isSpringTransactionalDisabled_TL.get()) { //NOSONAR
JdbcUtil.disableSpringTransactional(true);
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
try {
if (tran == null) {
return cmd.call();
} else {
return tran.callNotInMe(cmd);
}
} finally {
JdbcUtil.disableSpringTransactional(false);
}
} else {
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
if (tran == null) {
return cmd.call();
} else {
return tran.callNotInMe(cmd);
}
}
}
/**
* Executes the given command outside of any started transaction for the specified DataSource.
* If a transaction is already started in current thread, a new connection which is not used to started transaction will be used to execute the command.
*
* @param The type of the result returned by the command.
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to execute the command.
* @param cmd The command to execute outside of any started transaction.
* @return The result of the command execution.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static T callNotInStartedTransaction(final javax.sql.DataSource dataSource,
final Throwables.Function cmd) throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
if (isInSpring && !isSpringTransactionalDisabled_TL.get()) { //NOSONAR
JdbcUtil.disableSpringTransactional(true);
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
try {
if (tran == null) {
return cmd.apply(dataSource);
} else {
return tran.callNotInMe(() -> cmd.apply(dataSource));
}
} finally {
JdbcUtil.disableSpringTransactional(false);
}
} else {
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
if (tran == null) {
return cmd.apply(dataSource);
} else {
return tran.callNotInMe(() -> cmd.apply(dataSource));
}
}
}
/**
* Executes the given command outside of any started transaction for the specified DataSource.
* If a transaction is already started in current thread, a new connection which is not used to started transaction will be used to execute the command.
*
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to execute the command.
* @param cmd The command to execute outside of any started transaction.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static void runNotInStartedTransaction(final javax.sql.DataSource dataSource, final Throwables.Runnable cmd)
throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
if (isInSpring && !isSpringTransactionalDisabled_TL.get()) { //NOSONAR
JdbcUtil.disableSpringTransactional(true);
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
try {
if (tran == null) {
cmd.run();
} else {
tran.runNotInMe(cmd);
}
} finally {
JdbcUtil.disableSpringTransactional(false);
}
} else {
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
if (tran == null) {
cmd.run();
} else {
tran.runNotInMe(cmd);
}
}
}
/**
* Executes the given command outside of any started transaction for the specified DataSource.
* If a transaction is already started in current thread, a new connection which is not used to started transaction will be used to execute the command.
*
* @param The type of exception that the command may throw.
* @param dataSource The DataSource for which to execute the command.
* @param cmd The command to execute outside of any started transaction.
* @throws IllegalArgumentException If the dataSource or cmd is {@code null}.
* @throws E If the command throws an exception.
*/
@Beta
public static void runNotInStartedTransaction(final javax.sql.DataSource dataSource,
final Throwables.Consumer cmd) throws IllegalArgumentException, E {
N.checkArgNotNull(dataSource, s.dataSource);
N.checkArgNotNull(cmd, s.cmd);
if (isInSpring && !isSpringTransactionalDisabled_TL.get()) { //NOSONAR
JdbcUtil.disableSpringTransactional(true);
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
try {
if (tran == null) {
cmd.accept(dataSource);
} else {
tran.runNotInMe(() -> cmd.accept(dataSource));
}
} finally {
JdbcUtil.disableSpringTransactional(false);
}
} else {
final SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
if (tran == null) {
cmd.accept(dataSource);
} else {
tran.runNotInMe(() -> cmd.accept(dataSource));
}
}
}
/**
* Gets the SQL operation.
*
* @param sql
* @return
*/
static SQLOperation getSQLOperation(final String sql) {
if (Strings.startsWithIgnoreCase(sql.trim(), "select ")) {
return SQLOperation.SELECT;
} else if (Strings.startsWithIgnoreCase(sql.trim(), "update ")) {
return SQLOperation.UPDATE;
} else if (Strings.startsWithIgnoreCase(sql.trim(), "insert ")) {
return SQLOperation.INSERT;
} else if (Strings.startsWithIgnoreCase(sql.trim(), "delete ")) {
return SQLOperation.DELETE;
} else if (Strings.startsWithIgnoreCase(sql.trim(), "merge ")) {
return SQLOperation.MERGE;
} else {
for (final SQLOperation so : SQLOperation.values()) {
if (Strings.startsWithIgnoreCase(sql.trim(), so.name())) {
return so;
}
}
}
return SQLOperation.UNKNOWN;
}
static final Throwables.Consumer stmtSetterForBigQueryResult = stmt -> {
// stmt.setFetchDirectionToForward().setFetchSize(JdbcUtil.DEFAULT_FETCH_SIZE_FOR_BIG_RESULT);
stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
if (stmt.getFetchSize() < JdbcUtil.DEFAULT_FETCH_SIZE_FOR_BIG_RESULT) {
stmt.setFetchSize(JdbcUtil.DEFAULT_FETCH_SIZE_FOR_BIG_RESULT);
}
};
static final Throwables.Consumer stmtSetterForStream = stmt -> {
stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
if (stmt.getFetchSize() < JdbcUtil.DEFAULT_FETCH_SIZE_FOR_STREAM) {
stmt.setFetchSize(JdbcUtil.DEFAULT_FETCH_SIZE_FOR_STREAM);
}
};
/**
* Prepares a SQL query using the provided DataSource and SQL string.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareQuery(tran.connection(), sql);
} else {
PreparedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareQuery(conn, sql).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a SQL query using the provided DataSource and SQL string.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @param autoGeneratedKeys whether auto-generated keys should be returned
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql, final boolean autoGeneratedKeys)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareQuery(tran.connection(), sql, autoGeneratedKeys);
} else {
PreparedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareQuery(conn, sql, autoGeneratedKeys).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a SQL query using the provided DataSource, SQL string, and column indexes for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @param returnColumnIndexes the column indexes for which auto-generated keys should be returned
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql, final int[] returnColumnIndexes)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotEmpty(returnColumnIndexes, s.returnColumnIndexes);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareQuery(tran.connection(), sql, returnColumnIndexes);
} else {
PreparedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareQuery(conn, sql, returnColumnIndexes).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a SQL query using the provided DataSource, SQL string, and column names for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @param returnColumnNames the column names for which auto-generated keys should be returned
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql, final String[] returnColumnNames)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotEmpty(returnColumnNames, s.returnColumnNames);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareQuery(tran.connection(), sql, returnColumnNames);
} else {
PreparedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareQuery(conn, sql, returnColumnNames).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a SQL query using the provided DataSource, SQL string, and a custom statement creator.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @param stmtCreator a function to create a PreparedStatement
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareQuery(tran.connection(), sql, stmtCreator);
} else {
PreparedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareQuery(conn, sql, stmtCreator).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a SQL query using the provided Connection and SQL string.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
return new PreparedQuery(prepareStatement(conn, sql));
}
/**
* Prepares a SQL query using the provided Connection and SQL string.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @param autoGeneratedKeys whether auto-generated keys should be returned
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql, final boolean autoGeneratedKeys)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
return new PreparedQuery(prepareStatement(conn, sql, autoGeneratedKeys));
}
/**
* Prepares a SQL query using the provided Connection, SQL string, and column indexes for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @param returnColumnIndexes the column indexes for which auto-generated keys should be returned
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the Connection, SQL string, or returnColumnIndexes is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql, final int[] returnColumnIndexes)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotEmpty(returnColumnIndexes, s.returnColumnIndexes);
return new PreparedQuery(prepareStatement(conn, sql, returnColumnIndexes));
}
/**
* Prepares a SQL query using the provided Connection, SQL string, and column names for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @param returnColumnNames the column names for which auto-generated keys should be returned
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the Connection, SQL string, or returnColumnNames is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql, final String[] returnColumnNames)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotEmpty(returnColumnNames, s.returnColumnNames);
return new PreparedQuery(prepareStatement(conn, sql, returnColumnNames));
}
/**
* Prepares a SQL query using the provided Connection and SQL string.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @param stmtCreator a function to create a PreparedStatement
* @return a PreparedQuery object representing the prepared SQL query
* @throws IllegalArgumentException if the Connection, SQL string, or stmtCreator is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
return new PreparedQuery(prepareStatement(conn, sql, stmtCreator));
}
/**
* Prepares a SQL query for a large result set using the provided DataSource and SQL string.
*
* This method sets the fetch direction to {@code FetchDirection.FORWARD} and the fetch size to {@code DEFAULT_FETCH_SIZE_FOR_BIG_RESULT=1000}.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @return a PreparedQuery object representing the prepared SQL query
* @throws SQLException if a SQL exception occurs while preparing the query
*/
@Beta
public static PreparedQuery prepareQueryForBigResult(final javax.sql.DataSource ds, final String sql) throws SQLException {
return prepareQuery(ds, sql).configStmt(stmtSetterForBigQueryResult);
}
/**
* Prepares a SQL query for a large result set using the provided Connection and SQL string.
*
* This method sets the fetch direction to {@code FetchDirection.FORWARD} and the fetch size to {@code DEFAULT_FETCH_SIZE_FOR_BIG_RESULT=1000}.
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @return a PreparedQuery object representing the prepared SQL query
* @throws SQLException if a SQL exception occurs while preparing the query
*/
@Beta
public static PreparedQuery prepareQueryForBigResult(final Connection conn, final String sql) throws SQLException {
return prepareQuery(conn, sql).configStmt(stmtSetterForBigQueryResult);
}
/**
* Prepares a named SQL query using the provided DataSource and named SQL string.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(namedSql, s.namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource and named SQL string.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param autoGeneratedKeys whether auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql, final boolean autoGeneratedKeys)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(namedSql, s.namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, autoGeneratedKeys);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, autoGeneratedKeys).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, named SQL string, and column indexes for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnIndexes the column indexes for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource, named SQL string, or returnColumnIndexes is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql, final int[] returnColumnIndexes)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnIndexes, s.returnColumnIndexes);
final SQLTransaction tran = getTransaction(ds, namedSql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, returnColumnIndexes);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, returnColumnIndexes).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, named SQL string, and column names for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnNames the column names for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource, named SQL string, or returnColumnNames is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql, final String[] returnColumnNames)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnNames, s.returnColumnNames);
final SQLTransaction tran = getTransaction(ds, namedSql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, returnColumnNames);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, returnColumnNames).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, named SQL string, and a custom statement creator.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param stmtCreator a function to create a PreparedStatement
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource, named SQL string, or stmtCreator is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(namedSql, s.namedSql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
final SQLTransaction tran = getTransaction(ds, namedSql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, stmtCreator);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, stmtCreator).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided Connection and named SQL string.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(namedSql, s.namedSql);
final ParsedSql parsedSql = parseNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, parsedSql), parsedSql);
}
/**
* Prepares a named SQL query using the provided Connection, named SQL string, and a flag for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param autoGeneratedKeys whether auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql, final boolean autoGeneratedKeys)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(namedSql, s.namedSql);
final ParsedSql parsedSql = parseNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, parsedSql, autoGeneratedKeys), parsedSql);
}
/**
* Prepares a named SQL query using the provided Connection, named SQL string, and column indexes for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnIndexes the column indexes for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection, named SQL string, or returnColumnIndexes is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql, final int[] returnColumnIndexes)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnIndexes, s.returnColumnIndexes);
final ParsedSql parsedSql = parseNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, parsedSql, returnColumnIndexes), parsedSql);
}
/**
* Prepares a named SQL query using the provided Connection, named SQL string, and column names for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnNames the column names for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection, named SQL string, or returnColumnNames is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql, final String[] returnColumnNames)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnNames, s.returnColumnNames);
final ParsedSql parsedSql = parseNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, parsedSql, returnColumnNames), parsedSql);
}
/**
* Prepares a named SQL query using the provided Connection and named SQL string.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param stmtCreator a function to create a PreparedStatement
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection, named SQL string, or stmtCreator is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(namedSql, s.namedSql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
final ParsedSql parsedSql = parseNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, parsedSql, stmtCreator), parsedSql);
}
/**
* Prepares a named SQL query using the provided DataSource and ParsedSql object.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final ParsedSql namedSql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotNull(namedSql, s.namedSql);
validateNamedSql(namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql.getParameterizedSql(), CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, ParsedSql object, and a flag for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param autoGeneratedKeys whether auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final ParsedSql namedSql, final boolean autoGeneratedKeys)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotNull(namedSql, s.namedSql);
validateNamedSql(namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql.getParameterizedSql(), CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, autoGeneratedKeys);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, autoGeneratedKeys).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, ParsedSql object, and column indexes for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnIndexes the column indexes for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource, named SQL string, or returnColumnIndexes is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final ParsedSql namedSql, final int[] returnColumnIndexes)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotNull(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnIndexes, s.returnColumnIndexes);
validateNamedSql(namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql.getParameterizedSql(), CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, returnColumnIndexes);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, returnColumnIndexes).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, ParsedSql object, and column names for auto-generated keys.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnNames the column names for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource, named SQL string, or returnColumnNames is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final ParsedSql namedSql, final String[] returnColumnNames)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotNull(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnNames, s.returnColumnNames);
validateNamedSql(namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql.getParameterizedSql(), CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, returnColumnNames);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, returnColumnNames).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided DataSource, ParsedSql object, and a custom statement creator.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param stmtCreator a function to create a PreparedStatement
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the DataSource, named SQL string, or stmtCreator is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final ParsedSql namedSql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotNull(namedSql, s.namedSql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
validateNamedSql(namedSql);
final SQLTransaction tran = getTransaction(ds, namedSql.getParameterizedSql(), CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareNamedQuery(tran.connection(), namedSql, stmtCreator);
} else {
NamedQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareNamedQuery(conn, namedSql, stmtCreator).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a named SQL query using the provided Connection and ParsedSql object.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final ParsedSql namedSql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotNull(namedSql, s.namedSql);
validateNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, namedSql), namedSql);
}
/**
* Prepares a named SQL query using the provided Connection, ParsedSql object, and a flag for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param autoGeneratedKeys whether auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection or named SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final ParsedSql namedSql, final boolean autoGeneratedKeys)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotNull(namedSql, s.namedSql);
validateNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, namedSql, autoGeneratedKeys), namedSql);
}
/**
* Prepares a named SQL query using the provided Connection, ParsedSql object, and column indexes for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnIndexes the column indexes for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection, named SQL string, or returnColumnIndexes is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final ParsedSql namedSql, final int[] returnColumnIndexes)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotNull(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnIndexes, s.returnColumnIndexes);
validateNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, namedSql, returnColumnIndexes), namedSql);
}
/**
* Prepares a named SQL query using the provided Connection, ParsedSql object, and column names for auto-generated keys.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnNames the column names for which auto-generated keys should be returned
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection, named SQL string, or returnColumnNames is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final ParsedSql namedSql, final String[] returnColumnNames)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotNull(namedSql, s.namedSql);
N.checkArgNotEmpty(returnColumnNames, s.returnColumnNames);
validateNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, namedSql, returnColumnNames), namedSql);
}
/**
* Prepares a named SQL query using the provided Connection and ParsedSql object.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param stmtCreator a function to create a PreparedStatement
* @return a NamedQuery object representing the prepared named SQL query
* @throws IllegalArgumentException if the Connection, named SQL string, or stmtCreator is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final ParsedSql namedSql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotNull(namedSql, s.namedSql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
validateNamedSql(namedSql);
return new NamedQuery(prepareStatement(conn, namedSql, stmtCreator), namedSql);
}
/**
* Prepares a named SQL query for a big result set using the provided DataSource and named SQL string.
*
* This method configures the fetch direction to {@code FetchDirection.FORWARD} and sets the fetch size to {@code DEFAULT_FETCH_SIZE_FOR_BIG_RESULT=1000}.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare
* @return a NamedQuery object representing the prepared named SQL query
* @throws SQLException if a SQL exception occurs while preparing the query
*/
@Beta
public static NamedQuery prepareNamedQueryForBigResult(final javax.sql.DataSource ds, final String namedSql) throws SQLException {
return prepareNamedQuery(ds, namedSql).configStmt(stmtSetterForBigQueryResult);
}
/**
* Prepares a named SQL query for a big result set using the provided DataSource and ParsedSql object.
*
* This method configures the fetch direction to {@code FetchDirection.FORWARD} and sets the fetch size to {@code DEFAULT_FETCH_SIZE_FOR_BIG_RESULT=1000}.
*
*
* @param ds the DataSource to use for the query
* @param namedSql the named SQL string to prepare, for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return a NamedQuery object representing the prepared named SQL query
* @throws SQLException if a SQL exception occurs while preparing the query
*/
@Beta
public static NamedQuery prepareNamedQueryForBigResult(final javax.sql.DataSource ds, final ParsedSql namedSql) throws SQLException {
return prepareNamedQuery(ds, namedSql).configStmt(stmtSetterForBigQueryResult);
}
/**
* Prepares a named SQL query for a big result set using the provided Connection and named SQL string.
*
* This method configures the fetch direction to {@code FetchDirection.FORWARD} and sets the fetch size to {@code DEFAULT_FETCH_SIZE_FOR_BIG_RESULT=1000}.
*
*
* @param conn the Connection to use for the query
* @param namedSql the named SQL string to prepare
* @return a NamedQuery object representing the prepared named SQL query
* @throws SQLException if a SQL exception occurs while preparing the query
*/
@Beta
public static NamedQuery prepareNamedQueryForBigResult(final Connection conn, final String namedSql) throws SQLException {
return prepareNamedQuery(conn, namedSql).configStmt(stmtSetterForBigQueryResult);
}
/**
* Prepares a callable SQL query using the provided DataSource and SQL Stored Procedure.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @return a CallableQuery object representing the prepared callable SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static CallableQuery prepareCallableQuery(final javax.sql.DataSource ds, final String sql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareCallableQuery(tran.connection(), sql);
} else {
CallableQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareCallableQuery(conn, sql).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a callable SQL query using the provided DataSource and SQL Stored Procedure.
*
* If this method is called where a transaction is started by {@code JdbcUtil.beginTransaction}
* or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the Transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to prepare
* @return a CallableQuery object representing the prepared callable SQL query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static CallableQuery prepareCallableQuery(final javax.sql.DataSource ds, final String sql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return prepareCallableQuery(tran.connection(), sql, stmtCreator);
} else {
CallableQuery result = null;
Connection conn = null;
try {
conn = getConnection(ds);
result = prepareCallableQuery(conn, sql, stmtCreator).onClose(createCloseHandler(conn, ds));
} finally {
if (result == null) {
releaseConnection(conn, ds);
}
}
return result;
}
}
/**
* Prepares a callable SQL query using the provided Connection and SQL Stored Procedure.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @return a CallableQuery object representing the prepared callable SQL query
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static CallableQuery prepareCallableQuery(final Connection conn, final String sql) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
return new CallableQuery(prepareCallable(conn, sql));
}
/**
* Prepares a callable SQL query using the provided Connection and SQL Stored Procedure.
*
* This method does not close the provided Connection after the query is executed.
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to prepare
* @param stmtCreator a function to create a CallableStatement
* @return a CallableQuery object representing the prepared callable SQL query
* @throws IllegalArgumentException if the Connection, SQL string, or stmtCreator is {@code null} or empty
* @throws SQLException if a SQL exception occurs while preparing the query
*/
public static CallableQuery prepareCallableQuery(final Connection conn, final String sql,
final Throwables.BiFunction stmtCreator) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgNotNull(stmtCreator, s.stmtCreator);
return new CallableQuery(prepareCallable(conn, sql, stmtCreator));
}
static PreparedStatement prepareStatement(final Connection conn, final String sql) throws SQLException {
logSql(sql);
return conn.prepareStatement(sql);
}
static PreparedStatement prepareStatement(final Connection conn, final String sql, final boolean autoGeneratedKeys) throws SQLException {
logSql(sql);
return conn.prepareStatement(sql, autoGeneratedKeys ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);
}
static PreparedStatement prepareStatement(final Connection conn, final String sql, final int[] returnColumnIndexes) throws SQLException {
logSql(sql);
return conn.prepareStatement(sql, returnColumnIndexes);
}
static PreparedStatement prepareStatement(final Connection conn, final String sql, final String[] returnColumnNames) throws SQLException {
logSql(sql);
return conn.prepareStatement(sql, returnColumnNames);
}
static PreparedStatement prepareStatement(final Connection conn, final String sql, final int resultSetType, final int resultSetConcurrency)
throws SQLException {
logSql(sql);
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
static PreparedStatement prepareStatement(final Connection conn, final String sql, final int resultSetType, final int resultSetConcurrency,
final int resultSetHoldability) throws SQLException {
logSql(sql);
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
static PreparedStatement prepareStatement(final Connection conn, final String sql,
final Throwables.BiFunction stmtCreator) throws SQLException {
logSql(sql);
return stmtCreator.apply(conn, sql);
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql) throws SQLException {
logSql(parsedSql.sql());
return conn.prepareStatement(parsedSql.getParameterizedSql());
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql, final boolean autoGeneratedKeys) throws SQLException {
logSql(parsedSql.sql());
return conn.prepareStatement(parsedSql.getParameterizedSql(), autoGeneratedKeys ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql, final int[] returnColumnIndexes) throws SQLException {
logSql(parsedSql.sql());
return conn.prepareStatement(parsedSql.getParameterizedSql(), returnColumnIndexes);
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql, final String[] returnColumnNames) throws SQLException {
logSql(parsedSql.sql());
return conn.prepareStatement(parsedSql.getParameterizedSql(), returnColumnNames);
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql, final int resultSetType, final int resultSetConcurrency)
throws SQLException {
logSql(parsedSql.sql());
return conn.prepareStatement(parsedSql.getParameterizedSql(), resultSetType, resultSetConcurrency);
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql, final int resultSetType, final int resultSetConcurrency,
final int resultSetHoldability) throws SQLException {
logSql(parsedSql.sql());
return conn.prepareStatement(parsedSql.getParameterizedSql(), resultSetType, resultSetConcurrency, resultSetHoldability);
}
static PreparedStatement prepareStatement(final Connection conn, final ParsedSql parsedSql,
final Throwables.BiFunction stmtCreator) throws SQLException {
logSql(parsedSql.sql());
return stmtCreator.apply(conn, parsedSql.getParameterizedSql());
}
static CallableStatement prepareCallable(final Connection conn, final String sql) throws SQLException {
logSql(sql);
return conn.prepareCall(sql);
}
static CallableStatement prepareCallable(final Connection conn, final String sql,
final Throwables.BiFunction stmtCreator) throws SQLException {
logSql(sql);
return stmtCreator.apply(conn, sql);
}
static CallableStatement prepareCallable(final Connection conn, final ParsedSql parsedSql) throws SQLException {
logSql(parsedSql.sql());
return conn.prepareCall(parsedSql.getParameterizedSql());
}
static CallableStatement prepareCallable(final Connection conn, final ParsedSql parsedSql,
final Throwables.BiFunction stmtCreator) throws SQLException {
logSql(parsedSql.sql());
return stmtCreator.apply(conn, parsedSql.getParameterizedSql());
}
/**
*
* @param conn
* @param sql
* @param parameters
* @return
* @throws SQLException
*/
@SafeVarargs
static PreparedStatement prepareStmt(final Connection conn, final String sql, final Object... parameters) throws SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
final ParsedSql parsedSql = ParsedSql.parse(sql);
final PreparedStatement stmt = prepareStatement(conn, parsedSql);
if (N.notEmpty(parameters)) {
setParameters(parsedSql, stmt, parameters);
}
return stmt;
}
/**
*
* @param conn
* @param sql
* @param parameters
* @return
* @throws SQLException
*/
@SafeVarargs
static CallableStatement prepareCall(final Connection conn, final String sql, final Object... parameters) throws SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
final ParsedSql parsedSql = ParsedSql.parse(sql);
final CallableStatement stmt = prepareCallable(conn, parsedSql);
if (N.notEmpty(parameters)) {
setParameters(parsedSql, stmt, parameters);
}
return stmt;
}
/**
* Batch prepare statement.
*
* @param conn
* @param sql
* @param parametersList
* @return
* @throws SQLException
*/
static PreparedStatement prepareBatchStmt(final Connection conn, final String sql, final List> parametersList) throws SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
final ParsedSql parsedSql = ParsedSql.parse(sql);
final PreparedStatement stmt = prepareStatement(conn, parsedSql);
for (final Object parameters : parametersList) {
setParameters(parsedSql, stmt, N.asArray(parameters));
stmt.addBatch();
}
return stmt;
}
/**
*
* @param conn
* @param sql
* @param parametersList
* @return
* @throws SQLException
*/
static CallableStatement prepareBatchCall(final Connection conn, final String sql, final List> parametersList) throws SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
final ParsedSql parsedSql = ParsedSql.parse(sql);
final CallableStatement stmt = prepareCallable(conn, parsedSql);
for (final Object parameters : parametersList) {
setParameters(parsedSql, stmt, N.asArray(parameters));
stmt.addBatch();
}
return stmt;
}
/**
* Creates the named SQL.
*
* @param namedSql
* @return
*/
private static ParsedSql parseNamedSql(final String namedSql) {
N.checkArgNotEmpty(namedSql, s.namedSql);
final ParsedSql parsedSql = ParsedSql.parse(namedSql);
validateNamedSql(parsedSql);
return parsedSql;
}
private static void validateNamedSql(final ParsedSql namedSql) {
if (namedSql.getNamedParameters().size() != namedSql.getParameterCount()) {
throw new IllegalArgumentException("\"" + namedSql.sql() + "\" is not a valid named sql:");
}
}
private static SQLTransaction getTransaction(final javax.sql.DataSource ds, final String sql, final CreatedBy createdBy) {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, createdBy);
if (tran == null || (tran.isForUpdateOnly() && sqlOperation == SQLOperation.SELECT)) {
return null;
} else {
return tran;
}
}
/**
* Executes a SQL query using the provided DataSource and SQL string with optional parameters.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the query
* @param sql the SQL string to execute
* @param parameters optional parameters for the SQL query
* @return a DataSet object containing the result of the query
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the query
*/
@SafeVarargs
public static DataSet executeQuery(final javax.sql.DataSource ds, final String sql, final Object... parameters)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return executeQuery(tran.connection(), sql, parameters);
} else {
final Connection conn = getConnection(ds);
try {
return executeQuery(conn, sql, parameters);
} finally {
releaseConnection(conn, ds);
}
}
}
/**
* Executes a SQL query using the provided Connection and SQL string with optional parameters.
*
* This method does not close the provided Connection after the query is executed.
*
*
* @param conn the Connection to use for the query
* @param sql the SQL string to execute
* @param parameters optional parameters for the SQL query
* @return a DataSet object containing the result of the query
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the query
*/
@SafeVarargs
public static DataSet executeQuery(final Connection conn, final String sql, final Object... parameters) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = prepareStmt(conn, sql, parameters);
stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
rs = executeQuery(stmt);
return extractData(rs);
} finally {
closeQuietly(rs, stmt);
}
}
// /**
// *
// * @param stmt
// * @return
// * @throws SQLException
// */
// public static DataSet executeQuery(final PreparedStatement stmt) throws SQLException {
// ResultSet rs = null;
//
// try {
// rs = executeQuerry(stmt);
//
// return extractData(rs);
// } finally {
// closeQuietly(rs);
// }
// }
/**
* Executes a SQL update using the provided DataSource and SQL string with optional parameters.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the update
* @param sql the SQL string to execute
* @param parameters optional parameters for the SQL update
* @return the number of rows affected by the update
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the update
*/
@SafeVarargs
public static int executeUpdate(final javax.sql.DataSource ds, final String sql, final Object... parameters) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return executeUpdate(tran.connection(), sql, parameters);
} else {
final Connection conn = getConnection(ds);
try {
return executeUpdate(conn, sql, parameters);
} finally {
releaseConnection(conn, ds);
}
}
}
/**
* Executes a SQL update using the provided Connection and SQL string with optional parameters.
*
* This method does not close the provided Connection after the update is executed.
*
*
* @param conn the Connection to use for the update
* @param sql the SQL string to execute
* @param parameters optional parameters for the SQL update
* @return the number of rows affected by the update
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the update
*/
@SafeVarargs
public static int executeUpdate(final Connection conn, final String sql, final Object... parameters) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
PreparedStatement stmt = null;
try {
stmt = prepareStmt(conn, sql, parameters);
return executeUpdate(stmt);
} finally {
closeQuietly(stmt);
}
}
/**
* Executes a batch SQL update using the provided DataSource, SQL string, and list of parameters.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static int executeBatchUpdate(final javax.sql.DataSource ds, final String sql, final List> listOfParameters)
throws IllegalArgumentException, SQLException {
return executeBatchUpdate(ds, sql, listOfParameters, DEFAULT_BATCH_SIZE);
}
/**
* Executes a batch SQL update using the provided DataSource, SQL string, list of parameters, and batch size.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @param batchSize the size of each batch
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static int executeBatchUpdate(final javax.sql.DataSource ds, final String sql, final List> listOfParameters, final int batchSize)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgPositive(batchSize, s.batchSize);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return executeBatchUpdate(tran.connection(), sql, listOfParameters, batchSize);
} else if (listOfParameters.size() <= batchSize) {
final Connection conn = getConnection(ds);
try {
return executeBatchUpdate(conn, sql, listOfParameters, batchSize);
} finally {
releaseConnection(conn, ds);
}
} else {
final SQLTransaction tran2 = JdbcUtil.beginTransaction(ds);
int ret = 0;
try {
ret = executeBatchUpdate(tran2.connection(), sql, listOfParameters, batchSize);
tran2.commit();
} finally {
tran2.rollbackIfNotCommitted();
}
return ret;
}
}
/**
* Executes a batch SQL update using the provided Connection, SQL string, and list of parameters.
*
* This method does not close the provided Connection after the batch update is executed.
*
*
* @param conn the Connection to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static int executeBatchUpdate(final Connection conn, final String sql, final List> listOfParameters)
throws IllegalArgumentException, SQLException {
return executeBatchUpdate(conn, sql, listOfParameters, DEFAULT_BATCH_SIZE);
}
/**
* Executes a batch SQL update using the provided Connection, SQL string, list of parameters, and batch size.
*
* This method does not close the provided Connection after the batch update is executed.
*
*
* @param conn the Connection to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @param batchSize the size of each batch
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static int executeBatchUpdate(final Connection conn, final String sql, final List> listOfParameters, final int batchSize)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn);
N.checkArgNotNull(sql);
N.checkArgPositive(batchSize, s.batchSize);
if (N.isEmpty(listOfParameters)) {
return 0;
}
final ParsedSql parsedSql = ParsedSql.parse(sql);
final boolean originalAutoCommit = conn.getAutoCommit();
PreparedStatement stmt = null;
boolean noException = false;
try {
if (originalAutoCommit && listOfParameters.size() > batchSize) {
conn.setAutoCommit(false);
}
stmt = prepareStatement(conn, parsedSql);
final Object[] parameters = new Object[1];
int res = 0;
int idx = 0;
for (final Object parameter : listOfParameters) {
parameters[0] = parameter;
setParameters(parsedSql, stmt, parameters);
stmt.addBatch();
if (++idx % batchSize == 0) {
res += N.sum(executeBatch(stmt));
}
}
if (idx % batchSize != 0) {
res += N.sum(executeBatch(stmt));
}
noException = true;
return res;
} finally {
if (originalAutoCommit && listOfParameters.size() > batchSize) {
try {
if (noException) {
conn.commit();
} else {
conn.rollback();
}
} finally {
try {
conn.setAutoCommit(true);
} finally {
JdbcUtil.closeQuietly(stmt);
}
}
} else {
JdbcUtil.closeQuietly(stmt);
}
}
}
/**
* Executes a large batch SQL update using the provided DataSource, SQL string, and list of parameters.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static long executeLargeBatchUpdate(final javax.sql.DataSource ds, final String sql, final List> listOfParameters)
throws IllegalArgumentException, SQLException {
return executeLargeBatchUpdate(ds, sql, listOfParameters, DEFAULT_BATCH_SIZE);
}
/**
* Executes a large batch SQL update using the provided DataSource, SQL string, list of parameters, and batch size.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @param batchSize the size of each batch
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static long executeLargeBatchUpdate(final javax.sql.DataSource ds, final String sql, final List> listOfParameters, final int batchSize)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
N.checkArgPositive(batchSize, s.batchSize);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return executeLargeBatchUpdate(tran.connection(), sql, listOfParameters, batchSize);
} else if (listOfParameters.size() <= batchSize) {
final Connection conn = getConnection(ds);
try {
return executeLargeBatchUpdate(conn, sql, listOfParameters, batchSize);
} finally {
releaseConnection(conn, ds);
}
} else {
final SQLTransaction tran2 = JdbcUtil.beginTransaction(ds);
long ret = 0;
try {
ret = executeLargeBatchUpdate(tran2.connection(), sql, listOfParameters, batchSize);
tran2.commit();
} finally {
tran2.rollbackIfNotCommitted();
}
return ret;
}
}
/**
* Executes a large batch SQL update using the provided Connection, SQL string, and list of parameters.
*
* This method does not close the provided Connection after the batch update is executed.
*
*
* @param conn the Connection to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static long executeLargeBatchUpdate(final Connection conn, final String sql, final List> listOfParameters)
throws IllegalArgumentException, SQLException {
return executeLargeBatchUpdate(conn, sql, listOfParameters, DEFAULT_BATCH_SIZE);
}
/**
* Executes a large batch SQL update using the provided Connection, SQL string, list of parameters, and batch size.
*
* This method does not close the provided Connection after the batch update is executed.
*
*
* @param conn the Connection to use for the batch update
* @param sql the SQL string to execute
* @param listOfParameters a list of parameter sets for the batch update
* @param batchSize the size of each batch
* @return the number of rows affected by the batch update
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the batch update
*/
public static long executeLargeBatchUpdate(final Connection conn, final String sql, final List> listOfParameters, final int batchSize)
throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn);
N.checkArgNotNull(sql);
N.checkArgPositive(batchSize, s.batchSize);
if (N.isEmpty(listOfParameters)) {
return 0;
}
final ParsedSql parsedSql = ParsedSql.parse(sql);
final boolean originalAutoCommit = conn.getAutoCommit();
PreparedStatement stmt = null;
boolean noException = false;
try {
if (originalAutoCommit && listOfParameters.size() > batchSize) {
conn.setAutoCommit(false);
}
stmt = prepareStatement(conn, parsedSql);
final Object[] parameters = new Object[1];
long res = 0;
int idx = 0;
for (final Object parameter : listOfParameters) {
parameters[0] = parameter;
setParameters(parsedSql, stmt, parameters);
stmt.addBatch();
if (++idx % batchSize == 0) {
res += N.sum(executeLargeBatch(stmt));
}
}
if (idx % batchSize != 0) {
res += N.sum(executeLargeBatch(stmt));
}
noException = true;
return res;
} finally {
if (originalAutoCommit && listOfParameters.size() > batchSize) {
try {
if (noException) {
conn.commit();
} else {
conn.rollback();
}
} finally {
try {
conn.setAutoCommit(true);
} finally {
JdbcUtil.closeQuietly(stmt);
}
}
} else {
JdbcUtil.closeQuietly(stmt);
}
}
}
/**
* Executes a SQL statement using the provided DataSource, SQL string, and optional parameters.
*
* If a transaction is started by {@code JdbcUtil.beginTransaction} or in {@code Spring} with the same {@code DataSource} in the same thread,
* the {@code Connection} started the transaction will be used here.
* Otherwise, a {@code Connection} directly from the specified {@code DataSource} (Connection pool) will be borrowed and used.
*
*
* @param ds the DataSource to use for the SQL execution
* @param sql the SQL string to execute
* @param parameters optional parameters for the SQL statement
* @return {@code true} if the first result is a ResultSet object; {@code false} if it is an update count or there are no results
* @throws IllegalArgumentException if the DataSource or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the statement
*/
@SafeVarargs
public static boolean execute(final javax.sql.DataSource ds, final String sql, final Object... parameters) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(ds, s.dataSource);
N.checkArgNotEmpty(sql, s.sql);
final SQLTransaction tran = getTransaction(ds, sql, CreatedBy.JDBC_UTIL);
if (tran != null) {
return execute(tran.connection(), sql, parameters);
} else {
final Connection conn = getConnection(ds);
try {
return execute(conn, sql, parameters);
} finally {
releaseConnection(conn, ds);
}
}
}
/**
* Executes a SQL statement using the provided Connection, SQL string, and optional parameters.
*
* This method does not close the provided Connection after the statement is executed.
*
*
* @param conn the Connection to use for the SQL execution
* @param sql the SQL string to execute
* @param parameters optional parameters for the SQL statement
* @return {@code true} if the first result is a ResultSet object; {@code false} if it is an update count or there are no results
* @throws IllegalArgumentException if the Connection or SQL string is {@code null} or empty
* @throws SQLException if a SQL exception occurs while executing the statement
*/
@SafeVarargs
public static boolean execute(final Connection conn, final String sql, final Object... parameters) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(conn, s.conn);
N.checkArgNotEmpty(sql, s.sql);
PreparedStatement stmt = null;
try {
stmt = prepareStmt(conn, sql, parameters);
return JdbcUtil.execute(stmt);
} finally {
closeQuietly(stmt);
}
}
static ResultSet executeQuery(final PreparedStatement stmt) throws SQLException {
final SqlLogConfig sqlLogConfig = minExecutionTimeForSqlPerfLog_TL.get();
if (isToHandleSqlLog(sqlLogConfig)) {
final long startTime = System.currentTimeMillis();
try {
return stmt.executeQuery();
} finally {
handleSqlLog(stmt, sqlLogConfig, startTime);
clearParameters(stmt);
}
} else {
try {
return stmt.executeQuery();
} finally {
clearParameters(stmt);
}
}
}
static int executeUpdate(final PreparedStatement stmt) throws SQLException {
final SqlLogConfig sqlLogConfig = minExecutionTimeForSqlPerfLog_TL.get();
if (isToHandleSqlLog(sqlLogConfig)) {
final long startTime = System.currentTimeMillis();
try {
return stmt.executeUpdate();
} finally {
handleSqlLog(stmt, sqlLogConfig, startTime);
clearParameters(stmt);
}
} else {
try {
return stmt.executeUpdate();
} finally {
clearParameters(stmt);
}
}
}
static long executeLargeUpdate(final PreparedStatement stmt) throws SQLException {
final SqlLogConfig sqlLogConfig = minExecutionTimeForSqlPerfLog_TL.get();
if (isToHandleSqlLog(sqlLogConfig)) {
final long startTime = System.currentTimeMillis();
try {
return stmt.executeLargeUpdate();
} finally {
handleSqlLog(stmt, sqlLogConfig, startTime);
try {
stmt.clearBatch();
} catch (final SQLException e) {
logger.error("Failed to clear batch parameters after executeLargeUpdate", e);
}
}
} else {
try {
return stmt.executeLargeUpdate();
} finally {
try {
stmt.clearBatch();
} catch (final SQLException e) {
logger.error("Failed to clear batch parameters after executeLargeUpdate", e);
}
}
}
}
static int[] executeBatch(final Statement stmt) throws SQLException {
final SqlLogConfig sqlLogConfig = minExecutionTimeForSqlPerfLog_TL.get();
if (isToHandleSqlLog(sqlLogConfig)) {
final long startTime = System.currentTimeMillis();
try {
return stmt.executeBatch();
} finally {
handleSqlLog(stmt, sqlLogConfig, startTime);
try {
stmt.clearBatch();
} catch (final SQLException e) {
logger.error("Failed to clear batch parameters after executeBatch", e);
}
}
} else {
try {
return stmt.executeBatch();
} finally {
try {
stmt.clearBatch();
} catch (final SQLException e) {
logger.error("Failed to clear batch parameters after executeBatch", e);
}
}
}
}
static long[] executeLargeBatch(final Statement stmt) throws SQLException {
final SqlLogConfig sqlLogConfig = minExecutionTimeForSqlPerfLog_TL.get();
if (isToHandleSqlLog(sqlLogConfig)) {
final long startTime = System.currentTimeMillis();
try {
return stmt.executeLargeBatch();
} finally {
handleSqlLog(stmt, sqlLogConfig, startTime);
try {
stmt.clearBatch();
} catch (final SQLException e) {
logger.error("Failed to clear batch parameters after executeLargeBatch", e);
}
}
} else {
try {
return stmt.executeLargeBatch();
} finally {
try {
stmt.clearBatch();
} catch (final SQLException e) {
logger.error("Failed to clear batch parameters after executeLargeBatch", e);
}
}
}
}
static boolean execute(final PreparedStatement stmt) throws SQLException {
final SqlLogConfig sqlLogConfig = minExecutionTimeForSqlPerfLog_TL.get();
if (isToHandleSqlLog(sqlLogConfig)) {
final long startTime = System.currentTimeMillis();
try {
return stmt.execute();
} finally {
handleSqlLog(stmt, sqlLogConfig, startTime);
clearParameters(stmt);
}
} else {
try {
return stmt.execute();
} finally {
clearParameters(stmt);
}
}
}
private static boolean isToHandleSqlLog(final SqlLogConfig sqlLogConfig) {
return _sqlLogHandler != null || (isSqlPerfLogAllowed && sqlLogConfig.minExecutionTimeForSqlPerfLog >= 0 && sqlLogger.isInfoEnabled());
}
static void clearParameters(final PreparedStatement stmt) {
// calling clearParameters() will impact/remove registered out parameters in CallableStatement.
if (stmt == null || stmt instanceof CallableStatement) {
// no
} else {
try {
stmt.clearParameters();
} catch (final SQLException e) {
logger.error("Failed to clear parameters after execution", e);
}
}
}
static void setParameters(final ParsedSql parsedSql, final PreparedStatement stmt, final Object[] parameters) throws SQLException {
final int parameterCount = parsedSql.getParameterCount();
if (parameterCount == 0) {
return;
} else if (N.isEmpty(parameters)) {
throw new IllegalArgumentException(
"The count of parameter in sql is: " + parsedSql.getParameterCount() + ". But the specified parameters is null or empty");
}
@SuppressWarnings("rawtypes")
Type[] parameterTypes = null;
Object[] parameterValues = null;
if (isEntityOrMapParameter(parsedSql, parameters)) {
final List namedParameters = parsedSql.getNamedParameters();
final Object parameter_0 = parameters[0];
final Class> cls = parameter_0.getClass();
parameterValues = new Object[parameterCount];
if (ClassUtil.isBeanClass(cls)) {
final Object entity = parameter_0;
final BeanInfo entityInfo = ParserUtil.getBeanInfo(cls);
parameterTypes = new Type[parameterCount];
PropInfo propInfo = null;
for (int i = 0; i < parameterCount; i++) {
propInfo = entityInfo.getPropInfo(namedParameters.get(i));
if (propInfo == null) {
throw new IllegalArgumentException(
"No property found with name: " + namedParameters.get(i) + " in class: " + ClassUtil.getCanonicalClassName(cls));
}
parameterValues[i] = propInfo.getPropValue(entity);
parameterTypes[i] = propInfo.dbType;
}
} else if (parameter_0 instanceof Map) {
@SuppressWarnings("unchecked")
final Map m = (Map) parameter_0;
for (int i = 0; i < parameterCount; i++) {
parameterValues[i] = m.get(namedParameters.get(i));
if ((parameterValues[i] == null) && !m.containsKey(namedParameters.get(i))) {
throw new IllegalArgumentException("Parameter for property '" + namedParameters.get(i) + "' is missed");
}
}
} else {
final EntityId entityId = (EntityId) parameter_0;
for (int i = 0; i < parameterCount; i++) {
parameterValues[i] = entityId.get(namedParameters.get(i));
if ((parameterValues[i] == null) && !entityId.containsKey(namedParameters.get(i))) {
throw new IllegalArgumentException("Parameter for property '" + namedParameters.get(i) + "' is missed");
}
}
}
} else {
parameterValues = getParameterValues(parsedSql, parameters);
}
setParameters(stmt, parameterCount, parameterValues, parameterTypes);
}
@SuppressWarnings("rawtypes")
static void setParameters(final PreparedStatement stmt, final int parameterCount, final Object[] parameters, final Type[] parameterTypes)
throws SQLException {
if (N.notEmpty(parameterTypes) && parameterTypes.length >= parameterCount) {
for (int i = 0; i < parameterCount; i++) {
parameterTypes[i].set(stmt, i + 1, parameters[i]);
}
} else if (N.notEmpty(parameters) && parameters.length >= parameterCount) {
for (int i = 0; i < parameterCount; i++) {
if (parameters[i] == null) {
stmt.setObject(i + 1, parameters[i]);
} else {
N.typeOf(parameters[i].getClass()).set(stmt, i + 1, parameters[i]);
}
}
}
}
/**
* Gets the parameter values.
*
* @param parsedSql
* @param parameters
* @return
*/
static Object[] getParameterValues(final ParsedSql parsedSql, final Object... parameters) {
if ((parameters.length == 1) && (parameters[0] != null)) {
if (parameters[0] instanceof Object[] && ((((Object[]) parameters[0]).length) >= parsedSql.getParameterCount())) {
return (Object[]) parameters[0];
} else if (parameters[0] instanceof List && (((List>) parameters[0]).size() >= parsedSql.getParameterCount())) {
final Collection> c = (Collection>) parameters[0];
return c.toArray(new Object[c.size()]);
}
}
return parameters;
}
static boolean isEntityOrMapParameter(final ParsedSql parsedSql, final Object... parameters) {
if (N.isEmpty(parsedSql.getNamedParameters()) || N.isEmpty(parameters) || (parameters.length != 1) || (parameters[0] == null)) {
return false;
}
final Class extends Object> cls = parameters[0].getClass();
return ClassUtil.isBeanClass(cls) || ClassUtil.isRecordClass(cls) || Map.class.isAssignableFrom(cls) || EntityId.class.isAssignableFrom(cls);
}
static final RowFilter INTERNAL_DUMMY_ROW_FILTER = RowFilter.ALWAYS_TRUE;
static final RowExtractor INTERNAL_DUMMY_ROW_EXTRACTOR = (rs, outputRow) -> {
throw new UnsupportedOperationException("DO NOT CALL ME.");
};
/**
* Extracts data from the provided ResultSet and returns it as a DataSet.
*
* @param rs the ResultSet to extract data from
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs) throws SQLException {
return extractData(rs, false);
}
/**
* Extracts data from the provided ResultSet starting from the specified offset and up to the specified count.
*
* @param rs the ResultSet to extract data from
* @param offset the starting position in the ResultSet
* @param count the number of rows to extract
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final int offset, final int count) throws SQLException {
return extractData(rs, offset, count, false);
}
/**
* Extracts data from the provided ResultSet using the specified RowFilter.
*
* @param rs the ResultSet to extract data from
* @param filter the RowFilter to apply while extracting data
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final RowFilter filter) throws SQLException {
return extractData(rs, 0, Integer.MAX_VALUE, filter, INTERNAL_DUMMY_ROW_EXTRACTOR, false);
}
/**
* Extracts data from the provided ResultSet using the specified RowExtractor.
*
* @param rs the ResultSet to extract data from
* @param rowExtractor the RowExtractor to apply while extracting data
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final RowExtractor rowExtractor) throws SQLException {
return extractData(rs, 0, Integer.MAX_VALUE, INTERNAL_DUMMY_ROW_FILTER, rowExtractor, false);
}
/**
* Extracts data from the provided ResultSet using the specified RowFilter and RowExtractor.
*
* @param rs the ResultSet to extract data from
* @param filter the RowFilter to apply while extracting data
* @param rowExtractor the RowExtractor to apply while extracting data
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final RowFilter filter, final RowExtractor rowExtractor) throws SQLException {
return extractData(rs, 0, Integer.MAX_VALUE, filter, rowExtractor, false);
}
/**
* Extracts data from the provided ResultSet and returns it as a DataSet.
*
* This method allows specifying whether to close the ResultSet after extraction.
*
*
* @param rs the ResultSet to extract data from
* @param closeResultSet whether to close the ResultSet after extraction
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final boolean closeResultSet) throws SQLException {
return extractData(rs, 0, Integer.MAX_VALUE, closeResultSet);
}
/**
* Extracts data from the provided ResultSet starting from the specified offset and up to the specified count.
*
* This method allows specifying whether to close the ResultSet after extraction.
*
*
* @param rs the ResultSet to extract data from
* @param offset the starting position in the ResultSet
* @param count the number of rows to extract
* @param closeResultSet whether to close the ResultSet after extraction
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final int offset, final int count, final boolean closeResultSet) throws SQLException {
return extractData(rs, offset, count, INTERNAL_DUMMY_ROW_FILTER, INTERNAL_DUMMY_ROW_EXTRACTOR, closeResultSet);
}
/**
* Extracts data from the provided ResultSet starting from the specified offset and up to the specified count.
*
* This method allows specifying a RowFilter to apply while extracting data and whether to close the ResultSet after extraction.
*
*
* @param rs the ResultSet to extract data from
* @param offset the starting position in the ResultSet
* @param count the number of rows to extract
* @param filter the RowFilter to apply while extracting data
* @param closeResultSet whether to close the ResultSet after extraction
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final int offset, final int count, final RowFilter filter, final boolean closeResultSet)
throws SQLException {
return extractData(rs, offset, count, filter, INTERNAL_DUMMY_ROW_EXTRACTOR, closeResultSet);
}
/**
* Extracts data from the provided ResultSet starting from the specified offset and up to the specified count.
*
* This method allows specifying a RowExtractor to apply while extracting data and whether to close the ResultSet after extraction.
*
*
* @param rs the ResultSet to extract data from
* @param offset the starting position in the ResultSet
* @param count the number of rows to extract
* @param rowExtractor the RowExtractor to apply while extracting data
* @param closeResultSet whether to close the ResultSet after extraction
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
*/
public static DataSet extractData(final ResultSet rs, final int offset, final int count, final RowExtractor rowExtractor, final boolean closeResultSet)
throws SQLException {
return extractData(rs, offset, count, INTERNAL_DUMMY_ROW_FILTER, rowExtractor, closeResultSet);
}
/**
* Extracts data from the provided ResultSet starting from the specified offset and up to the specified count.
*
* This method allows specifying a RowFilter and a RowExtractor to apply while extracting data and whether to close the ResultSet after extraction.
*
*
* @param rs the ResultSet to extract data from
* @param offset the starting position in the ResultSet
* @param count the number of rows to extract
* @param filter the RowFilter to apply while extracting data
* @param rowExtractor the RowExtractor to apply while extracting data
* @param closeResultSet whether to close the ResultSet after extraction
* @return a DataSet containing the extracted data
* @throws SQLException if a SQL exception occurs while extracting data
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static DataSet extractData(final ResultSet rs, final int offset, final int count, final RowFilter filter, final RowExtractor rowExtractor,
final boolean closeResultSet) throws IllegalArgumentException, SQLException {
N.checkArgNotNull(rs, s.ResultSet);
N.checkArgNotNegative(offset, s.offset);
N.checkArgNotNegative(count, s.count);
N.checkArgNotNull(filter, s.filter);
N.checkArgNotNull(rowExtractor, s.rowExtractor);
final boolean checkDateType = checkDateType(rs);
try {
return JdbcUtil.extractResultSetToDataSet(rs, offset, count, filter, rowExtractor, checkDateType);
} finally {
if (closeResultSet) {
closeQuietly(rs);
}
}
}
static DataSet extractResultSetToDataSet(final ResultSet rs, final int offset, int count, final RowFilter filter, final RowExtractor rowExtractor,
final boolean checkDateType) throws SQLException {
final ResultSetMetaData rsmd = rs.getMetaData();
final int columnCount = rsmd.getColumnCount();
final List columnNameList = new ArrayList<>(columnCount);
final List> columnList = new ArrayList<>(columnCount);
for (int i = 0; i < columnCount;) {
columnNameList.add(JdbcUtil.getColumnLabel(rsmd, ++i));
columnList.add(new ArrayList<>());
}
JdbcUtil.skip(rs, offset);
if (filter == INTERNAL_DUMMY_ROW_FILTER) {
if (rowExtractor == INTERNAL_DUMMY_ROW_EXTRACTOR) {
while (count > 0 && rs.next()) {
for (int i = 0; i < columnCount;) {
columnList.get(i).add(JdbcUtil.getColumnValue(rs, ++i, checkDateType));
}
count--;
}
} else {
final Object[] outputRow = new Object[columnCount];
while (count > 0 && rs.next()) {
rowExtractor.accept(rs, outputRow);
for (int i = 0; i < columnCount; i++) {
columnList.get(i).add(outputRow[i]);
}
count--;
}
}
} else {
if (rowExtractor == INTERNAL_DUMMY_ROW_EXTRACTOR) {
while (count > 0 && rs.next()) {
if (filter.test(rs)) {
for (int i = 0; i < columnCount;) {
columnList.get(i).add(JdbcUtil.getColumnValue(rs, ++i, checkDateType));
}
count--;
}
}
} else {
final Object[] outputRow = new Object[columnCount];
while (count > 0 && rs.next()) {
if (filter.test(rs)) {
rowExtractor.accept(rs, outputRow);
for (int i = 0; i < columnCount; i++) {
columnList.get(i).add(outputRow[i]);
}
count--;
}
}
}
}
// return new RowDataSet(null, entityClass, columnNameList, columnList);
return new RowDataSet(columnNameList, columnList);
}
static R extractAndCloseResultSet(final ResultSet rs, final ResultExtractor extends R> resultExtractor) throws SQLException {
try {
return checkNotResultSet(resultExtractor.apply(rs));
} finally {
closeQuietly(rs);
}
}
static R extractAndCloseResultSet(final ResultSet rs, final BiResultExtractor extends R> resultExtractor) throws SQLException {
try {
return checkNotResultSet(resultExtractor.apply(rs, getColumnLabelList(rs)));
} finally {
closeQuietly(rs);
}
}
/**
* Extracts all ResultSets from the provided Statement and returns them as a CheckedStream of DataSet.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.extractAllResultSets(stmt).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param stmt the Statement to extract ResultSets from
* @return a CheckedStream of DataSet containing the extracted ResultSets
*/
public static CheckedStream extractAllResultSets(final Statement stmt) {
return extractAllResultSets(stmt, ResultExtractor.TO_DATA_SET);
}
/**
* Extracts all ResultSets from the provided Statement and returns them as a CheckedStream.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.extractAllResultSets(stmt, resultExtractor).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param stmt the Statement to extract ResultSets from
* @param resultExtractor the ResultExtractor to apply while extracting data
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream extractAllResultSets(final Statement stmt, final ResultExtractor resultExtractor)
throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(resultExtractor, s.resultExtractor);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class)
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> extractAndCloseResultSet(rs, resultExtractor));
}
/**
* Extracts all ResultSets from the provided Statement and returns them as a CheckedStream.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.extractAllResultSets(stmt, resultExtractor).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param stmt the Statement to extract ResultSets from
* @param resultExtractor the BiResultExtractor to apply while extracting data
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream extractAllResultSets(final Statement stmt, final BiResultExtractor resultExtractor)
throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(resultExtractor, s.resultExtractor);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class)
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> extractAndCloseResultSet(rs, resultExtractor));
}
/**
* Creates a stream from the provided ResultSet.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param resultSet the ResultSet to create a stream from
* @return a CheckedStream of Object arrays containing the data from the ResultSet
* @throws IllegalArgumentException if the provided ResultSet is null
*/
public static CheckedStream stream(final ResultSet resultSet) {
return stream(resultSet, Object[].class);
}
/**
* Creates a stream from the provided ResultSet.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param targetClass the class of the result type
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final Class extends T> targetClass) throws IllegalArgumentException {
N.checkArgNotNull(targetClass, s.targetClass);
N.checkArgNotNull(resultSet, s.resultSet);
return stream(resultSet, BiRowMapper.to(targetClass));
}
/**
* Creates a stream from the provided ResultSet using the specified RowMapper.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet, rowMapper).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param rowMapper the RowMapper to apply while extracting data
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final RowMapper extends T> rowMapper) throws IllegalArgumentException {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgNotNull(rowMapper, s.rowMapper);
return CheckedStream.of(iterate(resultSet, rowMapper, null));
}
static Throwables.Iterator iterate(final ResultSet resultSet, final RowMapper extends T> rowMapper, final Runnable onClose) {
return new Throwables.Iterator<>() {
private boolean hasNext;
@Override
public boolean hasNext() throws SQLException {
if (!hasNext) {
hasNext = resultSet.next();
}
return hasNext;
}
@Override
public T next() throws SQLException {
if (!hasNext()) {
throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX);
}
hasNext = false;
return rowMapper.apply(resultSet);
}
@Override
public void advance(final long n) throws IllegalArgumentException, SQLException {
N.checkArgNotNegative(n, s.n);
final long m = hasNext ? n - 1 : n;
JdbcUtil.skip(resultSet, m);
hasNext = false;
}
@Override
public long count() throws SQLException {
long cnt = hasNext ? 1 : 0;
hasNext = false;
while (resultSet.next()) {
cnt++;
}
return cnt;
}
@Override
protected void closeResource() {
if (onClose != null) {
onClose.run();
}
}
};
}
/**
* Creates a stream from the provided ResultSet using the specified RowFilter and RowMapper.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet, rowFilter, rowMapper).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param rowFilter the RowFilter to apply while filtering rows
* @param rowMapper the RowMapper to apply while extracting data
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final RowFilter rowFilter, final RowMapper extends T> rowMapper)
throws IllegalArgumentException {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgNotNull(rowFilter, s.rowFilter);
N.checkArgNotNull(rowMapper, s.rowMapper);
return CheckedStream.of(iterate(resultSet, rowFilter, rowMapper, null));
}
static Throwables.Iterator iterate(final ResultSet resultSet, final RowFilter rowFilter, final RowMapper extends T> rowMapper,
final Runnable onClose) {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgNotNull(rowFilter, s.rowFilter);
N.checkArgNotNull(rowMapper, s.rowMapper);
return new Throwables.Iterator<>() {
private boolean hasNext;
@Override
public boolean hasNext() throws SQLException {
if (!hasNext) {
while (resultSet.next()) {
if (rowFilter.test(resultSet)) {
hasNext = true;
break;
}
}
}
return hasNext;
}
@Override
public T next() throws SQLException {
if (!hasNext()) {
throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX);
}
hasNext = false;
return rowMapper.apply(resultSet);
}
@Override
protected void closeResource() {
if (onClose != null) {
onClose.run();
}
}
};
}
/**
* Creates a stream from the provided ResultSet using the specified BiRowMapper.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet, rowMapper).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param rowMapper the BiRowMapper to apply while extracting data
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final BiRowMapper extends T> rowMapper)
throws IllegalArgumentException {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgNotNull(rowMapper, s.rowMapper);
return CheckedStream.of(iterate(resultSet, rowMapper, null));
}
static Throwables.Iterator iterate(final ResultSet resultSet, final BiRowMapper extends T> rowMapper, final Runnable onClose) {
return new Throwables.Iterator<>() {
private List columnLabels = null;
private boolean hasNext;
@Override
public boolean hasNext() throws SQLException {
if (!hasNext) {
hasNext = resultSet.next();
}
return hasNext;
}
@Override
public T next() throws SQLException {
if (!hasNext()) {
throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX);
}
hasNext = false;
if (columnLabels == null) {
columnLabels = getColumnLabelList(resultSet);
}
return rowMapper.apply(resultSet, columnLabels);
}
@Override
public void advance(final long n) throws IllegalArgumentException, SQLException {
N.checkArgNotNegative(n, s.n);
final long m = hasNext ? n - 1 : n;
JdbcUtil.skip(resultSet, m);
hasNext = false;
}
@Override
public long count() throws SQLException {
long cnt = hasNext ? 1 : 0;
hasNext = false;
while (resultSet.next()) {
cnt++;
}
return cnt;
}
@Override
protected void closeResource() {
if (onClose != null) {
onClose.run();
}
}
};
}
/**
* Creates a stream from the provided ResultSet using the specified BiRowFilter and BiRowMapper.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet, rowFilter, rowMapper).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param rowFilter the BiRowFilter to apply while filtering rows
* @param rowMapper the BiRowMapper to apply while extracting data
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final BiRowFilter rowFilter, final BiRowMapper extends T> rowMapper)
throws IllegalArgumentException {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgNotNull(rowFilter, s.rowFilter);
N.checkArgNotNull(rowMapper, s.rowMapper);
return CheckedStream.of(iterate(resultSet, rowFilter, rowMapper));
}
static Throwables.Iterator iterate(final ResultSet resultSet, final BiRowFilter rowFilter, final BiRowMapper extends T> rowMapper) {
return new Throwables.Iterator<>() {
private List columnLabels = null;
private boolean hasNext;
@Override
public boolean hasNext() throws SQLException {
if (columnLabels == null) {
columnLabels = JdbcUtil.getColumnLabelList(resultSet);
}
if (!hasNext) {
while (resultSet.next()) {
if (rowFilter.test(resultSet, columnLabels)) {
hasNext = true;
break;
}
}
}
return hasNext;
}
@Override
public T next() throws SQLException {
if (!hasNext()) {
throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX);
}
hasNext = false;
return rowMapper.apply(resultSet, columnLabels);
}
};
}
/**
* Creates a stream from the provided ResultSet using the specified column index.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet, columnIndex).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param columnIndex the index of the column to extract data from, starting from 1
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final int columnIndex) throws IllegalArgumentException {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgPositive(columnIndex, s.columnIndex);
final boolean checkDateType = JdbcUtil.checkDateType(resultSet);
final RowMapper extends T> rowMapper = rs -> (T) getColumnValue(resultSet, columnIndex, checkDateType);
return stream(resultSet, rowMapper);
}
/**
* Creates a stream from the provided ResultSet using the specified column name.
*
* It's the user's responsibility to close the input {@code resultSet} after the stream is finished, or call:
*
* {@code JdbcUtil.stream(resultSet, columnName).onClose(Fn.closeQuietly(resultSet))...}
*
*
* @param the type of the result extracted from the ResultSet
* @param resultSet the ResultSet to create a stream from
* @param columnName the name of the column to extract data from
* @return a CheckedStream of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
public static CheckedStream stream(final ResultSet resultSet, final String columnName) throws IllegalArgumentException {
N.checkArgNotNull(resultSet, s.resultSet);
N.checkArgNotEmpty(columnName, s.columnName);
final RowMapper extends T> rowMapper = new RowMapper<>() {
private int columnIndex = -1;
private boolean checkDateType = true;
@Override
public T apply(final ResultSet rs) throws SQLException {
if (columnIndex == -1) {
columnIndex = getColumnIndex(resultSet, columnName);
checkDateType = JdbcUtil.checkDateType(resultSet);
}
return (T) getColumnValue(resultSet, columnIndex, checkDateType);
}
};
return stream(resultSet, rowMapper);
}
/**
* Creates a stream of all result sets from the provided Statement.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.streamAllResultSets(stmt, targetClass).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from each ResultSet
* @param stmt the Statement to create streams from
* @param targetClass the class of the result type
* @return a CheckedStream of CheckedStreams of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream, SQLException> streamAllResultSets(final Statement stmt,
final Class extends T> targetClass) throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(targetClass, s.targetClass);
JdbcUtil.checkDateType(stmt);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class) //
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> {
final BiRowMapper rowMapper = BiRowMapper.to(targetClass);
return JdbcUtil. stream(rs, rowMapper).onClose(() -> JdbcUtil.closeQuietly(rs));
});
}
/**
* Creates a stream of all result sets from the provided Statement.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.streamAllResultSets(stmt, rowMapper).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from each ResultSet
* @param stmt the Statement to create streams from
* @param rowMapper the RowMapper to map each row of the ResultSet to the desired type
* @return a CheckedStream of CheckedStreams of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream, SQLException> streamAllResultSets(final Statement stmt,
final RowMapper extends T> rowMapper) throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(rowMapper, s.rowMapper);
JdbcUtil.checkDateType(stmt);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class)
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> JdbcUtil. stream(rs, rowMapper).onClose(() -> JdbcUtil.closeQuietly(rs)));
}
/**
* Creates a stream of all result sets from the provided Statement.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.streamAllResultSets(stmt, rowFilter, rowMapper).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from each ResultSet
* @param stmt the Statement to create streams from
* @param rowFilter the RowFilter to filter rows of the ResultSet
* @param rowMapper the RowMapper to map each row of the ResultSet to the desired type
* @return a CheckedStream of CheckedStreams of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream, SQLException> streamAllResultSets(final Statement stmt, final RowFilter rowFilter,
final RowMapper extends T> rowMapper) throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(rowFilter, s.rowFilter);
N.checkArgNotNull(rowMapper, s.rowMapper);
JdbcUtil.checkDateType(stmt);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class)
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> JdbcUtil. stream(rs, rowFilter, rowMapper).onClose(() -> JdbcUtil.closeQuietly(rs)));
}
/**
* Creates a stream of all result sets from the provided Statement.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.streamAllResultSets(stmt, rowMapper).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from each ResultSet
* @param stmt the Statement to create streams from
* @return a CheckedStream of CheckedStreams of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream, SQLException> streamAllResultSets(final Statement stmt,
final BiRowMapper extends T> rowMapper) throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(rowMapper, s.rowMapper);
JdbcUtil.checkDateType(stmt);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class)
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> JdbcUtil. stream(rs, rowMapper).onClose(() -> JdbcUtil.closeQuietly(rs)));
}
/**
* Creates a stream of all result sets from the provided Statement.
*
* It's the user's responsibility to close the input {@code stmt} after the stream is finished, or call:
*
* {@code JdbcUtil.streamAllResultSets(stmt, rowFilter, rowMapper).onClose(Fn.closeQuietly(stmt))...}
*
*
* @param the type of the result extracted from each ResultSet
* @param stmt the Statement to create streams from
* @param rowFilter the BiRowFilter to filter rows of the ResultSet
* @param rowMapper the BiRowMapper to map each row of the ResultSet to the desired type
* @return a CheckedStream of CheckedStreams of the extracted results
* @throws IllegalArgumentException if the provided arguments are invalid
*/
@SuppressWarnings("resource")
public static CheckedStream, SQLException> streamAllResultSets(final Statement stmt, final BiRowFilter rowFilter,
final BiRowMapper extends T> rowMapper) throws IllegalArgumentException {
N.checkArgNotNull(stmt, s.stmt);
N.checkArgNotNull(rowFilter, s.rowFilter);
N.checkArgNotNull(rowMapper, s.rowMapper);
JdbcUtil.checkDateType(stmt);
final Supplier> supplier = Fn.memoize(() -> iterateAllResultSets(stmt, true));
return CheckedStream.just(supplier, SQLException.class)
.onClose(() -> supplier.get().close())
.flatMap(it -> CheckedStream.of(it.get()))
.map(rs -> JdbcUtil. stream(rs, rowFilter, rowMapper).onClose(() -> JdbcUtil.closeQuietly(rs)));
}
static Throwables.Iterator iterateAllResultSets(final Statement stmt, final boolean isFirstResultSet) { //NOSONAR
return new Throwables.Iterator<>() {
private final Holder resultSetHolder = new Holder<>();
private boolean isNextResultSet = isFirstResultSet;
private boolean noMoreResult = false;
@Override
public boolean hasNext() throws SQLException {
if (resultSetHolder.isNull() && noMoreResult == false) {
while (true) {
if (isNextResultSet) {
resultSetHolder.setValue(stmt.getResultSet());
isNextResultSet = false;
break;
} else if (stmt.getUpdateCount() != -1) {
isNextResultSet = stmt.getMoreResults();
} else {
noMoreResult = true;
break;
}
}
}
return resultSetHolder.isNotNull();
}
@Override
public ResultSet next() throws SQLException {
if (!hasNext()) {
throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX);
}
return resultSetHolder.getAndSet(null);
}
@Override
protected void closeResource() {
if (resultSetHolder.isNotNull()) {
JdbcUtil.closeQuietly(resultSetHolder.getAndSet(null));
}
}
};
}
/**
* Runs a {@code Stream} with each element (page) loaded from the database table by running the specified SQL {@code query}.
*
* The query must be ordered by at least one key/id and have a result size limitation, for example, {@code LIMIT pageSize} or {@code ROWS FETCH NEXT pageSize ROWS ONLY}.
*
*
* @param ds the DataSource to get the connection from
* @param query the SQL query to run for each page
* @param pageSize the number of rows to fetch per page
* @param paramSetter the BiParametersSetter to set parameters for the query; the second parameter is the result set for the previous page, and it's {@code null} for the first page
* @return a CheckedStream of DataSet, each representing a page of results
* @throws SQLException if a database access error occurs
*/
@SuppressWarnings("rawtypes")
public static CheckedStream queryByPage(final javax.sql.DataSource ds, final String query, final int pageSize,
final Jdbc.BiParametersSetter super AbstractQuery, DataSet> paramSetter) {
return queryByPage(ds, query, pageSize, paramSetter, Jdbc.ResultExtractor.TO_DATA_SET);
}
/**
* Runs a {@code Stream} with each element (page) loaded from the database table by running the specified SQL {@code query}.
*
* The query must be ordered by at least one key/id and have a result size limitation, for example, {@code LIMIT pageSize} or {@code ROWS FETCH NEXT pageSize ROWS ONLY}.
*
*
* @param the type of the result extracted from each page
* @param ds the DataSource to get the connection from
* @param query the SQL query to run for each page
* @param pageSize the number of rows to fetch per page
* @param paramSetter the BiParametersSetter to set parameters for the query; the second parameter is the result set for the previous page, and it's {@code null} for the first page
* @param resultExtractor the ResultExtractor to extract results from the ResultSet
* @return a CheckedStream of the extracted results
* @throws SQLException if a database access error occurs
*/
@SuppressWarnings("rawtypes")
public static CheckedStream queryByPage(final javax.sql.DataSource ds, final String query, final int pageSize,
final Jdbc.BiParametersSetter super AbstractQuery, R> paramSetter, final Jdbc.ResultExtractor resultExtractor) {
final boolean isNamedQuery = ParsedSql.parse(query).getNamedParameters().size() > 0;
return CheckedStream., SQLException> of(Holder.of((R) null)) //
.cycled()
.map(it -> {
final R ret = (isNamedQuery ? JdbcUtil.prepareNamedQuery(ds, query) : JdbcUtil.prepareQuery(ds, query)) //
.setFetchDirectionToForward()
.setFetchSize(pageSize)
.settParameters(it.value(), paramSetter)
.query(resultExtractor);
it.setValue(ret);
return ret;
})
.takeWhile(JdbcUtil::isNotEmptyResult);
}
/**
* Runs a {@code Stream} with each element (page) loaded from the database table by running the specified SQL {@code query}.
*
* The query must be ordered by at least one key/id and have a result size limitation, for example, {@code LIMIT pageSize} or {@code ROWS FETCH NEXT pageSize ROWS ONLY}.
*
*
* @param the type of the result extracted from each page
* @param ds the DataSource to get the connection from
* @param query the SQL query to run for each page
* @param pageSize the number of rows to fetch per page
* @param paramSetter the BiParametersSetter to set parameters for the query; the second parameter is the result set for the previous page, and it's {@code null} for the first page
* @param resultExtractor the ResultExtractor to extract results from the ResultSet
* @return a CheckedStream of the extracted results
* @throws SQLException if a database access error occurs
*/
@SuppressWarnings("rawtypes")
public static CheckedStream queryByPage(final javax.sql.DataSource ds, final String query, final int pageSize,
final Jdbc.BiParametersSetter super AbstractQuery, R> paramSetter, final Jdbc.BiResultExtractor resultExtractor) {
final boolean isNamedQuery = ParsedSql.parse(query).getNamedParameters().size() > 0;
return CheckedStream., SQLException> of(Holder.of((R) null)) //
.cycled()
.map(it -> {
final R ret = (isNamedQuery ? JdbcUtil.prepareNamedQuery(ds, query) : JdbcUtil.prepareQuery(ds, query)) //
.setFetchDirectionToForward()
.setFetchSize(pageSize)
.settParameters(it.value(), paramSetter)
.query(resultExtractor);
it.setValue(ret);
return ret;
})
.takeWhile(JdbcUtil::isNotEmptyResult);
}
/**
* Runs a {@code Stream} with each element (page) loaded from the database table by running the specified SQL {@code query}.
*
* The query must be ordered by at least one key/id and have a result size limitation, for example, {@code LIMIT pageSize} or {@code ROWS FETCH NEXT pageSize ROWS ONLY}.
*
*
* @param conn the Connection to get the connection from
* @param query the SQL query to run for each page
* @param pageSize the number of rows to fetch per page
* @param paramSetter the BiParametersSetter to set parameters for the query; the second parameter is the result set for the previous page, and it's {@code null} for the first page
* @return a CheckedStream of DataSet, each representing a page of results
* @throws SQLException if a database access error occurs
*/
@SuppressWarnings("rawtypes")
public static CheckedStream queryByPage(final Connection conn, final String query, final int pageSize,
final Jdbc.BiParametersSetter super AbstractQuery, DataSet> paramSetter) {
return queryByPage(conn, query, pageSize, paramSetter, Jdbc.ResultExtractor.TO_DATA_SET);
}
/**
* Runs a {@code Stream} with each element (page) loaded from the database table by running the specified SQL {@code query}.
*
* The query must be ordered by at least one key/id and have a result size limitation, for example, {@code LIMIT pageSize} or {@code ROWS FETCH NEXT pageSize ROWS ONLY}.
*
*
* @param the type of the result extracted from each page
* @param conn the Connection to get the connection from
* @param query the SQL query to run for each page
* @param pageSize the number of rows to fetch per page
* @param paramSetter the BiParametersSetter to set parameters for the query; the second parameter is the result set for the previous page, and it's {@code null} for the first page
* @param resultExtractor the ResultExtractor to extract results from the ResultSet
* @return a CheckedStream of the extracted results
* @throws SQLException if a database access error occurs
*/
@SuppressWarnings("rawtypes")
public static CheckedStream queryByPage(final Connection conn, final String query, final int pageSize,
final Jdbc.BiParametersSetter super AbstractQuery, R> paramSetter, final Jdbc.ResultExtractor resultExtractor) {
final boolean isNamedQuery = ParsedSql.parse(query).getNamedParameters().size() > 0;
return CheckedStream., SQLException> of(Holder.of((R) null)) //
.cycled()
.map(it -> {
final R ret = (isNamedQuery ? JdbcUtil.prepareNamedQuery(conn, query) : JdbcUtil.prepareQuery(conn, query)) //
.setFetchDirectionToForward()
.setFetchSize(pageSize)
.settParameters(it.value(), paramSetter)
.query(resultExtractor);
it.setValue(ret);
return ret;
})
.takeWhile(JdbcUtil::isNotEmptyResult);
}
/**
* Runs a {@code Stream} with each element (page) loaded from the database table by running the specified SQL {@code query}.
*
* The query must be ordered by at least one key/id and have a result size limitation, for example, {@code LIMIT pageSize} or {@code ROWS FETCH NEXT pageSize ROWS ONLY}.
*