blob: 6a75434125cb5a8d4a832fb45c563faf0015312e [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.ofbiz.entity.jdbc;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.sql.rowset.serial.SerialBlob;
import javax.sql.rowset.serial.SerialClob;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.ObjectType;
import org.ofbiz.base.util.UtilGenerics;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.entity.GenericDataSourceException;
import org.ofbiz.entity.GenericEntity;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericModelException;
import org.ofbiz.entity.GenericNotImplementedException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.condition.EntityConditionParam;
import org.ofbiz.entity.condition.EntityOperator;
import org.ofbiz.entity.condition.OrderByList;
import org.ofbiz.entity.config.model.Datasource;
import org.ofbiz.entity.model.ModelEntity;
import org.ofbiz.entity.model.ModelField;
import org.ofbiz.entity.model.ModelFieldType;
import org.ofbiz.entity.model.ModelFieldTypeReader;
import org.ofbiz.entity.model.ModelKeyMap;
import org.ofbiz.entity.model.ModelViewEntity;
/**
* GenericDAO Utility methods for general tasks
*
*/
public class SqlJdbcUtil {
public static final String module = SqlJdbcUtil.class.getName();
public static final int CHAR_BUFFER_SIZE = 4096;
/** Makes the FROM clause and when necessary the JOIN clause(s) as well */
public static String makeFromClause(ModelEntity modelEntity, ModelFieldTypeReader modelFieldTypeReader, Datasource datasourceInfo) throws GenericEntityException {
StringBuilder sql = new StringBuilder(" FROM ");
if (modelEntity instanceof ModelViewEntity) {
ModelViewEntity modelViewEntity = (ModelViewEntity) modelEntity;
if ("ansi".equals(datasourceInfo.getJoinStyle()) || "ansi-no-parenthesis".equals(datasourceInfo.getJoinStyle())) {
boolean useParenthesis = true;
if ("ansi-no-parenthesis".equals(datasourceInfo.getJoinStyle())) {
useParenthesis = false;
}
// FROM clause: in this case will be a bunch of joins that correspond with the view-links
// BIG NOTE on the JOIN clauses: the order of joins is determined by the order of the
// view-links; for more flexible order we'll have to figure something else out and
// extend the DTD for the nested view-link elements or something
// At this point it is assumed that in each view-link the left hand alias will
// either be the first alias in the series or will already be in a previous
// view-link and already be in the big join; SO keep a set of all aliases
// in the join so far and if the left entity alias isn't there yet, and this
// isn't the first one, throw an exception
Set<String> joinedAliasSet = new TreeSet<String>();
// TODO: at view-link read time make sure they are ordered properly so that each
// left hand alias after the first view-link has already been linked before
StringBuilder openParens = null;
if (useParenthesis) openParens = new StringBuilder();
StringBuilder restOfStatement = new StringBuilder();
for (int i = 0; i < modelViewEntity.getViewLinksSize(); i++) {
// don't put starting parenthesis
if (i > 0 && useParenthesis) openParens.append('(');
ModelViewEntity.ModelViewLink viewLink = modelViewEntity.getViewLink(i);
ModelEntity linkEntity = modelViewEntity.getMemberModelEntity(viewLink.getEntityAlias());
ModelEntity relLinkEntity = modelViewEntity.getMemberModelEntity(viewLink.getRelEntityAlias());
// ModelViewEntity.ModelMemberEntity linkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getEntityAlias());
// ModelViewEntity.ModelMemberEntity relLinkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getRelEntityAlias());
if (i == 0) {
// this is the first referenced member alias, so keep track of it for future use...
restOfStatement.append(makeViewTable(linkEntity, modelFieldTypeReader, datasourceInfo));
//another possible one that some dbs might need, but not sure of any yet: restOfStatement.append(" AS ");
restOfStatement.append(" ");
restOfStatement.append(viewLink.getEntityAlias());
joinedAliasSet.add(viewLink.getEntityAlias());
} else {
// make sure the left entity alias is already in the join...
if (!joinedAliasSet.contains(viewLink.getEntityAlias())) {
throw new GenericModelException("Tried to link the " + viewLink.getEntityAlias() + " alias to the " + viewLink.getRelEntityAlias() + " alias of the " + modelViewEntity.getEntityName() + " view-entity, but it is not the first view-link and has not been included in a previous view-link. In other words, the left/main alias isn't connected to the rest of the member-entities yet.");
}
}
// now put the rel (right) entity alias into the set that is in the join
joinedAliasSet.add(viewLink.getRelEntityAlias());
if (viewLink.isRelOptional()) {
restOfStatement.append(" LEFT OUTER JOIN ");
} else {
restOfStatement.append(" INNER JOIN ");
}
restOfStatement.append(makeViewTable(relLinkEntity, modelFieldTypeReader, datasourceInfo));
//another possible one that some dbs might need, but not sure of any yet: restOfStatement.append(" AS ");
restOfStatement.append(" ");
restOfStatement.append(viewLink.getRelEntityAlias());
restOfStatement.append(" ON ");
StringBuilder condBuffer = new StringBuilder();
for (int j = 0; j < viewLink.getKeyMapsSize(); j++) {
ModelKeyMap keyMap = viewLink.getKeyMap(j);
ModelField linkField = linkEntity.getField(keyMap.getFieldName());
if (linkField == null) {
throw new GenericModelException("Invalid field name in view-link key-map for the " + viewLink.getEntityAlias() + " and the " + viewLink.getRelEntityAlias() + " member-entities of the " + modelViewEntity.getEntityName() + " view-entity; the field [" + keyMap.getFieldName() + "] does not exist on the [" + linkEntity.getEntityName() + "] entity.");
}
ModelField relLinkField = relLinkEntity.getField(keyMap.getRelFieldName());
if (relLinkField == null) {
throw new GenericModelException("Invalid related field name in view-link key-map for the " + viewLink.getEntityAlias() + " and the " + viewLink.getRelEntityAlias() + " member-entities of the " + modelViewEntity.getEntityName() + " view-entity; the field [" + keyMap.getRelFieldName() + "] does not exist on the [" + relLinkEntity.getEntityName() + "] entity.");
}
if (condBuffer.length() > 0) {
condBuffer.append(" AND ");
}
condBuffer.append(viewLink.getEntityAlias());
condBuffer.append(".");
condBuffer.append(linkField.getColName());
condBuffer.append(" = ");
condBuffer.append(viewLink.getRelEntityAlias());
condBuffer.append(".");
condBuffer.append(relLinkField.getColName());
}
if (condBuffer.length() == 0) {
throw new GenericModelException("No view-link/join key-maps found for the " + viewLink.getEntityAlias() + " and the " + viewLink.getRelEntityAlias() + " member-entities of the " + modelViewEntity.getEntityName() + " view-entity.");
}
ModelViewEntity.ViewEntityCondition viewEntityCondition = viewLink.getViewEntityCondition();
if (viewEntityCondition != null) {
EntityCondition whereCondition = viewEntityCondition.getWhereCondition(modelFieldTypeReader, null);
if (whereCondition != null) {
condBuffer.append(" AND ");
condBuffer.append(whereCondition.makeWhereString(modelEntity, null, datasourceInfo));
}
}
restOfStatement.append(condBuffer.toString());
// don't put ending parenthesis
if (i < (modelViewEntity.getViewLinksSize() - 1) && useParenthesis) restOfStatement.append(')');
}
if (useParenthesis) sql.append(openParens.toString());
sql.append(restOfStatement.toString());
// handle tables not included in view-link
boolean fromEmpty = restOfStatement.length() == 0;
for (String aliasName: modelViewEntity.getMemberModelMemberEntities().keySet()) {
ModelEntity fromEntity = modelViewEntity.getMemberModelEntity(aliasName);
if (!joinedAliasSet.contains(aliasName)) {
if (!fromEmpty) sql.append(", ");
fromEmpty = false;
sql.append(makeViewTable(fromEntity, modelFieldTypeReader, datasourceInfo));
sql.append(" ");
sql.append(aliasName);
}
}
} else if ("theta-oracle".equals(datasourceInfo.getJoinStyle()) || "theta-mssql".equals(datasourceInfo.getJoinStyle())) {
// FROM clause
Iterator<String> meIter = modelViewEntity.getMemberModelMemberEntities().keySet().iterator();
while (meIter.hasNext()) {
String aliasName = meIter.next();
ModelEntity fromEntity = modelViewEntity.getMemberModelEntity(aliasName);
sql.append(makeViewTable(fromEntity, modelFieldTypeReader, datasourceInfo));
sql.append(" ");
sql.append(aliasName);
if (meIter.hasNext()) sql.append(", ");
}
// JOIN clause(s): none needed, all the work done in the where clause for theta-oracle
} else {
throw new GenericModelException("The join-style " + datasourceInfo.getJoinStyle() + " is not yet supported");
}
} else {
sql.append(modelEntity.getTableName(datasourceInfo));
}
return sql.toString();
}
/** Makes a WHERE clause String with "<col name>=?" if not null or "<col name> IS null" if null, all AND separated */
@Deprecated
public static String makeWhereStringFromFields(List<ModelField> modelFields, Map<String, Object> fields, String operator) {
return makeWhereStringFromFields(new StringBuilder(), modelFields, fields, operator, null).toString();
}
public static StringBuilder makeWhereStringFromFields(StringBuilder sb, List<ModelField> modelFields, Map<String, Object> fields, String operator) {
return makeWhereStringFromFields(sb, modelFields, fields, operator, null);
}
/** Makes a WHERE clause String with "<col name>=?" if not null or "<col name> IS null" if null, all AND separated */
@Deprecated
public static String makeWhereStringFromFields(List<ModelField> modelFields, Map<String, Object> fields, String operator, List<EntityConditionParam> entityConditionParams) {
return makeWhereStringFromFields(new StringBuilder(), modelFields, fields, operator, entityConditionParams).toString();
}
/** Makes a WHERE clause String with "<col name>=?" if not null or "<col name> IS null" if null, all AND separated */
public static StringBuilder makeWhereStringFromFields(StringBuilder sb, List<ModelField> modelFields, Map<String, Object> fields, String operator, List<EntityConditionParam> entityConditionParams) {
if (modelFields.size() < 1) {
return sb;
}
Iterator<ModelField> iter = modelFields.iterator();
while (iter.hasNext()) {
Object item = iter.next();
Object name = null;
ModelField modelField = null;
if (item instanceof ModelField) {
modelField = (ModelField) item;
sb.append(modelField.getColValue());
name = modelField.getName();
} else {
sb.append(item);
name = item;
}
Object fieldValue = fields.get(name);
if (fieldValue != null && fieldValue != GenericEntity.NULL_FIELD) {
sb.append('=');
addValue(sb, modelField, fieldValue, entityConditionParams);
} else {
sb.append(" IS NULL");
}
if (iter.hasNext()) {
sb.append(' ');
sb.append(operator);
sb.append(' ');
}
}
return sb;
}
public static String makeWhereClause(ModelEntity modelEntity, List<ModelField> modelFields, Map<String, Object> fields, String operator, String joinStyle) throws GenericEntityException {
StringBuilder whereString = new StringBuilder("");
if (UtilValidate.isNotEmpty(modelFields)) {
whereString.append(makeWhereStringFromFields(modelFields, fields, "AND"));
}
String viewClause = makeViewWhereClause(modelEntity, joinStyle);
if (viewClause.length() > 0) {
if (whereString.length() > 0) {
whereString.append(' ');
whereString.append(operator);
whereString.append(' ');
}
whereString.append(viewClause);
}
if (whereString.length() > 0) {
return " WHERE " + whereString.toString();
}
return "";
}
public static String makeViewWhereClause(ModelEntity modelEntity, String joinStyle) throws GenericEntityException {
if (modelEntity instanceof ModelViewEntity) {
StringBuilder whereString = new StringBuilder();
ModelViewEntity modelViewEntity = (ModelViewEntity) modelEntity;
if ("ansi".equals(joinStyle) || "ansi-no-parenthesis".equals(joinStyle)) {
// nothing to do here, all done in the JOIN clauses
} else if ("theta-oracle".equals(joinStyle) || "theta-mssql".equals(joinStyle)) {
boolean isOracleStyle = "theta-oracle".equals(joinStyle);
boolean isMssqlStyle = "theta-mssql".equals(joinStyle);
for (int i = 0; i < modelViewEntity.getViewLinksSize(); i++) {
ModelViewEntity.ModelViewLink viewLink = modelViewEntity.getViewLink(i);
ModelEntity linkEntity = modelViewEntity.getMemberModelEntity(viewLink.getEntityAlias());
ModelEntity relLinkEntity = modelViewEntity.getMemberModelEntity(viewLink.getRelEntityAlias());
if (linkEntity == null) {
throw new GenericEntityException("Link entity not found with alias: " + viewLink.getEntityAlias() + " for entity: " + modelViewEntity.getEntityName());
}
if (relLinkEntity == null) {
throw new GenericEntityException("Rel-Link entity not found with alias: " + viewLink.getRelEntityAlias() + " for entity: " + modelViewEntity.getEntityName());
}
// ModelViewEntity.ModelMemberEntity linkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getEntityAlias());
// ModelViewEntity.ModelMemberEntity relLinkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getRelEntityAlias());
for (int j = 0; j < viewLink.getKeyMapsSize(); j++) {
ModelKeyMap keyMap = viewLink.getKeyMap(j);
ModelField linkField = linkEntity.getField(keyMap.getFieldName());
ModelField relLinkField = relLinkEntity.getField(keyMap.getRelFieldName());
if (whereString.length() > 0) {
whereString.append(" AND ");
}
whereString.append(viewLink.getEntityAlias());
whereString.append(".");
whereString.append(linkField.getColName());
// check to see whether the left or right members are optional, if so:
// oracle: use the (+) on the optional side
// mssql: use the * on the required side
// NOTE: not testing if original table is optional, ONLY if related table is optional; otherwise things get really ugly...
// if (isOracleStyle && linkMemberEntity.getOptional()) whereString.append(" (+) ");
if (isMssqlStyle && viewLink.isRelOptional()) whereString.append("*");
whereString.append("=");
// if (isMssqlStyle && linkMemberEntity.getOptional()) whereString.append("*");
if (isOracleStyle && viewLink.isRelOptional()) whereString.append(" (+) ");
whereString.append(viewLink.getRelEntityAlias());
whereString.append(".");
whereString.append(relLinkField.getColName());
}
}
} else {
throw new GenericModelException("The join-style " + joinStyle + " is not supported");
}
if (whereString.length() > 0) {
return "(" + whereString.toString() + ")";
}
}
return "";
}
public static String makeOrderByClause(ModelEntity modelEntity, List<String> orderBy, Datasource datasourceInfo) throws GenericModelException {
return makeOrderByClause(modelEntity, orderBy, false, datasourceInfo);
}
public static String makeOrderByClause(ModelEntity modelEntity, List<String> orderBy, boolean includeTablenamePrefix, Datasource datasourceInfo) throws GenericModelException {
StringBuilder sql = new StringBuilder("");
//String fieldPrefix = includeTablenamePrefix ? (modelEntity.getTableName(datasourceInfo) + ".") : "";
if (UtilValidate.isNotEmpty(orderBy)) {
if (Debug.verboseOn()) Debug.logVerbose("Order by list contains: " + orderBy.size() + " entries.", module);
OrderByList orderByList = new OrderByList(orderBy);
orderByList.checkOrderBy(modelEntity);
orderByList.makeOrderByString(sql, modelEntity, includeTablenamePrefix, datasourceInfo);
}
if (Debug.verboseOn()) Debug.logVerbose("makeOrderByClause: " + sql.toString(), module);
return sql.toString();
}
public static String makeViewTable(ModelEntity modelEntity, ModelFieldTypeReader modelFieldTypeReader, Datasource datasourceInfo) throws GenericEntityException {
if (modelEntity instanceof ModelViewEntity) {
StringBuilder sql = new StringBuilder("(SELECT ");
Iterator<ModelField> fieldsIter = modelEntity.getFieldsIterator();
if (fieldsIter.hasNext()) {
ModelField curField = fieldsIter.next();
sql.append(curField.getColValue());
sql.append(" AS ");
sql.append(curField.getColName());
while (fieldsIter.hasNext()) {
curField = fieldsIter.next();
sql.append(", ");
sql.append(curField.getColValue());
sql.append(" AS ");
sql.append(curField.getColName());
}
}
sql.append(makeFromClause(modelEntity, modelFieldTypeReader, datasourceInfo));
String viewWhereClause = makeViewWhereClause(modelEntity, datasourceInfo.getJoinStyle());
ModelViewEntity modelViewEntity = (ModelViewEntity)modelEntity;
List<EntityCondition> whereConditions = new LinkedList<EntityCondition>();
List<EntityCondition> havingConditions = new LinkedList<EntityCondition>();
List<String> orderByList = new LinkedList<String>();
modelViewEntity.populateViewEntityConditionInformation(modelFieldTypeReader, whereConditions, havingConditions, orderByList, null);
String viewConditionClause;
if (!whereConditions.isEmpty()) {
viewConditionClause = EntityCondition.makeCondition(whereConditions, EntityOperator.AND).makeWhereString(modelViewEntity, null, datasourceInfo);
} else {
viewConditionClause = null;
}
if (UtilValidate.isNotEmpty(viewWhereClause) || UtilValidate.isNotEmpty(viewConditionClause)) {
sql.append(" WHERE ");
if (UtilValidate.isNotEmpty(viewWhereClause)) {
sql.append("(").append(viewWhereClause).append(")");
if (UtilValidate.isNotEmpty(viewConditionClause)) {
sql.append(" AND ");
}
}
if (UtilValidate.isNotEmpty(viewConditionClause)) {
sql.append("(").append(viewConditionClause).append(")");
}
}
// FIXME: handling HAVING, don't need ORDER BY for nested views
modelViewEntity.colNameString(modelViewEntity.getGroupBysCopy(), sql, " GROUP BY ", ", ", "", false);
sql.append(")");
return sql.toString();
} else {
return modelEntity.getTableName(datasourceInfo);
}
}
public static String filterColName(String colName) {
return colName.replace('.', '_').replace('(','_').replace(')','_');
}
/* ====================================================================== */
/* ====================================================================== */
/**
* The elements (ModelFields) of the list are bound to an SQL statement
* (SQL-Processor)
*
* @param sqlP
* @param list
* @param entity
* @throws GenericEntityException
*/
public static void setValues(SQLProcessor sqlP, List<ModelField> list, GenericEntity entity, ModelFieldTypeReader modelFieldTypeReader) throws GenericEntityException {
for (ModelField curField: list) {
setValue(sqlP, curField, entity, modelFieldTypeReader);
}
}
/**
* The elements (ModelFields) of the list are bound to an SQL statement
* (SQL-Processor), but values must not be null.
*
* @param sqlP
* @param list
* @param dummyValue
* @param modelFieldTypeReader
* @throws GenericEntityException
*/
public static void setValuesWhereClause(SQLProcessor sqlP, List<ModelField> list, GenericValue dummyValue, ModelFieldTypeReader modelFieldTypeReader) throws GenericEntityException {
for (ModelField curField: list) {
// for where clause variables only setValue if not null...
if (dummyValue.get(curField.getName()) != null) {
setValue(sqlP, curField, dummyValue, modelFieldTypeReader);
}
}
}
/**
* Get all primary keys from the model entity and bind their values
* to the an SQL statement (SQL-Processor)
*
* @param sqlP
* @param modelEntity
* @param entity
* @param modelFieldTypeReader
* @throws GenericEntityException
*/
public static void setPkValues(SQLProcessor sqlP, ModelEntity modelEntity, GenericEntity entity, ModelFieldTypeReader modelFieldTypeReader) throws GenericEntityException {
Iterator<ModelField> pksIter = modelEntity.getPksIterator();
while (pksIter.hasNext()) {
ModelField curField = pksIter.next();
// for where clause variables only setValue if not null...
if (entity.dangerousGetNoCheckButFast(curField) != null) {
setValue(sqlP, curField, entity, modelFieldTypeReader);
}
}
}
public static void getValue(ResultSet rs, int ind, ModelField curField, GenericEntity entity, ModelFieldTypeReader modelFieldTypeReader) throws GenericEntityException {
ModelFieldType mft = modelFieldTypeReader.getModelFieldType(curField.getType());
if (mft == null) {
throw new GenericModelException("definition fieldType " + curField.getType() + " not found, cannot getValue for field " +
entity.getEntityName() + "." + curField.getName() + ".");
}
// ----- Try out the new handler code -----
JdbcValueHandler<?> handler = mft.getJdbcValueHandler();
if (handler != null) {
try {
entity.dangerousSetNoCheckButFast(curField, handler.getValue(rs, ind));
return;
} catch (Exception e) {
Debug.logError(e, module);
}
} else {
Debug.logWarning("JdbcValueHandler not found for java-type " + mft.getJavaType() +
", falling back on switch statement. Entity = " +
curField.getModelEntity().getEntityName() +
", field = " + curField.getName() + ".", module);
}
// ------------------------------------------
String fieldType = mft.getJavaType();
try {
// checking to see if the object is null is really only necessary for the numbers
int typeValue = getType(fieldType);
ResultSetMetaData rsmd = rs.getMetaData();
int colType = rsmd.getColumnType(ind);
if (typeValue <= 4 || typeValue >= 11) {
switch (typeValue) {
case 1:
if (java.sql.Types.CLOB == colType) {
// Debug.logInfo("For field " + curField.getName() + " of entity " + entity.getEntityName() + " getString is a CLOB, trying getCharacterStream", module);
// if the String is empty, try to get a text input stream, this is required for some databases for larger fields, like CLOBs
Clob valueClob = rs.getClob(ind);
Reader valueReader = null;
if (valueClob != null) {
valueReader = valueClob.getCharacterStream();
}
//Reader valueReader = rs.getCharacterStream(ind);
if (valueReader != null) {
char[] inCharBuffer = new char[CHAR_BUFFER_SIZE];
StringBuilder strBuf = new StringBuilder();
int charsRead = 0;
try {
while ((charsRead = valueReader.read(inCharBuffer, 0, CHAR_BUFFER_SIZE)) > 0) {
strBuf.append(inCharBuffer, 0, charsRead);
}
valueReader.close();
} catch (IOException e) {
throw new GenericEntityException("Error reading long character stream for field " + curField.getName() + " of entity " + entity.getEntityName(), e);
}
entity.dangerousSetNoCheckButFast(curField, strBuf.toString());
} else {
entity.dangerousSetNoCheckButFast(curField, null);
}
} else {
String value = rs.getString(ind);
entity.dangerousSetNoCheckButFast(curField, value);
}
break;
case 2:
entity.dangerousSetNoCheckButFast(curField, rs.getTimestamp(ind));
break;
case 3:
entity.dangerousSetNoCheckButFast(curField, rs.getTime(ind));
break;
case 4:
entity.dangerousSetNoCheckButFast(curField, rs.getDate(ind));
break;
case 11:
Object obj = null;
byte[] originalBytes = rs.getBytes(ind);
obj = deserializeField(originalBytes, ind, curField);
if (obj != null) {
entity.dangerousSetNoCheckButFast(curField, obj);
} else {
entity.dangerousSetNoCheckButFast(curField, originalBytes);
}
break;
case 12:
Object originalObject;
byte[] fieldBytes;
try {
Blob theBlob = rs.getBlob(ind);
fieldBytes = theBlob != null ? theBlob.getBytes(1, (int) theBlob.length()) : null;
originalObject = theBlob;
} catch (SQLException e) {
// for backward compatibility if getBlob didn't work try getBytes
fieldBytes = rs.getBytes(ind);
originalObject = fieldBytes;
}
if (originalObject != null) {
// for backward compatibility, check to see if there is a serialized object and if so return that
Object blobObject = deserializeField(fieldBytes, ind, curField);
if (blobObject != null) {
entity.dangerousSetNoCheckButFast(curField, blobObject);
} else {
if (originalObject instanceof Blob) {
// NOTE using SerialBlob here instead of the Blob from the database to make sure we can pass it around, serialize it, etc
entity.dangerousSetNoCheckButFast(curField, new SerialBlob((Blob) originalObject));
} else {
entity.dangerousSetNoCheckButFast(curField, originalObject);
}
}
}
break;
case 13:
entity.dangerousSetNoCheckButFast(curField, new SerialClob(rs.getClob(ind)));
break;
case 14:
case 15:
entity.dangerousSetNoCheckButFast(curField, rs.getObject(ind));
break;
}
} else {
switch (typeValue) {
case 5:
int intValue = rs.getInt(ind);
if (rs.wasNull()) {
entity.dangerousSetNoCheckButFast(curField, null);
} else {
entity.dangerousSetNoCheckButFast(curField, Integer.valueOf(intValue));
}
break;
case 6:
long longValue = rs.getLong(ind);
if (rs.wasNull()) {
entity.dangerousSetNoCheckButFast(curField, null);
} else {
entity.dangerousSetNoCheckButFast(curField, Long.valueOf(longValue));
}
break;
case 7:
float floatValue = rs.getFloat(ind);
if (rs.wasNull()) {
entity.dangerousSetNoCheckButFast(curField, null);
} else {
entity.dangerousSetNoCheckButFast(curField, Float.valueOf(floatValue));
}
break;
case 8:
double doubleValue = rs.getDouble(ind);
if (rs.wasNull()) {
entity.dangerousSetNoCheckButFast(curField, null);
} else {
entity.dangerousSetNoCheckButFast(curField, Double.valueOf(doubleValue));
}
break;
case 9:
BigDecimal bigDecimalValue = rs.getBigDecimal(ind);
if (rs.wasNull()) {
entity.dangerousSetNoCheckButFast(curField, null);
} else {
entity.dangerousSetNoCheckButFast(curField, bigDecimalValue);
}
break;
case 10:
boolean booleanValue = rs.getBoolean(ind);
if (rs.wasNull()) {
entity.dangerousSetNoCheckButFast(curField, null);
} else {
entity.dangerousSetNoCheckButFast(curField, Boolean.valueOf(booleanValue));
}
break;
}
}
} catch (SQLException sqle) {
throw new GenericDataSourceException("SQL Exception while getting value : " + curField.getName() + " [" + curField.getColName() + "] (" + ind + ")", sqle);
}
}
private static Object deserializeField(byte[] fieldBytes, int ind, ModelField curField) throws GenericDataSourceException {
// NOTE DEJ20071022: the following code is to convert the byte[] back into an object; if that fails
//just return the byte[]; this was for the ByteWrapper thing which is now deprecated, so this may
//be removed in the near future to enhance performance
InputStream binaryInput = null;
if (fieldBytes != null && fieldBytes.length > 0) {
binaryInput = new ByteArrayInputStream(fieldBytes);
}
if (fieldBytes != null && fieldBytes.length <= 0) {
Debug.logWarning("Got bytes back for Object field with length: " + fieldBytes.length + " while getting value : " + curField.getName() + " [" + curField.getColName() + "] (" + ind + "): ", module);
}
//alt 1: binaryInput = rs.getBinaryStream(ind);
//alt 2: Blob blobLocator = rs.getBlob(ind);
//if (blobLocator != null) {
// binaryInput = blobLocator.getBinaryStream();
//}
if (binaryInput != null) {
ObjectInputStream in = null;
try {
in = new ObjectInputStream(binaryInput);
return in.readObject();
} catch (IOException ex) {
if (Debug.verboseOn()) Debug.logVerbose("Unable to read BLOB data from input stream while getting value : " + curField.getName() + " [" + curField.getColName() + "] (" + ind + "): " + ex.toString(), module);
return null;
} catch (ClassNotFoundException ex) {
if (Debug.verboseOn()) Debug.logVerbose("Class not found: Unable to cast BLOB data to an Java object while getting value: " + curField.getName() + " [" + curField.getColName() + "] (" + ind + "); most likely because it is a straight byte[], so just using the raw bytes" + ex.toString(), module);
return null;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
throw new GenericDataSourceException("Unable to close binary input stream while getting value : " + curField.getName() + " [" + curField.getColName() + "] (" + ind + "): " + e.toString(), e);
}
}
}
}
return null;
}
public static void setValue(SQLProcessor sqlP, ModelField modelField, GenericEntity entity, ModelFieldTypeReader modelFieldTypeReader) throws GenericEntityException {
Object fieldValue = entity.dangerousGetNoCheckButFast(modelField);
setValue(sqlP, modelField, entity.getEntityName(), fieldValue, modelFieldTypeReader);
}
public static <T> void setValue(SQLProcessor sqlP, ModelField modelField, String entityName, Object fieldValue, ModelFieldTypeReader modelFieldTypeReader) throws GenericEntityException {
ModelFieldType mft = modelFieldTypeReader.getModelFieldType(modelField.getType());
if (mft == null) {
throw new GenericModelException("GenericDAO.getValue: definition fieldType " + modelField.getType() + " not found, cannot setValue for field " +
entityName + "." + modelField.getName() + ".");
}
// if the value is the GenericEntity.NullField, treat as null
if (fieldValue == GenericEntity.NULL_FIELD) {
fieldValue = null;
}
// ----- Try out the new handler code -----
JdbcValueHandler<T> handler = UtilGenerics.cast(mft.getJdbcValueHandler());
if (handler != null) {
try {
sqlP.setValue(handler, handler.getJavaClass().cast(fieldValue));
return;
} catch (SQLException e) {
throw new GenericDataSourceException("SQL Exception while setting value on field [" + modelField.getName() + "] of entity " + entityName + ": ", e);
}
} else {
Debug.logWarning("JdbcValueHandler not found for java-type " + mft.getJavaType() +
", falling back on switch statement. Entity = " +
modelField.getModelEntity().getEntityName() +
", field = " + modelField.getName() + ".", module);
}
// ------------------------------------------
String fieldType = mft.getJavaType();
if (fieldValue != null) {
if (!ObjectType.instanceOf(fieldValue, fieldType)) {
// this is only an info level message because under normal operation for most JDBC
// drivers this will be okay, but if not then the JDBC driver will throw an exception
// and when lower debug levels are on this should help give more info on what happened
String fieldClassName = fieldValue.getClass().getName();
if (fieldValue instanceof byte[]) {
fieldClassName = "byte[]";
}
if (Debug.verboseOn()) Debug.logVerbose("type of field " + entityName + "." + modelField.getName() +
" is " + fieldClassName + ", was expecting " + mft.getJavaType() + "; this may " +
"indicate an error in the configuration or in the class, and may result " +
"in an SQL-Java data conversion error. Will use the real field type: " +
fieldClassName + ", not the definition.", module);
fieldType = fieldClassName;
}
}
try {
int typeValue = getType(fieldType);
switch (typeValue) {
case 1:
sqlP.setValue((String) fieldValue);
break;
case 2:
sqlP.setValue((java.sql.Timestamp) fieldValue);
break;
case 3:
sqlP.setValue((java.sql.Time) fieldValue);
break;
case 4:
sqlP.setValue((java.sql.Date) fieldValue);
break;
case 5:
sqlP.setValue((java.lang.Integer) fieldValue);
break;
case 6:
sqlP.setValue((java.lang.Long) fieldValue);
break;
case 7:
sqlP.setValue((java.lang.Float) fieldValue);
break;
case 8:
sqlP.setValue((java.lang.Double) fieldValue);
break;
case 9:
sqlP.setValue((java.math.BigDecimal) fieldValue);
break;
case 10:
sqlP.setValue((java.lang.Boolean) fieldValue);
break;
case 11:
sqlP.setBinaryStream(fieldValue);
break;
case 12:
if (fieldValue instanceof byte[]) {
sqlP.setBytes((byte[]) fieldValue);
} else if (fieldValue instanceof ByteBuffer) {
sqlP.setBytes(((ByteBuffer) fieldValue).array());
} else {
sqlP.setValue((java.sql.Blob) fieldValue);
}
break;
case 13:
sqlP.setValue((java.sql.Clob) fieldValue);
break;
case 14:
if (fieldValue != null) {
sqlP.setValue(new java.sql.Date(((java.util.Date) fieldValue).getTime()));
} else {
sqlP.setValue((java.sql.Date) null);
}
break;
case 15:
sqlP.setValue(UtilGenerics.<Collection<?>>cast(fieldValue));
break;
}
} catch (GenericNotImplementedException e) {
throw new GenericNotImplementedException("Not Implemented Exception while setting value on field [" + modelField.getName() + "] of entity " + entityName + ": " + e.toString(), e);
} catch (SQLException sqle) {
throw new GenericDataSourceException("SQL Exception while setting value on field [" + modelField.getName() + "] of entity " + entityName + ": ", sqle);
}
}
protected static Map<String, Integer> fieldTypeMap = new HashMap<String, Integer>();
static {
fieldTypeMap.put("java.lang.String", 1);
fieldTypeMap.put("String", 1);
fieldTypeMap.put("java.sql.Timestamp", 2);
fieldTypeMap.put("Timestamp", 2);
fieldTypeMap.put("java.sql.Time", 3);
fieldTypeMap.put("Time", 3);
fieldTypeMap.put("java.sql.Date", 4);
fieldTypeMap.put("Date", 4);
fieldTypeMap.put("java.lang.Integer", 5);
fieldTypeMap.put("Integer", 5);
fieldTypeMap.put("java.lang.Long", 6);
fieldTypeMap.put("Long", 6);
fieldTypeMap.put("java.lang.Float", 7);
fieldTypeMap.put("Float", 7);
fieldTypeMap.put("java.lang.Double", 8);
fieldTypeMap.put("Double", 8);
fieldTypeMap.put("java.math.BigDecimal", 9);
fieldTypeMap.put("BigDecimal", 9);
fieldTypeMap.put("java.lang.Boolean", 10);
fieldTypeMap.put("Boolean", 10);
fieldTypeMap.put("java.lang.Object", 11);
fieldTypeMap.put("Object", 11);
fieldTypeMap.put("java.sql.Blob", 12);
fieldTypeMap.put("Blob", 12);
fieldTypeMap.put("byte[]", 12);
fieldTypeMap.put("java.nio.ByteBuffer", 12);
fieldTypeMap.put("java.nio.HeapByteBuffer", 12);
fieldTypeMap.put("java.sql.Clob", 13);
fieldTypeMap.put("Clob", 13);
fieldTypeMap.put("java.util.Date", 14);
// all of these treated as Collection
fieldTypeMap.put("java.util.ArrayList", 15);
fieldTypeMap.put("java.util.HashSet", 15);
fieldTypeMap.put("java.util.LinkedHashSet", 15);
fieldTypeMap.put("java.util.LinkedList", 15);
}
public static int getType(String fieldType) throws GenericNotImplementedException {
Integer val = fieldTypeMap.get(fieldType);
if (val == null) {
throw new GenericNotImplementedException("Java type " + fieldType + " not currently supported. Sorry.");
}
return val.intValue();
}
public static void addValueSingle(StringBuffer buffer, ModelField field, Object value, List<EntityConditionParam> params) {
StringBuilder sb = new StringBuilder();
addValueSingle(sb, field, value, params);
buffer.append(sb);
}
public static void addValueSingle(StringBuilder buffer, ModelField field, Object value, List<EntityConditionParam> params) {
if (field != null) {
buffer.append('?');
} else {
buffer.append('\'');
if (value instanceof String) {
buffer.append(((String) value).replaceAll("'", "''"));
} else {
buffer.append(value);
}
buffer.append('\'');
}
if (field != null && params != null) params.add(new EntityConditionParam(field, value));
}
public static void addValue(StringBuffer buffer, ModelField field, Object value, List<EntityConditionParam> params) {
StringBuilder sb = new StringBuilder();
addValue(sb, field, value, params);
buffer.append(sb);
}
public static void addValue(StringBuilder buffer, ModelField field, Object value, List<EntityConditionParam> params) {
if (value instanceof Collection<?>) {
buffer.append("(");
Iterator<Object> it = UtilGenerics.checkCollection(value).iterator();
while (it.hasNext()) {
Object thisValue = it.next();
addValueSingle(buffer, field, thisValue, params);
if (it.hasNext()) buffer.append(", ");
}
buffer.append(")");
} else {
addValueSingle(buffer, field, value, params);
}
}
}