Please wait. This can take some minutes ...
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.
com.landawn.abacus.util.SQLExecutor Maven / Gradle / Ivy
/*
* 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 java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.io.Closeable;
import java.io.IOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
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.annotation.Beta;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.condition.ConditionFactory.L;
import com.landawn.abacus.condition.Equal;
import com.landawn.abacus.core.RowDataSet;
import com.landawn.abacus.core.sql.dataSource.SQLDataSource;
import com.landawn.abacus.dataChannel.StatementDataChannel;
import com.landawn.abacus.exception.AbacusException;
import com.landawn.abacus.exception.NonUniqueResultException;
import com.landawn.abacus.exception.UncheckedSQLException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.SQLBuilder.NE;
import com.landawn.abacus.util.SQLBuilder.NE2;
import com.landawn.abacus.util.SQLBuilder.NE3;
import com.landawn.abacus.util.SQLBuilder.SP;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.stream.Stream;
/**
* SQLExecutor is a simple sql/jdbc utility class. SQL is supported with different format:
*
*
*
* INSERT INTO account (first_name, last_name, gui, last_update_time, create_time) VALUES (?, ?, ?, ?, ?)
* INSERT INTO account (first_name, last_name, gui, last_update_time, create_time) VALUES (#{firstName}, #{lastName}, #{gui}, #{lastUpdateTime}, #{createTime})
* INSERT INTO account (first_name, last_name, gui, last_update_time, create_time) VALUES (:firstName, :lastName, :gui, :lastUpdateTime, :createTime)
*
* All these kinds of SQLs can be generated by SQLBuilder
conveniently. Parameters with format of Array/List parameters are supported for parameterized sql with '?'.
* Parameters with format of Array/List/Map/Entity are supported for parameterized SQL with named parameters.
*
*
* Here is sample of CRUD(create/read/update/delete):
*
========================================================================
*
*
static final DataSource dataSource = JdbcUtil.createDataSource(...);
static final SQLExecutor sqlExecutor = new SQLExecutor(dataSource);
...
Account account = createAccount();
// create
String sql_insert = NE.insert(GUI, FIRST_NAME, LAST_NAME, LAST_UPDATE_TIME, CREATE_TIME).into(Account.class).sql();
N.println(sql_insert);
sqlExecutor.insert(sql_insert, account);
// read
String sql_selectByGUI = NE.selectFrom(Account.class, N.asSet(DEVICES)).where(L.eq(GUI, L.QME)).sql();
N.println(sql_selectByGUI);
Account dbAccount = sqlExecutor.queryForEntity(Account.class, sql_selectByGUI, account);
assertEquals(account.getFirstName(), dbAccount.getFirstName());
// update
String sql_updateByLastName = NE.update(Account.class).set(FIRST_NAME).where(L.eq(LAST_NAME, L.QME)).sql();
N.println(sql_updateByLastName);
dbAccount.setFirstName("newFirstName");
sqlExecutor.update(sql_updateByLastName, dbAccount);
// delete
String sql_deleteByFirstName = NE.deleteFrom(Account.class).where(L.eq(FIRST_NAME, L.QME)).sql();
N.println(sql_deleteByFirstName);
sqlExecutor.update(sql_deleteByFirstName, dbAccount);
dbAccount = sqlExecutor.queryForEntity(Account.class, sql_selectByGUI, account);
assertNull(dbAccount);
*
*
* ========================================================================
*
*
* If {@code conn} argument is null or not specified, {@code SQLExecutor} is responsible to get the connection from the
* internal {@code DataSource}, start and commit/roll back transaction for batch operations if needed, and close the
* connection finally. otherwise it's user's responsibility to do such jobs if {@code conn} is specified and not null.
*
*
* The general programming way with SQLExeucte is to execute sql scripts(generated by SQLBuilder) with array/list/map/entity by calling (batch)insert/update/delete/query/... methods.
* if Transaction is required. it can be started:
*
*
* final SQLTransaction tran = sqlExecutor.beginTransaction(IsolationLevel.READ_COMMITTED);
boolean noException = false;
try {
// sqlExecutor.insert(tran.getConnection(), ...);
// sqlExecutor.update(tran.getConnection(), ...);
// sqlExecutor.query(tran.getConnection(), ...);
noException = true;
} finally {
// The connection will be automatically closed after the transaction is committed or rolled back.
if (noException) {
tran.commit();
} else {
tran.rollback();
}
}
*
*
*
* SQLExecutor is tread-safe.
*
* @since 0.8
*
* @author Haiyang Li
*
* @see
JdbcUtil
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/PreparedStatement.html
* @see
http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
*/
public final class SQLExecutor implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(SQLExecutor.class);
static final String ID = "id";
static final String QUERY_WITH_DATA_SOURCE = "queryWithDataSource";
static final StatementSetter DEFAULT_STATEMENT_SETTER = new DefaultStatementSetter();
static final ResultSetExtractor> DEFAULT_RESULT_SET_EXTRACTOR = new DefaultResultSetExtractor();
static final ResultSetExtractor
ROW_ITERATOR_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor() {
@Override
public RowIterator extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
return new RowIterator(rs, jdbcSettings.getOffset(), jdbcSettings.getCount(), true, true);
}
};
static final ResultSetExtractor EXISTS_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor() {
@Override
public Boolean extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
long offset = jdbcSettings.getOffset();
while ((offset-- > 0) && rs.next()) {
}
return offset <= 0 && rs.next();
}
};
static final ResultSetExtractor> SINGLE_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor>() {
@Override
public Nullable> extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
long offset = jdbcSettings.getOffset();
while ((offset-- > 0) && rs.next()) {
}
if (offset <= 0 && rs.next()) {
return Nullable.of(rs.getObject(1));
}
return Nullable.empty();
}
};
static final ResultSetExtractor> LIST_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor>() {
@Override
public List extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
N.checkArgument(rs.getMetaData().getColumnCount() == 1, "Multiple columns selected in sql %s", namedSQL.getPureSQL());
long offset = jdbcSettings.getOffset();
long count = jdbcSettings.getCount();
while ((offset-- > 0) && rs.next()) {
}
final List result = new ArrayList<>((int) N.min(count, 16));
while (count-- > 0 && rs.next()) {
result.add(rs.getObject(1));
}
return result;
}
};
@SuppressWarnings("rawtypes")
private static final ResultSetExtractor ENTITY_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor() {
@SuppressWarnings("deprecation")
@Override
public Object extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
long offset = jdbcSettings.getOffset();
while ((offset-- > 0) && rs.next()) {
}
if (offset <= 0 && rs.next()) {
final List columnLabelList = getColumnLabelList(namedSQL, rs);
final int columnCount = columnLabelList.size();
final Object entity = N.newInstance(cls);
if (Map.class.isAssignableFrom(cls)) {
final Map m = (Map) entity;
for (int i = 0; i < columnCount; i++) {
m.put(columnLabelList.get(i), rs.getObject(i + 1));
}
} else {
// Method method = null;
//
// for (int i = 0; i < columnCount; i++) {
// method = N.getPropSetMethod(cls, columnLabelList.get(i));
//
// if (method != null) {
// N.setPropValue(entity, method, rs.getObject(i + 1));
// }
// }
for (int i = 0; i < columnCount; i++) {
ClassUtil.setPropValue(entity, columnLabelList.get(i), rs.getObject(i + 1), true);
}
if (N.isDirtyMarker(cls)) {
((DirtyMarker) entity).markDirty(false);
}
}
return entity;
}
return null;
}
};
@SuppressWarnings("rawtypes")
private static final ResultSetExtractor ENTITY_LIST_RESULT_SET_EXTRACTOR = new AbstractResultSetExtractor>() {
@SuppressWarnings("deprecation")
@Override
public List extractData(final Class> cls, final NamedSQL namedSQL, final ResultSet rs, final JdbcSettings jdbcSettings) throws SQLException {
final List resultList = new ArrayList<>();
long offset = jdbcSettings.getOffset();
long count = jdbcSettings.getCount();
while ((offset-- > 0) && rs.next()) {
}
if (offset <= 0 && count > 0) {
final String[] columnLabels = getColumnLabelList(namedSQL, rs).toArray(N.EMPTY_STRING_ARRAY);
final int columnCount = columnLabels.length;
final boolean isMap = Map.class.isAssignableFrom(cls);
final boolean isDirtyMarker = N.isDirtyMarker(cls);
while ((count-- > 0) && rs.next()) {
final Object entity = N.newInstance(cls);
if (isMap) {
final Map m = (Map) entity;
for (int i = 0; i < columnCount; i++) {
m.put(columnLabels[i], rs.getObject(i + 1));
}
} else {
// Method method = null;
//
// for (int i = 0; i < columnCount; i++) {
// method = N.getPropSetMethod(cls, columnLabelList.get(i));
//
// if (method != null) {
// N.setPropValue(entity, method, rs.getObject(i + 1));
// }
// }
for (int i = 0; i < columnCount; i++) {
ClassUtil.setPropValue(entity, columnLabels[i], rs.getObject(i + 1), true);
}
if (isDirtyMarker) {
((DirtyMarker) entity).markDirty(false);
}
}
resultList.add(entity);
}
}
return resultList;
}
};
private static final int factor = Math.min(Math.max(1, IOUtil.MAX_MEMORY_IN_MB / 1024), 8);
private static final int CACHED_SQL_LENGTH = 1024 * factor;
private static final int SQL_CACHE_SIZE = 1000 * factor;
private static final Map> _sqlColumnLabelPool = new ConcurrentHashMap<>();
private final Map> _tableColumnNamePool = new ConcurrentHashMap<>();
private final DataSource _ds;
private final DataSourceManager _dsm;
private final DataSourceSelector _dss;
private final JdbcSettings _jdbcSettings;
private final SQLMapper _sqlMapper;
private final NamingPolicy _namingPolicy;
private final AsyncExecutor _asyncExecutor;
private final boolean _isReadOnly;
private final String _dbProudctName;
private final String _dbProudctVersion;
private final DBVersion _dbVersion;
private final IsolationLevel _defaultIsolationLevel;
private final AsyncSQLExecutor _asyncSQLExecutor;
private final Map, Mapper>> mapperPool = new ConcurrentHashMap<>();
/**
*
* @param dataSource
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource) {
this(dataSource, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings) {
this(dataSource, jdbcSettings, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @param sqlMapper
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper) {
this(dataSource, jdbcSettings, sqlMapper, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @param sqlMapper
* @param namingPolicy
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy) {
this(dataSource, jdbcSettings, sqlMapper, namingPolicy, null);
}
/**
*
* @param dataSource
* @param jdbcSettings
* @param sqlMapper
* @param asyncExecutor
* @see JdbcUtil#createDataSource(String)
* @see JdbcUtil#createDataSource(java.io.InputStream)
*/
public SQLExecutor(final javax.sql.DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy,
final AsyncExecutor asyncExecutor) {
this(null, JdbcUtil.wrap(dataSource), jdbcSettings, sqlMapper, namingPolicy, asyncExecutor, false);
}
/**
*
* @param dataSourceManager
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager) {
this(dataSourceManager, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings) {
this(dataSourceManager, jdbcSettings, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @param sqlMapper
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper) {
this(dataSourceManager, jdbcSettings, sqlMapper, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @param sqlMapper
* @param namingPolicy
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy) {
this(dataSourceManager, jdbcSettings, sqlMapper, namingPolicy, null);
}
/**
*
* @param dataSourceManager
* @param jdbcSettings
* @param sqlMapper
* @param asyncExecutor
* @see JdbcUtil#createDataSourceManager(String)
* @see JdbcUtil#createDataSourceManager(java.io.InputStream)
*/
public SQLExecutor(final DataSourceManager dataSourceManager, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper, final NamingPolicy namingPolicy,
final AsyncExecutor asyncExecutor) {
this(dataSourceManager, null, jdbcSettings, sqlMapper, namingPolicy, asyncExecutor, false);
}
protected SQLExecutor(final DataSourceManager dataSourceManager, final DataSource dataSource, final JdbcSettings jdbcSettings, final SQLMapper sqlMapper,
final NamingPolicy namingPolicy, final AsyncExecutor asyncExecutor, final boolean isReadOnly) {
if (dataSourceManager == null) {
this._ds = dataSource;
this._dsm = null;
this._dss = null;
} else {
this._ds = dataSourceManager.getPrimaryDataSource();
this._dsm = dataSourceManager;
this._dss = dataSourceManager.getDataSourceSelector();
}
this._jdbcSettings = (jdbcSettings == null) ? JdbcSettings.create() : jdbcSettings.copy();
if (_jdbcSettings.getBatchSize() == 0) {
_jdbcSettings.setBatchSize(JdbcSettings.DEFAULT_BATCH_SIZE);
}
_jdbcSettings.freeze();
this._sqlMapper = sqlMapper;
this._namingPolicy = namingPolicy == null ? NamingPolicy.LOWER_CASE_WITH_UNDERSCORE : namingPolicy;
this._asyncExecutor = asyncExecutor == null ? new AsyncExecutor(64, 300, TimeUnit.SECONDS) : asyncExecutor;
this._isReadOnly = isReadOnly;
Connection conn = getConnection();
try {
_dbProudctName = conn.getMetaData().getDatabaseProductName();
_dbProudctVersion = conn.getMetaData().getDatabaseProductVersion();
_dbVersion = JdbcUtil.getDBVersion(conn);
} catch (SQLException e) {
throw new UncheckedSQLException(e);
} finally {
closeQuietly(conn);
}
_defaultIsolationLevel = this._ds instanceof SQLDataSource ? ((SQLDataSource) this._ds).getDefaultIsolationLevel() : IsolationLevel.DEFAULT;
this._asyncSQLExecutor = new AsyncSQLExecutor(this, _asyncExecutor);
}
// public static SQLExecutor create(final String dataSourceFile) {
// return new SQLExecutor(JdbcUtil.createDataSourceManager(dataSourceFile));
// }
//
// public static SQLExecutor create(final InputStream dataSourceInputStream) {
// return new SQLExecutor(JdbcUtil.createDataSourceManager(dataSourceInputStream));
// }
//
// public static SQLExecutor create(final String url, final String user, final String password) {
// return new SQLExecutor(JdbcUtil.createDataSource(url, user, password));
// }
//
// public static SQLExecutor create(final String driver, final String url, final String user, final String password) {
// return new SQLExecutor(JdbcUtil.createDataSource(driver, url, user, password));
// }
//
// public static SQLExecutor create(final Class extends Driver> driverClass, final String url, final String user, final String password) {
// return new SQLExecutor(JdbcUtil.createDataSource(driverClass, url, user, password));
// }
//
// /**
// *
// * @param props refer to Connection.xsd for the supported properties.
// * @return
// */
// public static SQLExecutor create(final Map props) {
// return new SQLExecutor(JdbcUtil.createDataSource(props));
// }
//
// public static SQLExecutor create(final javax.sql.DataSource sqlDataSource) {
// return new SQLExecutor(JdbcUtil.wrap(sqlDataSource));
// }
//
// public SQLMapper sqlMapper() {
// return _sqlMapper;
// }
@Beta
public static SQLExecutor w(final String url, final String user, final String password) {
return new SQLExecutor(JdbcUtil.createDataSource(url, user, password));
}
@Beta
public static SQLExecutor w(final String driver, final String url, final String user, final String password) {
return new SQLExecutor(JdbcUtil.createDataSource(driver, url, user, password));
}
@Beta
public static SQLExecutor w(final Class extends Driver> driverClass, final String url, final String user, final String password) {
return new SQLExecutor(JdbcUtil.createDataSource(driverClass, url, user, password));
}
public Mapper mapper(final Class targetClass) {
Mapper mapper = (Mapper) mapperPool.get(targetClass);
if (mapper == null) {
N.checkArgument(N.isEntity(targetClass), ClassUtil.getCanonicalClassName(targetClass) + " is not an entity class with getter/setter methods");
mapper = new Mapper(targetClass, this, this._namingPolicy);
mapperPool.put(targetClass, mapper);
}
return mapper;
}
// /**
// * Create a Mapper
which has the same life cycle as the specified Connection
.
// * To start transaction for a Mapper
:
// *
// *
// * final Transaction tran = sqlExecutor.beginTransaction(isolationLevel);
// * final ExMapper mapper = sqlExecutor.mapper(targetClass, tran.connection());
// * boolean isOk = false;
// * try {
// * // Do something with sqlExecutor and mapper
// * isOk = true;
// * } finally {
// * if (isOk) {
// * tran.commit();
// * } else {
// * tran.rollback();
// * }
// * }
// *
// *
// *
// * @param targetClass
// * @param conn
// * @return
// */
// public ExMapper mapper(final Class targetClass, final Connection conn) {
// if (conn == null) {
// return mapper(targetClass);
// }
//
// return new ExMapper(conn, targetClass, this, this._namingPolicy);
// }
public AsyncSQLExecutor async() {
return _asyncSQLExecutor;
}
public DataSource dataSource() {
return _ds;
}
public JdbcSettings jdbcSettings() {
return _jdbcSettings;
}
public String dbProudctName() {
return _dbProudctName;
}
public String dbProudctVersion() {
return _dbProudctVersion;
}
public DBVersion dbVersion() {
return _dbVersion;
}
@SafeVarargs
public final T insert(final String sql, final Object... parameters) {
return insert(null, sql, null, null, parameters);
}
@SafeVarargs
public final T insert(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return insert(null, sql, statementSetter, null, parameters);
}
@SafeVarargs
public final T insert(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return insert(null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final T insert(final Connection conn, final String sql, final Object... parameters) {
return insert(conn, sql, null, null, parameters);
}
@SafeVarargs
public final T insert(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return insert(conn, sql, statementSetter, null, parameters);
}
/**
* @see #batchInsert(Connection, String, StatementSetter, JdbcSettings, String, Object[])
*/
@SuppressWarnings({ "unchecked", "deprecation" })
@SafeVarargs
public final T insert(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings, final Object... parameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
String idPropName = checkGeneratedIdPropName(jdbcSettings);
DataSource ds = null;
Connection localConn = null;
Object result = null;
PreparedStatement stmt = null;
try {
ds = getDataSource(namedSQL.getPureSQL(), parameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.RETURN_GENERATED_KEYS, false, parameters);
result = executeInsert(namedSQL, stmt);
} catch (SQLException e) {
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
closeQuietly(stmt, localConn, conn);
}
if ((result != null) && isEntityOrMapParameter(namedSQL, parameters)) {
Object parameter_0 = (parameters[0] instanceof TypedParameters) ? ((TypedParameters) parameters[0]).parameters[0] : parameters[0];
if (parameter_0 instanceof Map) {
// // don't update input map ?
// Map m = (Map) parameter_0;
// Object idPropValue = m.get(generatedIdPropName);
//
// if ((idPropValue == null)
// || (idPropValue instanceof Number
// && (((Number) idPropValue).longValue() == 0))) {
// m.put(generatedIdPropName, result);
// }
} else {
final Object entity = parameter_0;
try {
Method idGetMethod = ClassUtil.getPropGetMethod(entity.getClass(), idPropName);
Method idSetMethod = ClassUtil.getPropSetMethod(entity.getClass(), idPropName);
if ((idGetMethod != null) && (idSetMethod != null)) {
Object idPropValue = ClassUtil.getPropValue(entity, idGetMethod);
if ((idPropValue == null) || (idPropValue instanceof Number && (((Number) idPropValue).longValue() == 0))) {
ClassUtil.setPropValue(entity, idSetMethod, result);
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("Failed to set the returned id property to entity. no get/set method for id property (" + idPropName + ") found. ");
}
}
} catch (Exception e) {
logger.error("Failed to set the returned id property to entity", e);
}
if (entity instanceof DirtyMarker) {
((DirtyMarker) entity).dirtyPropNames().clear();
}
}
}
return (T) result;
}
protected Object executeInsert(final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
stmt.executeUpdate();
Object id = null;
ResultSet rs = null;
try {
rs = stmt.getGeneratedKeys();
if (rs.next()) {
id = rs.getObject(1);
}
} catch (SQLException e) {
logger.error("Failed to retrieve the auto-generated Ids", e);
} finally {
closeQuietly(rs);
}
return id;
}
List batchInsert(final String sql, final Object[] parametersList) {
return batchInsert(null, sql, null, null, parametersList);
}
List batchInsert(final String sql, final StatementSetter statementSetter, final Object[] parametersList) {
return batchInsert(null, sql, statementSetter, null, parametersList);
}
List batchInsert(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object[] parametersList) {
return batchInsert(null, sql, statementSetter, jdbcSettings, parametersList);
}
List batchInsert(final Connection conn, final String sql, final Object[] parametersList) {
return batchInsert(conn, sql, null, null, parametersList);
}
List batchInsert(final Connection conn, final String sql, final StatementSetter statementSetter, final Object[] parametersList) {
return batchInsert(conn, sql, statementSetter, null, parametersList);
}
/**
* Returns the auto-generated key by preparing statement
* {@code prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)} {@code null} is returned if no auto-generated key.
*
* Call {@code update} instead if there is no auto-generated key.
*
* @param conn
* @param sql
* @param statementSetter
* @param props
* @param parametersList
* @return
*/
List batchInsert(final Connection conn, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object[] parametersList) {
return batchInsert(conn, sql, statementSetter, jdbcSettings, Arrays.asList(parametersList));
}
public List batchInsert(final String sql, final List> parametersList) {
return batchInsert(null, sql, null, null, parametersList);
}
public List batchInsert(final String sql, final StatementSetter statementSetter, final List> parametersList) {
return batchInsert(null, sql, statementSetter, null, parametersList);
}
public List batchInsert(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final List> parametersList) {
return batchInsert(null, sql, statementSetter, jdbcSettings, parametersList);
}
public List batchInsert(final Connection conn, final String sql, final List> parametersList) {
return batchInsert(conn, sql, null, null, parametersList);
}
public List batchInsert(final Connection conn, final String sql, final StatementSetter statementSetter, final List> parametersList) {
return batchInsert(conn, sql, statementSetter, null, parametersList);
}
/**
*
* @see #batchInsert(Connection, String, StatementSetter, JdbcSettings, Object[])
*/
@SuppressWarnings("deprecation")
public List batchInsert(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings,
final List> parametersList) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
String idPropName = checkGeneratedIdPropName(jdbcSettings);
final int len = parametersList.size();
final int batchSize = getBatchSize(jdbcSettings);
List resultIdList = new ArrayList<>(len);
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
int isolationLevel = 0;
boolean autoCommit = true;
try {
ds = getDataSource(namedSQL.getPureSQL(), parametersList, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
try {
isolationLevel = localConn.getTransactionIsolation();
autoCommit = localConn.getAutoCommit();
} catch (SQLException e) {
closeQuietly(null, localConn, conn);
throw new UncheckedSQLException(e, namedSQL.toString());
}
if ((conn == null) && (len > batchSize)) {
localConn.setAutoCommit(false);
if (jdbcSettings.getIsolationLevel() == null || jdbcSettings.getIsolationLevel() == IsolationLevel.DEFAULT) {
// ignore. by default
} else {
localConn.setTransactionIsolation(jdbcSettings.getIsolationLevel().intValue());
}
}
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.RETURN_GENERATED_KEYS, true, parametersList);
if (len <= batchSize) {
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, parametersList.get(i));
stmt.addBatch();
}
executeBatchInsert(resultIdList, namedSQL, stmt);
} else {
int num = 0;
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, parametersList.get(i));
stmt.addBatch();
num++;
if ((num % batchSize) == 0) {
executeBatchInsert(resultIdList, namedSQL, stmt);
}
}
if ((num % batchSize) > 0) {
executeBatchInsert(resultIdList, namedSQL, stmt);
}
}
if ((conn == null) && (len > batchSize)) {
localConn.commit();
}
} catch (SQLException e) {
if ((conn == null) && (len > batchSize)) {
if (logger.isWarnEnabled()) {
logger.warn("Trying to roll back ...");
}
try {
localConn.rollback();
if (logger.isWarnEnabled()) {
logger.warn("succeeded to roll back");
}
} catch (SQLException e1) {
logger.error("Failed to roll back", e1);
}
}
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
if ((conn == null) && (len > batchSize)) {
try {
localConn.setAutoCommit(autoCommit);
localConn.setTransactionIsolation(isolationLevel);
} catch (SQLException e) {
logger.error("Failed to reset AutoCommit", e);
}
}
closeQuietly(stmt, localConn, conn);
}
if (N.notNullOrEmpty(resultIdList)) {
if (isEntityOrMapParameter(namedSQL, parametersList.get(0))) {
if (resultIdList.size() == len) {
boolean isTypedParameter = parametersList.get(0) instanceof TypedParameters;
Object parameter_0 = isTypedParameter ? ((TypedParameters) parametersList.get(0)).parameters[0] : parametersList.get(0);
if (parameter_0 instanceof Map) {
// // don't update input map ?
// Map m = null;
// Object idPropValue = null;
//
// for (int i = 0; i < parameters.length; i++) {
// m = (Map) (isTypedParameter
// ? ((TypedParameters) parameters[i]).parameters[0] :
// parameters[i]);
// idPropValue = m.get(generatedIdPropName);
//
// if ((idPropValue == null)
// || (idPropValue instanceof Number
// && (((Number) idPropValue).longValue() == 0))) {
// m.put(generatedIdPropName, resultList.get(i));
// }
// }
} else {
try {
Method idGetMethod = ClassUtil.getPropGetMethod(parameter_0.getClass(), idPropName);
Method idSetMethod = ClassUtil.getPropSetMethod(parameter_0.getClass(), idPropName);
if ((idGetMethod != null) && (idSetMethod != null)) {
Object entity = null;
Object idPropValue = null;
for (int i = 0; i < len; i++) {
entity = (isTypedParameter ? ((TypedParameters) parametersList.get(i)).parameters[0] : parametersList.get(i));
idPropValue = ClassUtil.invokeMethod(entity, idGetMethod);
if ((idPropValue == null) || (idPropValue instanceof Number && (((Number) idPropValue).longValue() == 0))) {
ClassUtil.setPropValue(entity, idSetMethod, resultIdList.get(i));
}
if (entity instanceof DirtyMarker) {
((DirtyMarker) entity).dirtyPropNames().clear();
}
}
} else {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to set the returned id property to entity. no get/set method for id property (" + idPropName + ") found. ");
}
}
} catch (Exception e) {
logger.error("Failed to set the returned id property to entity", e);
}
}
} else {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to set the returned id property to entity/map. because the size of returned key not equals the lenght of the input arrray");
}
}
}
}
return resultIdList;
}
protected void executeBatchInsert(final List resultIdList, final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
stmt.executeBatch();
ResultSet rs = null;
try {
rs = stmt.getGeneratedKeys();
while (rs.next()) {
resultIdList.add((T) rs.getObject(1));
}
} catch (SQLException e) {
logger.error("Failed to retrieve the auto-generated Ids", e);
} finally {
closeQuietly(rs);
}
stmt.clearBatch();
}
@SafeVarargs
public final int update(final String sql, final Object... parameters) {
return update(null, sql, null, null, parameters);
}
@SafeVarargs
public final int update(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return update(null, sql, statementSetter, null, parameters);
}
@SafeVarargs
public final int update(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return update(null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final int update(final Connection conn, final String sql, final Object... parameters) {
return update(conn, sql, null, null, parameters);
}
@SafeVarargs
public final int update(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return update(conn, sql, statementSetter, null, parameters);
}
/**
* @see #batchUpdate(Connection, String, StatementSetter, JdbcSettings, Object[])
*/
@SafeVarargs
public final int update(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings, final Object... parameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
try {
ds = getDataSource(namedSQL.getPureSQL(), parameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.NO_GENERATED_KEYS, false, parameters);
return executeUpdate(namedSQL, stmt);
} catch (SQLException e) {
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
closeQuietly(stmt, localConn, conn);
}
}
protected int executeUpdate(final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
return stmt.executeUpdate();
}
int batchUpdate(final String sql, final Object[] parametersList) {
return batchUpdate(null, sql, null, null, parametersList);
}
int batchUpdate(final String sql, final StatementSetter statementSetter, final Object[] parametersList) {
return batchUpdate(null, sql, statementSetter, null, parametersList);
}
int batchUpdate(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object[] parametersList) {
return batchUpdate(null, sql, statementSetter, jdbcSettings, parametersList);
}
int batchUpdate(final Connection conn, final String sql, final Object[] parametersList) {
return batchUpdate(conn, sql, null, null, parametersList);
}
int batchUpdate(final Connection conn, final String sql, final StatementSetter statementSetter, final Object[] parametersList) {
return batchUpdate(conn, sql, statementSetter, null, parametersList);
}
/**
* batch insert/update/delete sql scripts are supported
*
* @param conn
* @param sql
* @param statementSetter
* @param props
* @param parametersList
* @return
*/
int batchUpdate(final Connection conn, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object[] parametersList) {
return batchUpdate(conn, sql, statementSetter, jdbcSettings, Arrays.asList(parametersList));
}
public int batchUpdate(final String sql, final List> parametersList) {
return batchUpdate(null, sql, null, null, parametersList);
}
public int batchUpdate(final String sql, final StatementSetter statementSetter, final List> parametersList) {
return batchUpdate(null, sql, statementSetter, null, parametersList);
}
public int batchUpdate(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final List> parametersList) {
return batchUpdate(null, sql, statementSetter, jdbcSettings, parametersList);
}
public int batchUpdate(final Connection conn, final String sql, final List> parametersList) {
return batchUpdate(conn, sql, null, null, parametersList);
}
public int batchUpdate(final Connection conn, final String sql, final StatementSetter statementSetter, final List> parametersList) {
return batchUpdate(conn, sql, statementSetter, null, parametersList);
}
/**
* @see #batchUpdate(Connection, String, StatementSetter, JdbcSettings, Object[])
*/
public int batchUpdate(final Connection conn, final String sql, StatementSetter statementSetter, JdbcSettings jdbcSettings, final List> parametersList) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
final int len = parametersList.size();
final int batchSize = getBatchSize(jdbcSettings);
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
int isolationLevel = 0;
boolean autoCommit = true;
try {
ds = getDataSource(namedSQL.getPureSQL(), parametersList, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
try {
isolationLevel = localConn.getTransactionIsolation();
autoCommit = localConn.getAutoCommit();
} catch (SQLException e) {
closeQuietly(null, localConn, conn);
throw new UncheckedSQLException(e, namedSQL.toString());
}
if ((conn == null) && (len > batchSize)) {
localConn.setAutoCommit(false);
if (jdbcSettings.getIsolationLevel() == null || jdbcSettings.getIsolationLevel() == IsolationLevel.DEFAULT) {
// ignore. by default
} else {
localConn.setTransactionIsolation(jdbcSettings.getIsolationLevel().intValue());
}
}
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.NO_GENERATED_KEYS, true, parametersList);
int result = 0;
if (len <= batchSize) {
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, parametersList.get(i));
stmt.addBatch();
}
result += executeBatchUpdate(namedSQL, stmt);
} else {
int num = 0;
for (int i = 0; i < len; i++) {
statementSetter.setParameters(namedSQL, stmt, parametersList.get(i));
stmt.addBatch();
num++;
if ((num % batchSize) == 0) {
result += executeBatchUpdate(namedSQL, stmt);
}
}
if ((num % batchSize) > 0) {
result += executeBatchUpdate(namedSQL, stmt);
}
}
if ((conn == null) && (len > batchSize)) {
localConn.commit();
}
return result;
} catch (SQLException e) {
if ((conn == null) && (len > batchSize)) {
if (logger.isWarnEnabled()) {
logger.warn("Trying to roll back ...");
}
try {
localConn.rollback();
if (logger.isWarnEnabled()) {
logger.warn("succeeded to roll back");
}
} catch (SQLException e1) {
logger.error("Failed to roll back", e1);
}
}
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
if ((conn == null) && (len > batchSize)) {
try {
localConn.setAutoCommit(autoCommit);
localConn.setTransactionIsolation(isolationLevel);
} catch (SQLException e) {
logger.error("Failed to reset AutoCommit", e);
}
}
closeQuietly(stmt, localConn, conn);
}
}
protected int executeBatchUpdate(final NamedSQL namedSQL, final PreparedStatement stmt) throws SQLException {
if (_isReadOnly) {
throw new AbacusException("This SQL Executor is configured for read-only");
}
final int[] results = stmt.executeBatch();
stmt.clearBatch();
if ((results == null) || (results.length == 0)) {
return 0;
}
int sum = 0;
for (int i = 0; i < results.length; i++) {
sum += results[i];
}
return sum;
}
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int update(final EntityId entityId, final Map props) {
// return update(null, entityId, props);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int update(final Connection conn, final EntityId entityId, final Map props) {
// final Pair2 pair = generateUpdateSQL(entityId, props);
//
// return update(conn, pair.sql, pair.parameters);
// }
//
// private Pair2 generateUpdateSQL(final EntityId entityId, final Map props) {
// final Condition cond = EntityManagerUtil.entityId2Condition(entityId);
// final NamingPolicy namingPolicy = _jdbcSettings.getNamingPolicy();
//
// if (namingPolicy == null) {
// return NE.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// switch (namingPolicy) {
// case LOWER_CASE_WITH_UNDERSCORE: {
// return NE.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// case UPPER_CASE_WITH_UNDERSCORE: {
// return NE2.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// case CAMEL_CASE: {
// return NE3.update(entityId.entityName()).set(props).where(cond).pair();
// }
//
// default:
// throw new AbacusException("Unsupported naming policy");
// }
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int delete(final EntityId entityId) {
// return delete(null, entityId);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// int delete(final Connection conn, final EntityId entityId) {
// final Pair2 pair = generateDeleteSQL(entityId);
//
// return update(conn, pair.sql, pair.parameters);
// }
//
// private Pair2 generateDeleteSQL(final EntityId entityId) {
// final Condition cond = EntityManagerUtil.entityId2Condition(entityId);
// final NamingPolicy namingPolicy = _jdbcSettings.getNamingPolicy();
//
// if (namingPolicy == null) {
// return NE.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// switch (namingPolicy) {
// case LOWER_CASE_WITH_UNDERSCORE: {
// return NE.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// case UPPER_CASE_WITH_UNDERSCORE: {
// return NE2.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// case CAMEL_CASE: {
// return NE3.deleteFrom(entityId.entityName()).where(cond).pair();
// }
//
// default:
// throw new AbacusException("Unsupported naming policy");
// }
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// boolean exists(final EntityId entityId) {
// return exists(null, entityId);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// boolean exists(final Connection conn, final EntityId entityId) {
// final Pair2 pair = generateQuerySQL(entityId, NE._1_list);
//
// return query(conn, pair.sql, null, EXISTS_RESULT_SET_EXTRACTOR, null, pair.parameters);
// }
@SafeVarargs
public final boolean exists(final String sql, final Object... parameters) {
return exists(null, sql, parameters);
}
@SafeVarargs
public final boolean exists(final Connection conn, final String sql, final Object... parameters) {
return query(conn, sql, null, EXISTS_RESULT_SET_EXTRACTOR, null, parameters);
}
@SafeVarargs
public final int count(final String sql, final Object... parameters) {
return count(null, sql, parameters);
}
@SafeVarargs
public final int count(final Connection conn, final String sql, final Object... parameters) {
return queryForSingleResult(int.class, conn, sql, parameters).orElse(0);
}
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final EntityId entityId, final String... selectPropNames) {
// return get(targetClass, entityId, N.asList(selectPropNames));
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final EntityId entityId, final Collection selectPropNames) {
// return get(targetClass, null, entityId, selectPropNames);
// }
//
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final Connection conn, final EntityId entityId, final String... selectPropNames) {
// return get(targetClass, conn, entityId, N.asList(selectPropNames));
// }
//
// /**
// *
// * @param targetClass
// * @param conn
// * @param entityId
// * @param selectPropNames
// * @return NonUniqueResultException if more than one records are found.
// */
// // mess up. To uncomment this method, also need to modify getNamingPolicy/setNamingPolicy in JdbcSettings.
// T get(final Class targetClass, final Connection conn, final EntityId entityId, final Collection selectPropNames) {
// final Pair2 pair = generateQuerySQL(entityId, selectPropNames);
// final List entities = find(targetClass, conn, pair.sql, pair.parameters);
//
// if (entities.size() > 1) {
// throw new NonUniqueResultException("More than one records found by EntityId: " + entityId.toString());
// }
//
// return (entities.size() > 0) ? entities.get(0) : null;
// }
//
// private Pair2 generateQuerySQL(final EntityId entityId, final Collection selectPropNames) {
// final Condition cond = EntityManagerUtil.entityId2Condition(entityId);
// final NamingPolicy namingPolicy = _jdbcSettings.getNamingPolicy();
//
// if (namingPolicy == null) {
// return NE.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// switch (namingPolicy) {
// case LOWER_CASE_WITH_UNDERSCORE: {
// return NE.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// case UPPER_CASE_WITH_UNDERSCORE: {
// return NE2.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// case CAMEL_CASE: {
// return NE3.select(selectPropNames).from(entityId.entityName()).where(cond).limit(2).pair();
// }
//
// default:
// throw new AbacusException("Unsupported naming policy");
// }
// }
@SafeVarargs
public final T get(final Class targetClass, final String sql, final Object... parameters) {
return get(targetClass, sql, null, null, parameters);
}
@SafeVarargs
public final T get(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return get(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final T get(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return get(targetClass, conn, sql, null, null, parameters);
}
/**
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
* @throws NonUniqueResultException if two or more records are found.
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public final T get(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
JdbcSettings jdbcSettings, final Object... parameters) {
jdbcSettings = jdbcSettings == null ? _jdbcSettings.copy() : jdbcSettings.copy();
jdbcSettings.setCount(2);
final List entities = find(targetClass, conn, sql, statementSetter, jdbcSettings, parameters);
if (entities.size() > 1) {
throw new NonUniqueResultException("More than one records found by sql: " + sql);
}
return (entities.size() > 0) ? entities.get(0) : null;
}
@SafeVarargs
public final Optional gett(final Class targetClass, final String sql, final Object... parameters) {
return Optional.ofNullable(this.get(targetClass, sql, parameters));
}
@SafeVarargs
public final Optional gett(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return Optional.ofNullable(this.get(targetClass, sql, statementSetter, jdbcSettings, parameters));
}
@SafeVarargs
public final Optional gett(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return Optional.ofNullable(this.get(targetClass, conn, sql, parameters));
}
@SafeVarargs
public final Optional gett(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
JdbcSettings jdbcSettings, final Object... parameters) {
return Optional.ofNullable(this.get(targetClass, conn, sql, statementSetter, jdbcSettings, parameters));
}
@SafeVarargs
public final List find(final Class targetClass, final String sql, final Object... parameters) {
return find(targetClass, sql, null, null, parameters);
}
@SafeVarargs
public final List find(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return find(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final List find(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return find(targetClass, conn, sql, null, null, parameters);
}
/**
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public final List find(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
return (List) query(targetClass, conn, sql, statementSetter, ENTITY_LIST_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
}
@SafeVarargs
public final List findAll(final Class targetClass, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, sql, null, jdbcSettings, parameters);
}
@SafeVarargs
public final List findAll(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return findAll(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
List findAll(final Class targetClass, final Connection conn, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, conn, sql, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql in parallel. Mostly it's designed
* for partition to query the partitioning table in more than one databases.
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
List findAll(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
return queryAll(conn, sql, statementSetter, jdbcSettings, parameters).toList(targetClass);
}
@SafeVarargs
public final List findAll(final Class targetClass, final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, sqls, null, jdbcSettings, parameters);
}
@SafeVarargs
public final List findAll(final Class targetClass, final List sqls, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
return findAll(targetClass, null, sqls, statementSetter, jdbcSettings, parameters);
}
List findAll(final Class targetClass, final Connection conn, final List sqls, final JdbcSettings jdbcSettings,
final Object... parameters) {
return findAll(targetClass, conn, sqls, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql list in parallel. Mostly it's designed
* for partition to query multiple partitioning tables in one or more databases.
*
* @param targetClass
* @param conn
* @param sqls
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
List findAll(final Class targetClass, final Connection conn, final List sqls, final StatementSetter statementSetter,
JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(conn, sqls, statementSetter, jdbcSettings, parameters).toList(targetClass);
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalBoolean queryForBoolean(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(boolean.class, null, sql, parameters);
return result.isPresent() ? OptionalBoolean.of(result.get()) : OptionalBoolean.empty();
}
/**
*
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalChar queryForChar(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(char.class, null, sql, parameters);
return result.isPresent() ? OptionalChar.of(result.get()) : OptionalChar.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalByte queryForByte(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(byte.class, null, sql, parameters);
return result.isPresent() ? OptionalByte.of(result.get()) : OptionalByte.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalShort queryForShort(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(short.class, null, sql, parameters);
return result.isPresent() ? OptionalShort.of(result.get()) : OptionalShort.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalInt queryForInt(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(int.class, null, sql, parameters);
return result.isPresent() ? OptionalInt.of(result.get()) : OptionalInt.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalLong queryForLong(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(long.class, null, sql, parameters);
return result.isPresent() ? OptionalLong.of(result.get()) : OptionalLong.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalFloat queryForFloat(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(float.class, null, sql, parameters);
return result.isPresent() ? OptionalFloat.of(result.get()) : OptionalFloat.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final OptionalDouble queryForDouble(final String sql, final Object... parameters) {
final Nullable result = queryForSingleResult(double.class, null, sql, parameters);
return result.isPresent() ? OptionalDouble.of(result.get()) : OptionalDouble.empty();
}
/**
* @see SQLExecutor#queryForSingleResult(Class, Connection, String, Object...).
*/
@SafeVarargs
public final Nullable queryForString(final String sql, final Object... parameters) {
return queryForSingleResult(String.class, null, sql, parameters);
}
/**
* @see SQLExecutor#queryForSingleResult(Class, String, Object...).
*/
@SafeVarargs
public final Nullable queryForDate(final String sql, final Object... parameters) {
return queryForSingleResult(Date.class, sql, parameters);
}
/**
* @see SQLExecutor#queryForSingleResult(Class, String, Object...).
*/
@SafeVarargs
public final Nullable queryForDate(final Class targetClass, final String sql, final Object... parameters) {
// final Nullable date = this.queryForDate(sql, parameters);
//
// if (date.isNotNull()) {
// if (targetClass.isAssignableFrom(date.get().getClass())) {
// return (Nullable) date;
// } else if (targetClass.equals(Timestamp.class)) {
// return (Nullable) Nullable.of((new Timestamp(date.get().getTime())));
// } else if (targetClass.equals(Time.class)) {
// return (Nullable) Nullable.of((new Time(date.get().getTime())));
// } else if (targetClass.equals(java.sql.Date.class)) {
// return (Nullable) Nullable.of((new java.sql.Date(date.get().getTime())));
// } else {
// return Nullable.of(N.as(targetClass, date.get()));
// }
// } else {
// return (Nullable) date;
// }
return queryForSingleResult(targetClass, sql, parameters);
}
@SafeVarargs
public final Nullable queryForSingleResult(final Class targetClass, final String sql, final Object... parameters) {
return queryForSingleResult(targetClass, sql, null, null, parameters);
}
@SafeVarargs
public final Nullable queryForSingleResult(final Class targetClass, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
return queryForSingleResult(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final Nullable queryForSingleResult(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return queryForSingleResult(targetClass, conn, sql, null, null, parameters);
}
/**
* Just fetch the result in the 1st row and 1st column. {@code null} is returned if no result is found. And this
* method will try to convert the result to the specified {@code targetClass} if {@code targetClass} is not null and it's not
* assignable from the result.
*
* Special note for type conversion for {@code boolean} or {@code Boolean} type: {@code true} is returned if the
* {@code String} value of the target column is {@code "true"}, case insensitive. or it's an integer with value > 0.
* Otherwise, {@code false} is returned.
*
* Remember to add {@code limit} condition if big result will be returned by the query.
*
* @param targetClass
* set result type to avoid the NullPointerException if result is null and T is primitive type
* "int, long. short ... char, boolean..".
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @throws ClassCastException
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public final Nullable queryForSingleResult(final Class targetClass, final Connection conn, final String sql,
final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
final Nullable> result = query(conn, sql, statementSetter, SINGLE_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
return result.isPresent() ? Nullable.of(N.as(targetClass, result.get())) : (Nullable) Nullable.empty();
}
//
// public Map queryForMap(String sql, Object... parameters) {
// return queryForMap(sql, null, parameters);
// }
//
// public Map queryForMap(String sql, StatementSetter statementSetter, Object... parameters) {
// return queryForMap(null, sql, statementSetter, parameters);
// }
//
// public Map queryForMap(final Connection conn, final String sql, Object... parameters) {
// return queryForMap(conn, sql, null, parameters);
// }
//
// /**
// * Just fetch the result in the 1st row. {@code null} is returned if no result is found.
// *
// * Remember to add {@code limit} condition if big result will be returned by the query.
// *
// * @param conn
// * @param sql
// * @param statementSetter
// * @param parameters
// * @return
// */
// public Map queryForMap(final Connection conn, final String sql, StatementSetter statementSetter, Object... parameters) {
// return query(conn, sql, statementSetter, MAP_RESULT_SET_EXTRACTOR, null, parameters);
// }
@SafeVarargs
public final Optional queryForEntity(final Class targetClass, final String sql, final Object... parameters) {
return queryForEntity(targetClass, sql, null, null, parameters);
}
@SafeVarargs
public final Optional queryForEntity(final Class targetClass, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
return queryForEntity(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final Optional queryForEntity(final Class targetClass, final Connection conn, final String sql, final Object... parameters) {
return queryForEntity(targetClass, conn, sql, null, null, parameters);
}
/**
* Just fetch the result in the 1st row. {@code null} is returned if no result is found. This method will try to
* convert the column value to the type of mapping entity property if the mapping entity property is not assignable
* from column value.
*
* Remember to add {@code limit} condition if big result will be returned by the query.
*
* @param targetClass
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public final Optional queryForEntity(final Class targetClass, final Connection conn, final String sql, final StatementSetter statementSetter,
final JdbcSettings jdbcSettings, final Object... parameters) {
final T result = (T) query(targetClass, conn, sql, statementSetter, ENTITY_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
return result == null ? (Optional) Optional.empty() : Optional.of(result);
}
/**
* Query single column.
*
* @param sql
* @param parameters
* @return
*/
@SafeVarargs
public final List queryForList(final String sql, final Object... parameters) {
return queryForList(sql, null, null, parameters);
}
/**
* Query single column.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SafeVarargs
public final List queryForList(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return queryForList(null, sql, statementSetter, jdbcSettings, parameters);
}
/**
* Query single column.
*
* @param conn
* @param sql
* @param parameters
* @return
*/
@SafeVarargs
public final List queryForList(final Connection conn, final String sql, final Object... parameters) {
return queryForList(conn, sql, null, null, parameters);
}
/**
* Query single column.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @throws ClassCastException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SafeVarargs
public final List queryForList(final Connection conn, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
final List result = query(conn, sql, statementSetter, LIST_RESULT_SET_EXTRACTOR, jdbcSettings, parameters);
return (List) result;
}
@SafeVarargs
public final DataSet query(final String sql, final Object... parameters) {
return query(sql, null, parameters);
}
@SafeVarargs
public final DataSet query(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return query(sql, statementSetter, null, parameters);
}
//
// public T query(String sql, ResultSetExtractor resultSetExtractor,
// Object... parameters) {
// return query(null, sql, null, resultSetExtractor, null, parameters);
// }
//
@SafeVarargs
public final T query(final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final Object... parameters) {
return query(sql, statementSetter, resultSetExtractor, null, parameters);
}
/**
* Remember to close the ResultSet
, Statement
and Connection
if the return type T
is ResultSet
or RowIterator
.
*
* If T
is RowIterator
, call rowIterator.close()
to close ResultSet
, Statement
and Connection
.
*
* If T
is ResultSet
, call below codes to close ResultSet
, Statement
and Connection
.
*
*
*
* Connection conn = null;
* Statement stmt = null;
*
* try {
* stmt = rs.getStatement();
* conn = stmt.getConnection();
* } catch (SQLException e) {
* // TODO.
* } finally {
* JdbcUtil.closeQuietly(rs, stmt, conn);
* }
*
*
*
* @param sql
* @param statementSetter
* @param resultSetExtractor
* @param jdbcSettings
* @param parameters
* @return
*/
@SafeVarargs
public final T query(final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final JdbcSettings jdbcSettings, final Object... parameters) {
return query(null, sql, statementSetter, resultSetExtractor, jdbcSettings, parameters);
}
@SafeVarargs
public final DataSet query(final Connection conn, final String sql, final Object... parameters) {
return query(conn, sql, null, parameters);
}
@SafeVarargs
public final DataSet query(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return query(conn, sql, statementSetter, null, parameters);
}
@SafeVarargs
public final T query(final Connection conn, final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final Object... parameters) {
return query(conn, sql, statementSetter, resultSetExtractor, null, parameters);
}
/**
* Remember to close the ResultSet
, Statement
and Connection
if the return type T
is ResultSet
or RowIterator
.
*
* If T
is RowIterator
, call rowIterator.close()
to close ResultSet
, Statement
and Connection
.
*
* If T
is ResultSet
, call below codes to close ResultSet
, Statement
and Connection
.
*
*
*
* Connection conn = null;
* Statement stmt = null;
*
* try {
* stmt = rs.getStatement();
* conn = stmt.getConnection();
* } catch (SQLException e) {
* // TODO.
* } finally {
* JdbcUtil.closeQuietly(rs, stmt, conn);
* }
*
*
*
* @param conn
* @param sql
* @param statementSetter
* @param resultSetExtractor
* @param jdbcSettings
* @param parameters
* @return
*/
@SafeVarargs
public final T query(final Connection conn, final String sql, final StatementSetter statementSetter, final ResultSetExtractor resultSetExtractor,
final JdbcSettings jdbcSettings, final Object... parameters) {
return query(null, conn, sql, statementSetter, resultSetExtractor, jdbcSettings, parameters);
}
protected T query(final Class targetClass, final Connection conn, final String sql, StatementSetter statementSetter,
ResultSetExtractor resultSetExtractor, JdbcSettings jdbcSettings, final Object... parameters) {
final NamedSQL namedSQL = getNamedSQL(sql);
statementSetter = checkStatementSetter(namedSQL, statementSetter);
resultSetExtractor = checkResultSetExtractor(namedSQL, resultSetExtractor);
jdbcSettings = checkJdbcSettings(jdbcSettings, namedSQL);
T result = null;
DataSource ds = null;
Connection localConn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
ds = getDataSource(namedSQL.getPureSQL(), parameters, jdbcSettings);
localConn = (conn == null) ? ds.getConnection() : conn;
stmt = prepareStatement(ds, localConn, namedSQL, statementSetter, jdbcSettings, Statement.NO_GENERATED_KEYS, false, parameters);
rs = stmt.executeQuery();
result = resultSetExtractor.extractData(targetClass, namedSQL, rs, jdbcSettings);
} catch (SQLException e) {
String msg = AbacusException.getErrorMsg(e) + ". [SQL] " + namedSQL.getNamedSQL();
logger.error(msg);
throw new UncheckedSQLException(e, msg);
} finally {
if (result instanceof ResultSet || result instanceof RowIterator) {
// delay.
} else {
closeQuietly(rs, stmt, localConn, conn);
}
}
return result;
}
@SafeVarargs
public final DataSet queryAll(final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(sql, null, jdbcSettings, parameters);
}
@SafeVarargs
public final DataSet queryAll(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(null, sql, statementSetter, jdbcSettings, parameters);
}
DataSet queryAll(final Connection conn, final String sql, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(conn, sql, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql in parallel. Mostly it's designed
* for partition to query the partitioning table in more than one databases.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
DataSet queryAll(final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings, final Object... parameters) {
// TODO the specified connection will be closed if Stream is closed. that means the specified connection can't be held independently.
N.checkArgument(conn == null, "Must not specified connection");
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
if (N.isNullOrEmpty(jdbcSettings.getQueryWithDataSources())) {
return query(conn, sql, statementSetter, jdbcSettings, parameters);
} else {
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List columnNames = new ArrayList<>();
try (final Stream s = streamAlll(columnNames, sql, statementSetter, newJdbcSettings, parameters)) {
return toDataSet(columnNames, skipAndLimit(s, jdbcSettings));
}
}
}
@SafeVarargs
public final DataSet queryAll(final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(sqls, null, jdbcSettings, parameters);
}
@SafeVarargs
public final DataSet queryAll(final List sqls, final StatementSetter statementSetter, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(null, sqls, statementSetter, jdbcSettings, parameters);
}
DataSet queryAll(final Connection conn, final List sqls, final JdbcSettings jdbcSettings, final Object... parameters) {
return queryAll(conn, sqls, null, jdbcSettings, parameters);
}
/**
* Returns the merged ResultSet acquired by querying with the specified sql list in parallel. Mostly it's designed
* for partition to query multiple partitioning tables in one or more databases.
*
* @param conn
* @param sqls
* @param statementSetter
* @param jdbcSettings set multiple data sources by method: setQueryWithDataSources
* @param parameters
* @return
*/
DataSet queryAll(final Connection conn, final List sqls, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if Stream is closed. that means the specified connection can't be held independently.
N.checkArgument(conn == null, "Must not specified connection");
N.checkArgument(N.notNullOrEmpty(sqls), "'sqls' can't be null or empty");
if (jdbcSettings == null) {
jdbcSettings = _jdbcSettings.copy();
}
final JdbcSettings newJdbcSettings = jdbcSettings.copy().setOffset(0).setCount(Long.MAX_VALUE);
final List columnNames = new ArrayList<>();
try (final Stream s = (newJdbcSettings.isQueryInParallel() ? Stream.of(sqls).parallel(sqls.size()) : Stream.of(sqls))
.flatMap(new Function>() {
@Override
public Stream apply(String sql) {
return streamAlll(columnNames, sql, statementSetter, newJdbcSettings, parameters);
}
})) {
return toDataSet(columnNames, skipAndLimit(s, jdbcSettings));
}
}
private RowIterator iterate(final String sql, final StatementSetter statementSetter, final JdbcSettings newJdbcSettings, final Object... parameters) {
return query(sql, statementSetter, ROW_ITERATOR_RESULT_SET_EXTRACTOR, newJdbcSettings, parameters);
}
private Stream streamAlll(final List columnNames, final String sql, final StatementSetter statementSetter,
final JdbcSettings newJdbcSettings, final Object... parameters) {
final Collection dataSources = N.isNullOrEmpty(newJdbcSettings.getQueryWithDataSources()) ? N.asList(newJdbcSettings.getQueryWithDataSource())
: newJdbcSettings.getQueryWithDataSources();
return (newJdbcSettings.isQueryInParallel() ? Stream.of(dataSources).parallel(dataSources.size()) : Stream.of(dataSources))
.flatMap(new Function>() {
@Override
public Stream apply(String t) {
final RowIterator iter = iterate(sql, statementSetter, newJdbcSettings.copy().setQueryWithDataSource(t), parameters);
synchronized (columnNames) {
if (columnNames.size() == 0) {
try {
columnNames.addAll(getColumnLabelList(sql, iter.resultSet()));
} catch (SQLException e) {
IOUtil.closeQuietly(iter);
throw new UncheckedSQLException(e);
}
}
}
return Stream.of(iter).onClose(new Runnable() {
private volatile boolean isClosed = false;
@Override
public void run() {
if (isClosed) {
return;
}
isClosed = true;
IOUtil.closeQuietly(iter);
}
});
}
});
}
private Stream skipAndLimit(Stream s, JdbcSettings jdbcSettings) {
if (jdbcSettings.getOffset() > 0) {
s = s.skip(jdbcSettings.getOffset());
}
if (jdbcSettings.getCount() < Long.MAX_VALUE) {
s = s.limit(jdbcSettings.getCount());
}
return s;
}
private DataSet toDataSet(final List columnNames, final Stream s) {
final List columnNameList = new ArrayList<>();
final List> columnList = new ArrayList<>();
final MutableInt columnCount = MutableInt.of(0);
s.sequential().forEach(new Consumer() {
@Override
public void accept(Object[] a) {
if (columnCount.value() == 0) {
columnCount.setValue(columnNames.size());
columnNameList.addAll(columnNames);
for (int i = 0, len = columnCount.value(); i < len; i++) {
columnList.add(new ArrayList<>());
}
}
for (int i = 0, len = columnCount.value(); i < len; i++) {
columnList.get(i).add(a[i]);
}
}
});
return new RowDataSet(columnNameList, columnList);
}
@SafeVarargs
public final Try> stream(final String sql, final Object... parameters) {
return stream(sql, null, parameters);
}
@SafeVarargs
public final Try> stream(final String sql, final StatementSetter statementSetter, final Object... parameters) {
return stream(sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned Stream
to close the underlying ResultSet
.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SafeVarargs
public final Try> stream(final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return stream((Connection) null, sql, statementSetter, jdbcSettings, parameters);
}
Try> stream(final Connection conn, final String sql, final Object... parameters) {
return stream(conn, sql, null, parameters);
}
Try> stream(final Connection conn, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return stream(conn, sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned Stream
to close the underlying ResultSet
.
*
* @param conn
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
Try> stream(final Connection conn, final String sql, final StatementSetter statementSetter, JdbcSettings jdbcSettings,
final Object... parameters) {
// TODO the specified connection will be closed if Stream is closed. that means the specified connection can't be held independently.
N.checkArgument(conn == null, "Must not specified connection");
return stream2(null, sql, statementSetter, jdbcSettings, parameters);
}
@SafeVarargs
public final Try> stream(final Class targetClass, final String sql, final Object... parameters) {
return stream(targetClass, sql, null, parameters);
}
@SafeVarargs
public final Try> stream(final Class targetClass, final String sql, final StatementSetter statementSetter, final Object... parameters) {
return stream(targetClass, sql, statementSetter, null, parameters);
}
/**
* Remember to close the returned Stream
to close the underlying ResultSet
.
*
* @param sql
* @param statementSetter
* @param jdbcSettings
* @param parameters
* @return
*/
@SafeVarargs
public final Try> stream(final Class targetClass, final String sql, final StatementSetter statementSetter, final JdbcSettings jdbcSettings,
final Object... parameters) {
return stream(targetClass, null, sql, statementSetter, jdbcSettings, parameters);
}