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.util;
import static com.landawn.abacus.dataSource.DataSourceConfiguration.DRIVER;
import static com.landawn.abacus.dataSource.DataSourceConfiguration.PASSWORD;
import static com.landawn.abacus.dataSource.DataSourceConfiguration.URL;
import static com.landawn.abacus.dataSource.DataSourceConfiguration.USER;
import static com.landawn.abacus.util.IOUtil.DEFAULT_QUEUE_SIZE_FOR_ROW_PARSER;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Date;
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.SQLFeatureNotSupportedException;
import java.sql.SQLType;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import com.landawn.abacus.DataSet;
import com.landawn.abacus.DataSource;
import com.landawn.abacus.DataSourceManager;
import com.landawn.abacus.DataSourceSelector;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.IsolationLevel;
import com.landawn.abacus.SliceSelector;
import com.landawn.abacus.Transaction;
import com.landawn.abacus.Transaction.Status;
import com.landawn.abacus.annotation.Column;
import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.condition.ConditionFactory.CF;
import com.landawn.abacus.core.RowDataSet;
import com.landawn.abacus.dataSource.DataSourceConfiguration;
import com.landawn.abacus.dataSource.DataSourceManagerConfiguration;
import com.landawn.abacus.dataSource.NonSliceSelector;
import com.landawn.abacus.dataSource.SQLDataSource;
import com.landawn.abacus.dataSource.SQLDataSourceManager;
import com.landawn.abacus.dataSource.SimpleSourceSelector;
import com.landawn.abacus.exception.AbacusException;
import com.landawn.abacus.exception.DuplicatedResultException;
import com.landawn.abacus.exception.ParseException;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.exception.UncheckedSQLException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.EntityInfo;
import com.landawn.abacus.parser.ParserUtil.PropInfo;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.ExceptionalStream.ExceptionalIterator;
import com.landawn.abacus.util.Fn.FN;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.SQLBuilder.NAC;
import com.landawn.abacus.util.SQLBuilder.NLC;
import com.landawn.abacus.util.SQLBuilder.NSC;
import com.landawn.abacus.util.SQLBuilder.PAC;
import com.landawn.abacus.util.SQLBuilder.PLC;
import com.landawn.abacus.util.SQLBuilder.PSC;
import com.landawn.abacus.util.SQLBuilder.SP;
import com.landawn.abacus.util.SQLExecutor.JdbcSettings;
import com.landawn.abacus.util.SQLExecutor.StatementSetter;
import com.landawn.abacus.util.SQLTransaction.CreatedBy;
import com.landawn.abacus.util.StringUtil.Strings;
import com.landawn.abacus.util.Try.BiFunction;
import com.landawn.abacus.util.Tuple.Tuple2;
import com.landawn.abacus.util.Tuple.Tuple3;
import com.landawn.abacus.util.Tuple.Tuple4;
import com.landawn.abacus.util.Tuple.Tuple5;
import com.landawn.abacus.util.u.Nullable;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalBoolean;
import com.landawn.abacus.util.u.OptionalByte;
import com.landawn.abacus.util.u.OptionalChar;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalFloat;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.u.OptionalShort;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.stream.Collector;
import com.landawn.abacus.util.stream.IntStream.IntStreamEx;
import com.landawn.abacus.util.stream.Stream;
import com.landawn.abacus.util.stream.Stream.StreamEx;
/**
*
* @since 0.8
*
* @author Haiyang Li
*
* @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 http://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html
* @see http://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html
* @see http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html
* @see http://docs.oracle.com/javase/8/docs/api/java/sql/ResultSet.html
*/
public final class JdbcUtil {
private static final Logger logger = LoggerFactory.getLogger(JdbcUtil.class);
// ...
private static final String CURRENT_DIR_PATH = "./";
private static final JdbcUtil.BiParametersSetter super PreparedStatement, ? super Object[]> DEFAULT_STMT_SETTER = new JdbcUtil.BiParametersSetter() {
@Override
public void accept(PreparedStatement stmt, Object[] parameters) throws SQLException {
for (int i = 0, len = parameters.length; i < len; i++) {
stmt.setObject(i + 1, parameters[i]);
}
}
};
private static final Set sqlStateForTableNotExists = new HashSet<>();
static {
sqlStateForTableNotExists.add("42S02"); // for MySQCF.
sqlStateForTableNotExists.add("42P01"); // for PostgreSQCF.
sqlStateForTableNotExists.add("42501"); // for HSQLDB.
}
private JdbcUtil() {
// singleton
}
public static DBVersion getDBVersion(final Connection conn) throws UncheckedSQLException {
try {
String dbProudctName = conn.getMetaData().getDatabaseProductName();
String dbProudctVersion = conn.getMetaData().getDatabaseProductVersion();
DBVersion dbVersion = DBVersion.OTHERS;
String upperCaseProductName = dbProudctName.toUpperCase();
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 dbVersion;
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
/**
*
* @param dataSourceXmlFile
* @return DataSourceManager
*
* @see DataSource.xsd
*/
public static DataSourceManager createDataSourceManager(final String dataSourceXmlFile) throws UncheckedIOException, UncheckedSQLException {
InputStream is = null;
try {
is = new FileInputStream(Configuration.findFile(dataSourceXmlFile));
return createDataSourceManager(is, dataSourceXmlFile);
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
IOUtil.close(is);
}
}
/**
*
* @param dataSourceXmlInputStream
* @return DataSourceManager
*
* @see DataSource.xsd
*/
public static DataSourceManager createDataSourceManager(final InputStream dataSourceXmlInputStream) throws UncheckedIOException, UncheckedSQLException {
return createDataSourceManager(dataSourceXmlInputStream, CURRENT_DIR_PATH);
}
private static final String PROPERTIES = "properties";
private static final String RESOURCE = "resource";
private static DataSourceManager createDataSourceManager(final InputStream dataSourceXmlInputStream, final String dataSourceXmlFile)
throws UncheckedIOException, UncheckedSQLException {
DocumentBuilder domParser = XMLUtil.createDOMParser();
Document doc = null;
try {
doc = domParser.parse(dataSourceXmlInputStream);
Element rootElement = doc.getDocumentElement();
final Map props = new HashMap<>();
List propertiesElementList = XMLUtil.getElementsByTagName(rootElement, PROPERTIES);
if (N.notNullOrEmpty(propertiesElementList)) {
for (Element propertiesElement : propertiesElementList) {
File resourcePropertiesFile = Configuration.findFileByFile(new File(dataSourceXmlFile), propertiesElement.getAttribute(RESOURCE));
java.util.Properties properties = new java.util.Properties();
InputStream is = null;
try {
is = new FileInputStream(resourcePropertiesFile);
if (resourcePropertiesFile.getName().endsWith(".xml")) {
properties.loadFromXML(is);
} else {
properties.load(is);
}
} finally {
IOUtil.close(is);
}
for (Object key : properties.keySet()) {
props.put((String) key, (String) properties.get(key));
}
}
}
String nodeName = rootElement.getNodeName();
if (nodeName.equals(DataSourceManagerConfiguration.DATA_SOURCE_MANAGER)) {
DataSourceManagerConfiguration config = new DataSourceManagerConfiguration(rootElement, props);
return new SQLDataSourceManager(config);
} else if (nodeName.equals(DataSourceConfiguration.DATA_SOURCE)) {
DataSourceConfiguration config = new DataSourceConfiguration(rootElement, props);
return new SimpleDataSourceManager(new SQLDataSource(config));
} else {
throw new AbacusException("Unknown xml format with root element: " + nodeName);
}
} catch (SAXException e) {
throw new ParseException(e);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
*
* @param dataSourceFile
* @return
* @throws UncheckedIOException
* @throws UncheckedSQLException
* @see DataSource.xsd
*/
public static DataSource createDataSource(final String dataSourceFile) throws UncheckedIOException, UncheckedSQLException {
InputStream is = null;
try {
is = new FileInputStream(Configuration.findFile(dataSourceFile));
return createDataSource(is, dataSourceFile);
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
IOUtil.close(is);
}
}
/**
*
* @param dataSourceInputStream
* @return
* @throws UncheckedIOException
* @throws UncheckedSQLException
* @see DataSource.xsd
*/
public static DataSource createDataSource(final InputStream dataSourceInputStream) throws UncheckedIOException, UncheckedSQLException {
return createDataSource(dataSourceInputStream, CURRENT_DIR_PATH);
}
private static DataSource createDataSource(final InputStream dataSourceInputStream, final String dataSourceFile)
throws UncheckedIOException, UncheckedSQLException {
final String dataSourceString = IOUtil.readString(dataSourceInputStream);
if (CURRENT_DIR_PATH.equals(dataSourceFile) || dataSourceFile.endsWith(".xml")) {
try {
return createDataSourceManager(new ByteArrayInputStream(dataSourceString.getBytes())).getPrimaryDataSource();
} catch (ParseException e) {
// ignore.
} catch (UncheckedIOException e) {
// ignore.
}
}
final Map newProps = new HashMap<>();
final java.util.Properties properties = new java.util.Properties();
try {
properties.load(new ByteArrayInputStream(dataSourceString.getBytes()));
Object value = null;
for (Object key : properties.keySet()) {
value = properties.get(key);
newProps.put(key.toString().trim(), value.toString().trim());
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return new SQLDataSource(newProps);
}
public static DataSource createDataSource(final String url, final String user, final String password) throws UncheckedSQLException {
return createDataSource(getDriverClasssByUrl(url), url, user, password);
}
public static DataSource createDataSource(final String driver, final String url, final String user, final String password) throws UncheckedSQLException {
final Class extends Driver> driverClass = ClassUtil.forClass(driver);
return createDataSource(driverClass, url, user, password);
}
public static DataSource createDataSource(final Class extends Driver> driverClass, final String url, final String user, final String password)
throws UncheckedSQLException {
final Map props = new HashMap<>();
props.put(DRIVER, driverClass.getCanonicalName());
props.put(URL, url);
props.put(USER, user);
props.put(PASSWORD, password);
return createDataSource(props);
}
/**
*
* @param props refer to Connection.xsd for the supported properties.
* @return
*/
public static DataSource createDataSource(final Map props) throws UncheckedSQLException {
final String driver = (String) props.get(DRIVER);
if (N.isNullOrEmpty(driver)) {
final String url = (String) props.get(URL);
if (N.isNullOrEmpty(url)) {
throw new IllegalArgumentException("Url is not specified");
}
final Map tmp = new HashMap<>(props);
tmp.put(DRIVER, getDriverClasssByUrl(url).getCanonicalName());
return new SQLDataSource(tmp);
} else {
return new SQLDataSource(props);
}
}
/**
*
* @param sqlDataSource
* @return
* @deprecated
*/
@Deprecated
public static DataSource wrap(final javax.sql.DataSource sqlDataSource) {
return sqlDataSource instanceof DataSource ? ((DataSource) sqlDataSource) : new SimpleDataSource(sqlDataSource);
}
public static Connection createConnection(final String url, final String user, final String password) throws UncheckedSQLException {
return createConnection(getDriverClasssByUrl(url), url, user, password);
}
private static Class extends Driver> getDriverClasssByUrl(final String url) {
Class extends Driver> driverClass = null;
// jdbc:mysql://localhost:3306/abacustest
if (url.indexOf("mysql") > 0 || StringUtil.indexOfIgnoreCase(url, "mysql") > 0) {
driverClass = ClassUtil.forClass("com.mysql.jdbc.Driver");
// jdbc:postgresql://localhost:5432/abacustest
} else if (url.indexOf("postgresql") > 0 || StringUtil.indexOfIgnoreCase(url, "postgresql") > 0) {
driverClass = ClassUtil.forClass("org.postgresql.Driver");
// jdbc:h2:hsql://:/
} else if (url.indexOf("h2") > 0 || StringUtil.indexOfIgnoreCase(url, "h2") > 0) {
driverClass = ClassUtil.forClass("org.h2.Driver");
// jdbc:hsqldb:hsql://localhost/abacustest
} else if (url.indexOf("hsqldb") > 0 || StringUtil.indexOfIgnoreCase(url, "hsqldb") > 0) {
driverClass = ClassUtil.forClass("org.hsqldb.jdbc.JDBCDriver");
// jdbc.url=jdbc:oracle:thin:@localhost:1521:abacustest
} else if (url.indexOf("oracle") > 0 || StringUtil.indexOfIgnoreCase(url, "oracle") > 0) {
driverClass = ClassUtil.forClass("oracle.jdbc.driver.OracleDriver");
// jdbc.url=jdbc:sqlserver://localhost:1433;Database=abacustest
} else if (url.indexOf("sqlserver") > 0 || StringUtil.indexOfIgnoreCase(url, "sqlserver") > 0) {
driverClass = ClassUtil.forClass("com.microsoft.sqlserver.jdbc.SQLServerDriver");
// jdbc:db2://localhost:50000/abacustest
} else if (url.indexOf("db2") > 0 || StringUtil.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;
}
public static Connection createConnection(final String driverClass, final String url, final String user, final String password)
throws UncheckedSQLException {
Class extends Driver> cls = ClassUtil.forClass(driverClass);
return createConnection(cls, url, user, password);
}
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 (SQLException e) {
throw new UncheckedSQLException("Failed to close create connection", e);
}
}
private static boolean isInSpring = true;
static {
try {
isInSpring = ClassUtil.forClass("org.springframework.jdbc.datasource.DataSourceUtils") != null;
} catch (Throwable e) {
isInSpring = false;
}
}
/**
* Spring Transaction is supported and Integrated.
* If this method is called where a Spring transaction is started with the specified {@code DataSource},
* the {@code Connection} started the Spring Transaction will be returned. Otherwise a {@code Connection} directly from the specified {@code DataSource}(Connection pool) will be returned.
*
* @param ds
* @return
*/
public static Connection getConnection(final javax.sql.DataSource ds) {
if (isInSpring) {
try {
return org.springframework.jdbc.datasource.DataSourceUtils.getConnection(ds);
} catch (NoClassDefFoundError e) {
isInSpring = false;
try {
return ds.getConnection();
} catch (SQLException e1) {
throw new UncheckedSQLException(e1);
}
}
} else {
try {
return ds.getConnection();
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
/**
* Spring Transaction is supported and Integrated.
* If this method is called where a Spring transaction is started with the specified {@code DataSource},
* the specified {@code Connection} won't be returned to {@code DataSource}(Connection pool) until the transaction is committed or rolled back. Otherwise the specified {@code Connection} will be directly returned back to {@code DataSource}(Connection pool).
*
*
* @param conn
* @param ds
*/
public static void releaseConnection(final Connection conn, final javax.sql.DataSource ds) {
if (conn == null) {
return;
}
if (isInSpring && ds != null) {
try {
org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(conn, ds);
} catch (NoClassDefFoundError e) {
isInSpring = false;
JdbcUtil.closeQuietly(conn);
}
} else {
JdbcUtil.closeQuietly(conn);
}
}
static Runnable createCloseHandler(final Connection conn, final javax.sql.DataSource ds) {
return new Runnable() {
@Override
public void run() {
releaseConnection(conn, ds);
}
};
}
public static void close(final ResultSet rs) throws UncheckedSQLException {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
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
*/
public static void close(final ResultSet rs, final boolean closeStatement, final boolean closeConnection)
throws IllegalArgumentException, UncheckedSQLException {
if (closeConnection && closeStatement == false) {
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 || closeConnection) {
stmt = rs.getStatement();
}
if (closeConnection && stmt != null) {
conn = stmt.getConnection();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
close(rs, stmt, conn);
}
}
public static void close(final Statement stmt) throws UncheckedSQLException {
if (stmt != null) {
try {
if (stmt instanceof PreparedStatement) {
try {
((PreparedStatement) stmt).clearParameters();
} catch (SQLException e) {
logger.error("Failed to clear parameters", e);
}
}
stmt.close();
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
public static void close(final Connection conn) throws UncheckedSQLException {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
public static void close(final ResultSet rs, final Statement stmt) throws UncheckedSQLException {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (stmt != null) {
if (stmt instanceof PreparedStatement) {
try {
((PreparedStatement) stmt).clearParameters();
} catch (SQLException e) {
logger.error("Failed to clear parameters", e);
}
}
stmt.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
public static void close(final Statement stmt, final Connection conn) throws UncheckedSQLException {
try {
if (stmt != null) {
if (stmt instanceof PreparedStatement) {
try {
((PreparedStatement) stmt).clearParameters();
} catch (SQLException e) {
logger.error("Failed to clear parameters", e);
}
}
stmt.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
public static void close(final ResultSet rs, final Statement stmt, final Connection conn) throws UncheckedSQLException {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (stmt != null) {
if (stmt instanceof PreparedStatement) {
try {
((PreparedStatement) stmt).clearParameters();
} catch (SQLException e) {
logger.error("Failed to clear parameters", e);
}
}
stmt.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
}
}
/**
* Unconditionally close an 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);
}
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 == false) {
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 || closeConnection) {
stmt = rs.getStatement();
}
if (closeConnection && stmt != null) {
conn = stmt.getConnection();
}
} catch (SQLException e) {
logger.error("Failed to get Statement or Connection by ResultSet", e);
} finally {
closeQuietly(rs, stmt, conn);
}
}
/**
* Unconditionally close an 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 Connection.
*
* Equivalent to {@link Connection#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param conn
*/
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 (Exception e) {
logger.error("Failed to close ResultSet", e);
}
}
if (stmt != null) {
if (stmt instanceof PreparedStatement) {
try {
((PreparedStatement) stmt).clearParameters();
} catch (Exception e) {
logger.error("Failed to clear parameters", e);
}
}
try {
stmt.close();
} catch (Exception e) {
logger.error("Failed to close Statement", e);
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
logger.error("Failed to close Connection", e);
}
}
}
/**
*
* @param rs
* @param n the count of row to move ahead.
* @return the number skipped.
* @throws SQLException
*/
public static int skip(final ResultSet rs, int n) throws SQLException {
return skip(rs, (long) n);
}
/**
*
* @param rs
* @param n the count of row to move ahead.
* @return the number skipped.
* @throws SQLException
* @see {@link 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() == true ? 1 : 0;
} else {
final int currentRow = rs.getRow();
if (n <= Integer.MAX_VALUE) {
try {
if (n > Integer.MAX_VALUE - rs.getRow()) {
while (n-- > 0L && rs.next()) {
}
} else {
rs.absolute((int) n + rs.getRow());
}
} catch (SQLException e) {
while (n-- > 0L && rs.next()) {
}
}
} else {
while (n-- > 0L && rs.next()) {
}
}
return rs.getRow() - currentRow;
}
}
public static int getColumnCount(ResultSet rs) throws SQLException {
return rs.getMetaData().getColumnCount();
}
/**
*
* @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 = stmt.executeQuery();
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(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;
}
public static String getColumnLabel(final ResultSetMetaData rsmd, final int columnIndex) throws SQLException {
final String result = rsmd.getColumnLabel(columnIndex);
return N.isNullOrEmpty(result) ? rsmd.getColumnName(columnIndex) : result;
}
public static Object getColumnValue(final ResultSet rs, final int columnIndex) throws SQLException {
// Copied from JdbcUtils#getResultSetValue(ResultSet, int) in SpringJdbc under Apache License, Version 2.0.
// final Object obj = rs.getObject(columnIndex);
//
// if (obj == null) {
// return obj;
// }
//
// final String className = obj.getClass().getName();
//
// if (obj instanceof Blob) {
// final Blob blob = (Blob) obj;
// return blob.getBytes(1, (int) blob.length());
// } else if (obj instanceof Clob) {
// final Clob clob = (Clob) obj;
// return clob.getSubString(1, (int) clob.length());
// } else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
// return rs.getTimestamp(columnIndex);
// } else if (className.startsWith("oracle.sql.DATE")) {
// final String columnClassName = rs.getMetaData().getColumnClassName(columnIndex);
//
// if ("java.sql.Timestamp".equals(columnClassName) || "oracle.sql.TIMESTAMP".equals(columnClassName)) {
// return rs.getTimestamp(columnIndex);
// } else {
// return rs.getDate(columnIndex);
// }
// } else if (obj instanceof java.sql.Date) {
// if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(columnIndex))) {
// return rs.getTimestamp(columnIndex);
// }
// }
//
// return obj;
return rs.getObject(columnIndex);
}
public static Object getColumnValue(final ResultSet rs, final String columnLabel) throws SQLException {
// Copied from JdbcUtils#getResultSetValue(ResultSet, int) in SpringJdbc under Apache License, Version 2.0.
// final Object obj = rs.getObject(columnLabel);
//
// if (obj == null) {
// return obj;
// }
//
// final String className = obj.getClass().getName();
//
// if (obj instanceof Blob) {
// final Blob blob = (Blob) obj;
// return blob.getBytes(1, (int) blob.length());
// } else if (obj instanceof Clob) {
// final Clob clob = (Clob) obj;
// return clob.getSubString(1, (int) clob.length());
// } else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
// return rs.getTimestamp(columnLabel);
// } else if (className.startsWith("oracle.sql.DATE")) {
// final int columnIndex = JdbcUtil.getColumnLabelList(rs).indexOf(columnLabel);
//
// if (columnIndex >= 0) {
// final String columnClassName = rs.getMetaData().getColumnClassName(columnIndex + 1);
//
// if ("java.sql.Timestamp".equals(columnClassName) || "oracle.sql.TIMESTAMP".equals(columnClassName)) {
// return rs.getTimestamp(columnLabel);
// } else {
// return rs.getDate(columnLabel);
// }
// }
// } else if (obj instanceof java.sql.Date) {
// final int columnIndex = JdbcUtil.getColumnLabelList(rs).indexOf(columnLabel);
//
// if (columnIndex >= 0) {
// if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(columnIndex + 1))) {
// return rs.getTimestamp(columnLabel);
// }
// }
// }
//
// return obj;
return rs.getObject(columnLabel);
}
public static T getColumnValue(final Class targetClass, final ResultSet rs, final int columnIndex) throws SQLException {
return N. typeOf(targetClass).get(rs, columnIndex);
}
public static T getColumnValue(final Class targetClass, final ResultSet rs, final String columnLabel) throws SQLException {
return N. typeOf(targetClass).get(rs, columnLabel);
}
/**
* Refer to: {@code beginTransaction(javax.sql.DataSource, IsolationLevel, boolean)}.
* @param dataSource
* @return
* @throws UncheckedSQLException
* @see {@link #beginTransaction(javax.sql.DataSource, IsolationLevel, boolean)}
*/
public static SQLTransaction beginTransaction(final javax.sql.DataSource dataSource) throws UncheckedSQLException {
return beginTransaction(dataSource, IsolationLevel.DEFAULT);
}
/**
* Refer to: {@code beginTransaction(javax.sql.DataSource, IsolationLevel, boolean)}.
* @param dataSource
* @param isolationLevel
* @return
* @throws UncheckedSQLException
* @see {@link #beginTransaction(javax.sql.DataSource, IsolationLevel, boolean)}
*/
public static SQLTransaction beginTransaction(final javax.sql.DataSource dataSource, final IsolationLevel isolationLevel) throws UncheckedSQLException {
return beginTransaction(dataSource, isolationLevel, false);
}
/**
* Starts a global transaction which will be shared by all in-line database query with the same {@code DataSource} in the same thread,
* including methods: {@code JdbcUtil.beginTransaction/prepareQuery/prepareNamedQuery/prepareCallableQuery, SQLExecutor(Mapper).beginTransaction/get/insert/batchInsert/update/batchUpdate/query/list/findFirst/...}
*
*
* Spring Transaction is supported and Integrated.
* If this method is called at where a Spring transaction is started with the specified {@code DataSource},
* the {@code Connection} started the Spring Transaction will be used here.
* That's to say the Spring transaction will have the final control on commit/roll back over the {@code Connection}.
*
*
*
*
* Here is the general code pattern to work with {@code SQLTransaction}.
*
*
*
* public void doSomethingA() {
* ...
* final SQLTransaction tranA = JdbcUtil.beginTransacion(dataSource1, isolation);
*
* try {
* ...
* doSomethingB(); // Share the same transaction 'tranA' because they're in the same thread and start transaction with same DataSource 'dataSource1'.
* ...
* doSomethingC(); // won't share the same transaction 'tranA' although they're in the same thread but start transaction with different DataSource 'dataSource2'.
* ...
* tranA.commit();
* } finally {
* tranA.rollbackIfNotCommitted();
* }
* }
*
* public void doSomethingB() {
* ...
* final SQLTransaction tranB = JdbcUtil.beginTransacion(dataSource1, isolation);
* try {
* // do your work with the conn...
* ...
* tranB.commit();
* } finally {
* tranB.rollbackIfNotCommitted();
* }
* }
*
* public void doSomethingC() {
* ...
* final SQLTransaction tranC = JdbcUtil.beginTransacion(dataSource2, isolation);
* try {
* // do your work with the conn...
* ...
* tranC.commit();
* } finally {
* tranC.rollbackIfNotCommitted();
* }
* }
*
*
*
* 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.beginTransacion(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
* @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, "dataSource");
N.checkArgNotNull(isolationLevel, "isolationLevel");
SQLTransaction tran = SQLTransaction.getTransaction(dataSource, CreatedBy.JDBC_UTIL);
if (tran == null) {
Connection conn = null;
boolean noException = false;
try {
conn = getConnection(dataSource);
tran = new SQLTransaction(dataSource, conn, isolationLevel, CreatedBy.JDBC_UTIL, true);
tran.incrementAndGetRef(isolationLevel, isForUpdateOnly);
noException = true;
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
if (noException == false) {
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;
}
static SQLOperation getSQLOperation(String sql) {
return StringUtil.startsWithIgnoreCase(sql.trim(), "select ") ? SQLOperation.SELECT : SQLOperation.UPDATE;
}
/**
* 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
* @param sql
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* 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
* @param sql
* @param autoGeneratedKeys
* @return
* @throws SQLException
* @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 SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql, final int[] returnColumnIndexes) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql, final String[] returnColumnNames) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* 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
* @param sql
* @param stmtCreator the created {@code PreparedStatement} will be closed after any execution methods in {@code PreparedQuery/PreparedCallableQuery} is called.
* An execution method is a method which will trigger the backed {@code PreparedStatement/CallableStatement} to be executed, for example: get/query/queryForInt/Long/../findFirst/list/execute/....
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedQuery prepareQuery(final javax.sql.DataSource ds, final String sql,
final Try.BiFunction stmtCreator) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param sql
* @return
* @throws SQLException
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(sql, "sql");
return new PreparedQuery(conn.prepareStatement(sql));
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param sql
* @param autoGeneratedKeys
* @return
* @throws SQLException
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql, final boolean autoGeneratedKeys) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(sql, "sql");
return new PreparedQuery(conn.prepareStatement(sql, autoGeneratedKeys ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS));
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param sql
* @param stmtCreator the created {@code PreparedStatement} will be closed after any execution methods in {@code PreparedQuery/PreparedCallableQuery} is called.
* An execution method is a method which will trigger the backed {@code PreparedStatement/CallableStatement} to be executed, for example: get/query/queryForInt/Long/../findFirst/list/execute/....
* @return
* @throws SQLException
* @see {@link JdbcUtil#prepareStatement(Connection, String, Object...)}
*/
public static PreparedQuery prepareQuery(final Connection conn, final String sql,
final Try.BiFunction stmtCreator) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(sql, "sql");
N.checkArgNotNull(stmtCreator, "stmtCreator");
return new PreparedQuery(stmtCreator.apply(conn, sql));
}
/**
* 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
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(namedSql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* 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
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param autoGeneratedKeys
* @return
* @throws SQLException
* @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 SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(namedSql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* 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
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnIndexes
* @return
* @throws SQLException
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql, final int[] returnColumnIndexes) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(namedSql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* 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
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnNames
* @return
* @throws SQLException
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql, final String[] returnColumnNames) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(namedSql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* 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
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param stmtCreator the created {@code PreparedStatement} will be closed after any execution methods in {@code NamedQuery/PreparedCallableQuery} is called.
* An execution method is a method which will trigger the backed {@code PreparedStatement/CallableStatement} to be executed, for example: get/query/queryForInt/Long/../findFirst/list/execute/....
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static NamedQuery prepareNamedQuery(final javax.sql.DataSource ds, final String namedSql,
final Try.BiFunction stmtCreator) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(namedSql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
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;
}
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @return
* @throws SQLException
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(namedSql, "namedSql");
final NamedSQL namedSQL = createNamedSQL(namedSql);
return new NamedQuery(conn.prepareStatement(namedSQL.getParameterizedSQL()), namedSQL);
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param autoGeneratedKeys
* @return
* @throws SQLException
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql, final boolean autoGeneratedKeys) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(namedSql, "namedSql");
final NamedSQL namedSQL = createNamedSQL(namedSql);
return new NamedQuery(
conn.prepareStatement(namedSQL.getParameterizedSQL(), autoGeneratedKeys ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS),
namedSQL);
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnIndexes
* @return
* @throws SQLException
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql, final int[] returnColumnIndexes) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(namedSql, "namedSql");
N.checkArgNotNullOrEmpty(returnColumnIndexes, "returnColumnIndexes");
final NamedSQL namedSQL = createNamedSQL(namedSql);
return new NamedQuery(conn.prepareStatement(namedSQL.getParameterizedSQL(), returnColumnIndexes), namedSQL);
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param returnColumnNames
* @return
* @throws SQLException
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql, final String[] returnColumnNames) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(namedSql, "namedSql");
N.checkArgNotNullOrEmpty(returnColumnNames, "returnColumnNames");
final NamedSQL namedSQL = createNamedSQL(namedSql);
return new NamedQuery(conn.prepareStatement(namedSQL.getParameterizedSQL(), returnColumnNames), namedSQL);
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param namedSql for example {@code SELECT first_name, last_name FROM account where id = :id}
* @param stmtCreator the created {@code PreparedStatement} will be closed after any execution methods in {@code NamedQuery/PreparedCallableQuery} is called.
* An execution method is a method which will trigger the backed {@code PreparedStatement/CallableStatement} to be executed, for example: get/query/queryForInt/Long/../findFirst/list/execute/....
* @return
* @throws SQLException
* @see {@link JdbcUtil#prepareStatement(Connection, String, Object...)}
*/
public static NamedQuery prepareNamedQuery(final Connection conn, final String namedSql,
final Try.BiFunction stmtCreator) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(namedSql, "namedSql");
N.checkArgNotNull(stmtCreator, "stmtCreator");
final NamedSQL namedSQL = createNamedSQL(namedSql);
return new NamedQuery(stmtCreator.apply(conn, namedSQL.getParameterizedSQL()), namedSQL);
}
private static NamedSQL createNamedSQL(final String namedSql) {
N.checkArgNotNullOrEmpty(namedSql, "namedSql");
final NamedSQL namedSQL = NamedSQL.parse(namedSql);
if (namedSQL.getNamedParameters().size() != namedSQL.getParameterCount()) {
throw new IllegalArgumentException("\"" + namedSql + "\" is not a valid named sql:");
}
return namedSQL;
}
/**
* 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
* @param sql
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedCallableQuery prepareCallableQuery(final javax.sql.DataSource ds, final String sql) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
return prepareCallableQuery(tran.connection(), sql);
} else {
PreparedCallableQuery 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;
}
}
/**
* 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
* @param sql
* @param stmtCreator the created {@code CallableStatement} will be closed after any execution methods in {@code PreparedQuery/PreparedCallableQuery} is called.
* An execution method is a method which will trigger the backed {@code PreparedStatement/CallableStatement} to be executed, for example: get/query/queryForInt/Long/../findFirst/list/execute/....
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedCallableQuery prepareCallableQuery(final javax.sql.DataSource ds, final String sql,
final Try.BiFunction stmtCreator) throws SQLException {
final SQLOperation sqlOperation = JdbcUtil.getSQLOperation(sql);
final SQLTransaction tran = SQLTransaction.getTransaction(ds, CreatedBy.JDBC_UTIL);
if (tran != null && (tran.isForUpdateOnly() == false || sqlOperation != SQLOperation.SELECT)) {
return prepareCallableQuery(tran.connection(), sql, stmtCreator);
} else {
PreparedCallableQuery 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;
}
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*
*
* @param conn the specified {@code conn} won't be close after this query is executed.
* @param sql
* @return
* @throws SQLException
* @see #getConnection(javax.sql.DataSource)
* @see #releaseConnection(Connection, javax.sql.DataSource)
*/
public static PreparedCallableQuery prepareCallableQuery(final Connection conn, final String sql) throws SQLException {
N.checkArgNotNull(conn, "conn");
N.checkArgNotNull(sql, "sql");
return new PreparedCallableQuery(conn.prepareCall(sql));
}
/**
* Never write below code because it will definitely cause {@code Connection} leak:
*