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.core.SQLResult 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.core;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.landawn.abacus.DataSet;
import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.core.command.SQLCommand;
import com.landawn.abacus.core.command.SQLOperationCommand;
import com.landawn.abacus.dataSource.SQLDataSource;
import com.landawn.abacus.exception.UncheckedSQLException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.metadata.EntityDefinition;
import com.landawn.abacus.metadata.Property;
import com.landawn.abacus.type.ObjectType;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.type.TypeFactory;
import com.landawn.abacus.util.JdbcUtil;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.WD;
// TODO: Auto-generated Javadoc
/**
*
* @author Haiyang Li
* @since 0.8
*/
@Internal
public class SQLResult {
private static final Logger logger = LoggerFactory.getLogger(SQLResult.class);
private static final Map, ResultInfo>>> resultInfoPool = new HashMap<>();
protected final Executant executant;
protected final SQLOperationCommand sqlCmd;
protected final Map options;
protected final SQLDataSource ds;
protected final Statement stmt;
protected final ResultSet rs;
protected final ResultInfo resultInfo;
private final long executionTime;
private final int updateCount;
private final List generatedKeys;
private int size = -1;
private boolean isClosed = false;
public SQLResult(Executant executant, SQLOperationCommand sqlCmd, Map options, SQLDataSource ds, Statement stmt, ResultSet rs,
long executionTime) {
this(executant, sqlCmd, options, ds, stmt, rs, executionTime, 0, null);
}
public SQLResult(Executant executant, SQLOperationCommand sqlCmd, long executionTime, int updateCount) {
this(executant, sqlCmd, null, null, null, null, executionTime, updateCount, null);
}
public SQLResult(Executant executant, SQLOperationCommand sqlCmd, long executionTime, int updateCount, List generatedKeys) {
this(executant, sqlCmd, null, null, null, null, executionTime, updateCount, generatedKeys);
}
SQLResult(Executant executant, SQLOperationCommand sqlCmd, Map options, SQLDataSource ds, Statement stmt, ResultSet rs, long executionTime,
int updateCount, List generatedKeys) {
this.executant = executant;
this.sqlCmd = sqlCmd;
this.options = options;
this.ds = ds;
this.stmt = stmt;
this.rs = rs;
this.executionTime = executionTime;
this.updateCount = updateCount;
this.generatedKeys = generatedKeys == null ? N.emptyList() : generatedKeys;
if (rs == null) {
this.resultInfo = null;
} else {
this.resultInfo = getResultInfo(sqlCmd, rs);
}
}
/**
* Gets the executant.
*
* @return
*/
public Executant getExecutant() {
return executant;
}
/**
* Gets the SQL command.
*
* @return
*/
public SQLCommand getSQLCommand() {
return sqlCmd;
}
/**
* Gets the options.
*
* @return
*/
public Map getOptions() {
return options;
}
/**
* Gets the execution time.
*
* @return
*/
public long getExecutionTime() {
return executionTime;
}
/**
* Gets the upate count.
*
* @return
*/
public int getUpateCount() {
return updateCount;
}
/**
* Gets the generated keys.
*
* @return
*/
public List getGeneratedKeys() {
return generatedKeys;
}
/**
* Gets the prop name list.
*
* @return
*/
public List getPropNameList() {
return resultInfo.propNames;
}
/**
* Gets the prop name.
*
* @param propIndex
* @return
*/
public String getPropName(int propIndex) {
return resultInfo.propNames.get(propIndex);
}
/**
* Gets the prop index.
*
* @param propName
* @return
*/
public int getPropIndex(String propName) {
Integer index = resultInfo.propIndexes.get(propName);
if (index == null) {
throw new IllegalArgumentException("The result set " + getPropNameList() + " doesn't contain property[" + propName + "]. ");
}
return index;
}
/**
*
* @param
* @param propIndex
* @return
* @throws SQLException the SQL exception
*/
@SuppressWarnings("unchecked")
public T get(int propIndex) throws SQLException {
return (T) resultInfo.propTypes[propIndex].get(rs, propIndex + 1);
}
/**
*
* @param
* @param propName
* @return
* @throws SQLException the SQL exception
*/
@SuppressWarnings("unchecked")
public T get(String propName) throws SQLException {
return (T) get(getPropIndex(propName));
}
/**
*
* @param row
* @return true, if successful
* @throws SQLException the SQL exception
*/
public boolean absolute(int row) throws SQLException {
boolean result = rs.absolute(row + 1);
if (result) {
} else {
rs.previous();
}
return result;
}
/**
*
* @return true, if successful
* @throws SQLException the SQL exception
*/
public boolean next() throws SQLException {
return rs.next();
}
/**
* Gets the current row num.
*
* @return
* @throws SQLException the SQL exception
*/
public int getCurrentRowNum() throws SQLException {
return rs.getRow();
}
/**
* Gets the result set.
*
* @param selectPropNames
* @param options
* @return
* @throws UncheckedSQLException the unchecked SQL exception
*/
public DataSet getResultSet(Collection selectPropNames, Map options) throws UncheckedSQLException {
assertNotClosed();
try {
return createResultSet(selectPropNames, options);
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
}
public int size() {
assertNotClosed();
synchronized (this) {
if (size < 0) {
size = getExecutant().executeCount(sqlCmd, options);
}
return size;
}
}
/**
* Close.
*/
public void close() {
if (isClosed) {
return;
}
synchronized (this) {
try {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
logger.error("Failed to close ResultSet", e);
}
}
} finally {
if (stmt != null) {
executant.closeStatement(ds, stmt, getOptions());
}
}
}
isClosed = true;
}
/**
* Checks if is closed.
*
* @return true, if is closed
*/
public boolean isClosed() {
return isClosed;
}
/**
* Assert not closed.
*/
private void assertNotClosed() {
if (isClosed) {
throw new IllegalStateException("SQL result has been closed");
}
}
/**
* Creates the result set.
*
* @param selectPropNames
* @param options
* @return
* @throws SQLException the SQL exception
*/
private DataSet createResultSet(Collection selectPropNames, Map options) throws SQLException {
if (selectPropNames == null) {
selectPropNames = resultInfo.propNames;
} else {
if (!resultInfo.propNames.containsAll(selectPropNames)) {
List temp = new ArrayList<>(selectPropNames);
temp.removeAll(resultInfo.propNames);
for (String propName : temp) {
if (!(propName.trim().endsWith(WD.ASTERISK))) {
throw new IllegalArgumentException("The resultSet doesn't include all request property: " + selectPropNames
+ ". The property in the result is: " + resultInfo.propNames);
}
}
}
}
final int propCount = selectPropNames.size();
final List> columnList = new ArrayList<>(propCount);
for (int i = 0; i < propCount; i++) {
columnList.add(new ArrayList<>());
}
int offset = EntityManagerUtil.getOffset(options);
int count = EntityManagerUtil.getCount(options);
if (count > 0) {
int[] selectPropIndexTable = new int[propCount];
int arrayIndex = 0;
for (String propName : selectPropNames) {
selectPropIndexTable[arrayIndex++] = getPropIndex(propName);
}
synchronized (this) {
if (absolute(offset)) {
do {
for (int i = 0; i < propCount; i++) {
columnList.get(i).add(get(selectPropIndexTable[i]));
}
count--;
} while ((count > 0) && rs.next());
}
}
}
return new RowDataSet(new ArrayList<>(selectPropNames), columnList);
}
/**
* Gets the result info.
*
* @param sqlCmd
* @param rs
* @return
* @throws UncheckedSQLException the unchecked SQL exception
*/
private ResultInfo getResultInfo(SQLOperationCommand sqlCmd, ResultSet rs) throws UncheckedSQLException {
final EntityDefinition entityDef = sqlCmd.getEntityDef();
final String domainName = (entityDef.getFactory() == null) ? N.EMPTY_STRING : entityDef.getFactory().domainName();
final String entityName = entityDef.getName();
final Collection selectedPropNames = sqlCmd.getTargetPropNames();
ResultInfo resultInfo = null;
synchronized (resultInfoPool) {
Map, ResultInfo>> entityResultInfoMap = resultInfoPool.get(domainName);
if (entityResultInfoMap == null) {
entityResultInfoMap = new HashMap<>();
resultInfoPool.put(domainName, entityResultInfoMap);
}
Map, ResultInfo> resultInfoMap = entityResultInfoMap.get(entityName);
if (resultInfoMap == null) {
resultInfoMap = new HashMap<>();
entityResultInfoMap.put(entityName, resultInfoMap);
} else {
resultInfo = resultInfoMap.get(selectedPropNames);
}
if (resultInfo == null) {
int columnCount = 0;
List columnLabelList = null;
try {
final ResultSetMetaData rsmd = rs.getMetaData();
columnCount = rsmd.getColumnCount();
columnLabelList = new ArrayList<>(columnCount);
for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
columnLabelList.add(JdbcUtil.getColumnLabel(rsmd, columnIndex));
}
} catch (SQLException e) {
throw new UncheckedSQLException(e);
}
final Collection resultPropNames = selectedPropNames == null || selectedPropNames.size() != columnCount ? columnLabelList
: selectedPropNames;
final List propNames = new ArrayList<>(columnCount);
final Map propIndexes = new HashMap<>(columnCount * 2);
final Type[] propTypes = new Type[columnCount];
final Iterator it = resultPropNames.iterator();
Property prop = null;
String propName = null;
for (int index = 0; index < columnCount; index++) {
propName = it.next();
prop = entityDef.getProperty(propName);
if ((prop == null) && (resultPropNames != selectedPropNames)) {
for (Property e : entityDef.getPropertyList()) {
if (propName.equalsIgnoreCase(e.getColumnName())) {
propName = e.getName();
prop = e;
break;
}
}
}
propNames.add(propName);
propIndexes.put(propName, index);
if (prop == null) {
propTypes[index] = TypeFactory.getType(ObjectType.OBJECT);
} else {
propTypes[index] = prop.getType();
}
}
resultInfo = new ResultInfo(propNames, propIndexes, propTypes);
if (selectedPropNames == null) {
resultInfoPool.get(domainName).get(entityName).put(null, resultInfo);
} else {
resultInfoPool.get(domainName).get(entityName).put(new ArrayList<>(selectedPropNames), resultInfo);
}
}
}
return resultInfo;
}
/**
* The Class ResultInfo.
*/
private static class ResultInfo {
/** The prop names. */
final List propNames;
/** The prop indexes. */
final Map propIndexes;
/** The prop types. */
final Type[] propTypes;
/**
* Instantiates a new result info.
*
* @param propNames
* @param propIndexes
* @param propTypes
*/
ResultInfo(final List propNames, final Map propIndexes, final Type[] propTypes) {
this.propNames = propNames;
this.propIndexes = propIndexes;
this.propTypes = propTypes;
}
}
}