0001: /*******************************************************************************
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: *******************************************************************************/package org.ofbiz.entity.jdbc;
0019:
0020: import java.io.ByteArrayInputStream;
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.ObjectInputStream;
0024: import java.io.Reader;
0025: import java.math.BigDecimal;
0026: import java.sql.ResultSet;
0027: import java.sql.ResultSetMetaData;
0028: import java.sql.SQLException;
0029: import java.sql.Clob;
0030: import java.util.Collection;
0031: import java.util.Iterator;
0032: import java.util.List;
0033: import java.util.Map;
0034: import java.util.Set;
0035: import java.util.TreeSet;
0036:
0037: import javolution.util.FastMap;
0038:
0039: import org.ofbiz.base.util.Debug;
0040: import org.ofbiz.base.util.ObjectType;
0041: import org.ofbiz.base.util.UtilValidate;
0042: import org.ofbiz.entity.GenericDataSourceException;
0043: import org.ofbiz.entity.GenericEntity;
0044: import org.ofbiz.entity.GenericEntityException;
0045: import org.ofbiz.entity.GenericModelException;
0046: import org.ofbiz.entity.GenericNotImplementedException;
0047: import org.ofbiz.entity.GenericValue;
0048: import org.ofbiz.entity.condition.EntityConditionParam;
0049: import org.ofbiz.entity.condition.OrderByList;
0050: import org.ofbiz.entity.config.DatasourceInfo;
0051: import org.ofbiz.entity.datasource.GenericDAO;
0052: import org.ofbiz.entity.model.ModelEntity;
0053: import org.ofbiz.entity.model.ModelField;
0054: import org.ofbiz.entity.model.ModelFieldType;
0055: import org.ofbiz.entity.model.ModelFieldTypeReader;
0056: import org.ofbiz.entity.model.ModelKeyMap;
0057: import org.ofbiz.entity.model.ModelViewEntity;
0058:
0059: /**
0060: * GenericDAO Utility methods for general tasks
0061: *
0062: */
0063: public class SqlJdbcUtil {
0064: public static final String module = GenericDAO.class.getName();
0065:
0066: public static final int CHAR_BUFFER_SIZE = 4096;
0067:
0068: /** Makes the FROM clause and when necessary the JOIN clause(s) as well */
0069: public static String makeFromClause(ModelEntity modelEntity,
0070: DatasourceInfo datasourceInfo)
0071: throws GenericEntityException {
0072: StringBuffer sql = new StringBuffer(" FROM ");
0073:
0074: if (modelEntity instanceof ModelViewEntity) {
0075: ModelViewEntity modelViewEntity = (ModelViewEntity) modelEntity;
0076:
0077: if ("ansi".equals(datasourceInfo.joinStyle)
0078: || "ansi-no-parenthesis"
0079: .equals(datasourceInfo.joinStyle)) {
0080: boolean useParenthesis = true;
0081: if ("ansi-no-parenthesis"
0082: .equals(datasourceInfo.joinStyle)) {
0083: useParenthesis = false;
0084: }
0085:
0086: // FROM clause: in this case will be a bunch of joins that correspond with the view-links
0087:
0088: // BIG NOTE on the JOIN clauses: the order of joins is determined by the order of the
0089: // view-links; for more flexible order we'll have to figure something else out and
0090: // extend the DTD for the nested view-link elements or something
0091:
0092: // At this point it is assumed that in each view-link the left hand alias will
0093: // either be the first alias in the series or will already be in a previous
0094: // view-link and already be in the big join; SO keep a set of all aliases
0095: // in the join so far and if the left entity alias isn't there yet, and this
0096: // isn't the first one, throw an exception
0097: Set joinedAliasSet = new TreeSet();
0098:
0099: // TODO: at view-link read time make sure they are ordered properly so that each
0100: // left hand alias after the first view-link has already been linked before
0101:
0102: StringBuffer openParens = null;
0103: if (useParenthesis)
0104: openParens = new StringBuffer();
0105: StringBuffer restOfStatement = new StringBuffer();
0106:
0107: for (int i = 0; i < modelViewEntity.getViewLinksSize(); i++) {
0108: // don't put starting parenthesis
0109: if (i > 0 && useParenthesis)
0110: openParens.append('(');
0111:
0112: ModelViewEntity.ModelViewLink viewLink = modelViewEntity
0113: .getViewLink(i);
0114:
0115: ModelEntity linkEntity = modelViewEntity
0116: .getMemberModelEntity(viewLink
0117: .getEntityAlias());
0118: ModelEntity relLinkEntity = modelViewEntity
0119: .getMemberModelEntity(viewLink
0120: .getRelEntityAlias());
0121:
0122: // ModelViewEntity.ModelMemberEntity linkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getEntityAlias());
0123: // ModelViewEntity.ModelMemberEntity relLinkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getRelEntityAlias());
0124:
0125: if (i == 0) {
0126: // this is the first referenced member alias, so keep track of it for future use...
0127: restOfStatement.append(makeViewTable(
0128: linkEntity, datasourceInfo));
0129: //another possible one that some dbs might need, but not sure of any yet: restOfStatement.append(" AS ");
0130: restOfStatement.append(" ");
0131: restOfStatement.append(viewLink
0132: .getEntityAlias());
0133:
0134: joinedAliasSet.add(viewLink.getEntityAlias());
0135: } else {
0136: // make sure the left entity alias is already in the join...
0137: if (!joinedAliasSet.contains(viewLink
0138: .getEntityAlias())) {
0139: throw new GenericModelException(
0140: "Tried to link the "
0141: + viewLink.getEntityAlias()
0142: + " alias to the "
0143: + viewLink
0144: .getRelEntityAlias()
0145: + " alias of the "
0146: + modelViewEntity
0147: .getEntityName()
0148: + " 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.");
0149: }
0150: }
0151: // now put the rel (right) entity alias into the set that is in the join
0152: joinedAliasSet.add(viewLink.getRelEntityAlias());
0153:
0154: if (viewLink.isRelOptional()) {
0155: restOfStatement.append(" LEFT OUTER JOIN ");
0156: } else {
0157: restOfStatement.append(" INNER JOIN ");
0158: }
0159:
0160: restOfStatement.append(makeViewTable(relLinkEntity,
0161: datasourceInfo));
0162: //another possible one that some dbs might need, but not sure of any yet: restOfStatement.append(" AS ");
0163: restOfStatement.append(" ");
0164: restOfStatement
0165: .append(viewLink.getRelEntityAlias());
0166: restOfStatement.append(" ON ");
0167:
0168: StringBuffer condBuffer = new StringBuffer();
0169:
0170: for (int j = 0; j < viewLink.getKeyMapsSize(); j++) {
0171: ModelKeyMap keyMap = viewLink.getKeyMap(j);
0172: ModelField linkField = linkEntity
0173: .getField(keyMap.getFieldName());
0174: if (linkField == null) {
0175: throw new GenericModelException(
0176: "Invalid field name in view-link key-map for the "
0177: + viewLink.getEntityAlias()
0178: + " and the "
0179: + viewLink
0180: .getRelEntityAlias()
0181: + " member-entities of the "
0182: + modelViewEntity
0183: .getEntityName()
0184: + " view-entity; the field ["
0185: + keyMap.getFieldName()
0186: + "] does not exist on the ["
0187: + linkEntity
0188: .getEntityName()
0189: + "] entity.");
0190: }
0191: ModelField relLinkField = relLinkEntity
0192: .getField(keyMap.getRelFieldName());
0193: if (relLinkField == null) {
0194: throw new GenericModelException(
0195: "Invalid related field name in view-link key-map for the "
0196: + viewLink.getEntityAlias()
0197: + " and the "
0198: + viewLink
0199: .getRelEntityAlias()
0200: + " member-entities of the "
0201: + modelViewEntity
0202: .getEntityName()
0203: + " view-entity; the field ["
0204: + keyMap.getRelFieldName()
0205: + "] does not exist on the ["
0206: + relLinkEntity
0207: .getEntityName()
0208: + "] entity.");
0209: }
0210:
0211: if (condBuffer.length() > 0) {
0212: condBuffer.append(" AND ");
0213: }
0214:
0215: condBuffer.append(viewLink.getEntityAlias());
0216: condBuffer.append(".");
0217: condBuffer.append(filterColName(linkField
0218: .getColName()));
0219:
0220: condBuffer.append(" = ");
0221:
0222: condBuffer.append(viewLink.getRelEntityAlias());
0223: condBuffer.append(".");
0224: condBuffer.append(filterColName(relLinkField
0225: .getColName()));
0226: }
0227: if (condBuffer.length() == 0) {
0228: throw new GenericModelException(
0229: "No view-link/join key-maps found for the "
0230: + viewLink.getEntityAlias()
0231: + " and the "
0232: + viewLink.getRelEntityAlias()
0233: + " member-entities of the "
0234: + modelViewEntity
0235: .getEntityName()
0236: + " view-entity.");
0237: }
0238: restOfStatement.append(condBuffer.toString());
0239:
0240: // don't put ending parenthesis
0241: if (i < (modelViewEntity.getViewLinksSize() - 1)
0242: && useParenthesis)
0243: restOfStatement.append(')');
0244: }
0245:
0246: if (useParenthesis)
0247: sql.append(openParens.toString());
0248: sql.append(restOfStatement.toString());
0249:
0250: // handle tables not included in view-link
0251: Iterator meIter = modelViewEntity
0252: .getMemberModelMemberEntities().entrySet()
0253: .iterator();
0254: boolean fromEmpty = restOfStatement.length() == 0;
0255:
0256: while (meIter.hasNext()) {
0257: Map.Entry entry = (Map.Entry) meIter.next();
0258: ModelEntity fromEntity = modelViewEntity
0259: .getMemberModelEntity((String) entry
0260: .getKey());
0261:
0262: if (!joinedAliasSet.contains((String) entry
0263: .getKey())) {
0264: if (!fromEmpty)
0265: sql.append(", ");
0266: fromEmpty = false;
0267:
0268: sql.append(makeViewTable(fromEntity,
0269: datasourceInfo));
0270: sql.append(" ");
0271: sql.append((String) entry.getKey());
0272: }
0273: }
0274:
0275: } else if ("theta-oracle".equals(datasourceInfo.joinStyle)
0276: || "theta-mssql".equals(datasourceInfo.joinStyle)) {
0277: // FROM clause
0278: Iterator meIter = modelViewEntity
0279: .getMemberModelMemberEntities().entrySet()
0280: .iterator();
0281:
0282: while (meIter.hasNext()) {
0283: Map.Entry entry = (Map.Entry) meIter.next();
0284: ModelEntity fromEntity = modelViewEntity
0285: .getMemberModelEntity((String) entry
0286: .getKey());
0287:
0288: sql
0289: .append(makeViewTable(fromEntity,
0290: datasourceInfo));
0291: sql.append(" ");
0292: sql.append((String) entry.getKey());
0293: if (meIter.hasNext())
0294: sql.append(", ");
0295: }
0296:
0297: // JOIN clause(s): none needed, all the work done in the where clause for theta-oracle
0298: } else {
0299: throw new GenericModelException("The join-style "
0300: + datasourceInfo.joinStyle
0301: + " is not yet supported");
0302: }
0303: } else {
0304: sql.append(modelEntity.getTableName(datasourceInfo));
0305: }
0306: return sql.toString();
0307: }
0308:
0309: /** Makes a WHERE clause String with "<col name>=?" if not null or "<col name> IS null" if null, all AND separated */
0310: public static String makeWhereStringFromFields(List modelFields,
0311: Map fields, String operator) {
0312: return makeWhereStringFromFields(modelFields, fields, operator,
0313: null);
0314: }
0315:
0316: /** Makes a WHERE clause String with "<col name>=?" if not null or "<col name> IS null" if null, all AND separated */
0317: public static String makeWhereStringFromFields(List modelFields,
0318: Map fields, String operator, List entityConditionParams) {
0319: if (modelFields.size() < 1) {
0320: return "";
0321: }
0322:
0323: StringBuffer returnString = new StringBuffer("");
0324: Iterator iter = modelFields.iterator();
0325: while (iter.hasNext()) {
0326: Object item = iter.next();
0327: Object name = null;
0328: ModelField modelField = null;
0329: if (item instanceof ModelField) {
0330: modelField = (ModelField) item;
0331: returnString.append(modelField.getColName());
0332: name = modelField.getName();
0333: } else {
0334: returnString.append(item);
0335: name = item;
0336: }
0337:
0338: Object fieldValue = fields.get(name);
0339: if (fieldValue != null
0340: && fieldValue != GenericEntity.NULL_FIELD) {
0341: returnString.append('=');
0342: addValue(returnString, modelField, fieldValue,
0343: entityConditionParams);
0344: } else {
0345: returnString.append(" IS NULL");
0346: }
0347:
0348: if (iter.hasNext()) {
0349: returnString.append(' ');
0350: returnString.append(operator);
0351: returnString.append(' ');
0352: }
0353: }
0354:
0355: return returnString.toString();
0356: }
0357:
0358: public static String makeWhereClause(ModelEntity modelEntity,
0359: List modelFields, Map fields, String operator,
0360: String joinStyle) throws GenericEntityException {
0361: StringBuffer whereString = new StringBuffer("");
0362:
0363: if (modelFields != null && modelFields.size() > 0) {
0364: whereString.append(makeWhereStringFromFields(modelFields,
0365: fields, "AND"));
0366: }
0367:
0368: String viewClause = makeViewWhereClause(modelEntity, joinStyle);
0369:
0370: if (viewClause.length() > 0) {
0371: if (whereString.length() > 0) {
0372: whereString.append(' ');
0373: whereString.append(operator);
0374: whereString.append(' ');
0375: }
0376:
0377: whereString.append(viewClause);
0378: }
0379:
0380: if (whereString.length() > 0) {
0381: return " WHERE " + whereString.toString();
0382: }
0383:
0384: return "";
0385: }
0386:
0387: public static String makeViewWhereClause(ModelEntity modelEntity,
0388: String joinStyle) throws GenericEntityException {
0389: if (modelEntity instanceof ModelViewEntity) {
0390: StringBuffer whereString = new StringBuffer();
0391: ModelViewEntity modelViewEntity = (ModelViewEntity) modelEntity;
0392:
0393: if ("ansi".equals(joinStyle)
0394: || "ansi-no-parenthesis".equals(joinStyle)) {
0395: // nothing to do here, all done in the JOIN clauses
0396: } else if ("theta-oracle".equals(joinStyle)
0397: || "theta-mssql".equals(joinStyle)) {
0398: boolean isOracleStyle = "theta-oracle"
0399: .equals(joinStyle);
0400: boolean isMssqlStyle = "theta-mssql".equals(joinStyle);
0401:
0402: for (int i = 0; i < modelViewEntity.getViewLinksSize(); i++) {
0403: ModelViewEntity.ModelViewLink viewLink = modelViewEntity
0404: .getViewLink(i);
0405:
0406: ModelEntity linkEntity = modelViewEntity
0407: .getMemberModelEntity(viewLink
0408: .getEntityAlias());
0409: ModelEntity relLinkEntity = modelViewEntity
0410: .getMemberModelEntity(viewLink
0411: .getRelEntityAlias());
0412:
0413: if (linkEntity == null) {
0414: throw new GenericEntityException(
0415: "Link entity not found with alias: "
0416: + viewLink.getEntityAlias()
0417: + " for entity: "
0418: + modelViewEntity
0419: .getEntityName());
0420: }
0421:
0422: if (relLinkEntity == null) {
0423: throw new GenericEntityException(
0424: "Rel-Link entity not found with alias: "
0425: + viewLink.getRelEntityAlias()
0426: + " for entity: "
0427: + modelViewEntity
0428: .getEntityName());
0429: }
0430:
0431: // ModelViewEntity.ModelMemberEntity linkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getEntityAlias());
0432: // ModelViewEntity.ModelMemberEntity relLinkMemberEntity = modelViewEntity.getMemberModelMemberEntity(viewLink.getRelEntityAlias());
0433:
0434: for (int j = 0; j < viewLink.getKeyMapsSize(); j++) {
0435: ModelKeyMap keyMap = viewLink.getKeyMap(j);
0436: ModelField linkField = linkEntity
0437: .getField(keyMap.getFieldName());
0438: ModelField relLinkField = relLinkEntity
0439: .getField(keyMap.getRelFieldName());
0440:
0441: if (whereString.length() > 0) {
0442: whereString.append(" AND ");
0443: }
0444: whereString.append(viewLink.getEntityAlias());
0445: whereString.append(".");
0446: whereString.append(filterColName(linkField
0447: .getColName()));
0448:
0449: // check to see whether the left or right members are optional, if so:
0450: // oracle: use the (+) on the optional side
0451: // mssql: use the * on the required side
0452:
0453: // NOTE: not testing if original table is optional, ONLY if related table is optional; otherwise things get really ugly...
0454: // if (isOracleStyle && linkMemberEntity.getOptional()) whereString.append(" (+) ");
0455: if (isMssqlStyle && viewLink.isRelOptional())
0456: whereString.append("*");
0457: whereString.append("=");
0458: // if (isMssqlStyle && linkMemberEntity.getOptional()) whereString.append("*");
0459: if (isOracleStyle && viewLink.isRelOptional())
0460: whereString.append(" (+) ");
0461:
0462: whereString
0463: .append(viewLink.getRelEntityAlias());
0464: whereString.append(".");
0465: whereString.append(filterColName(relLinkField
0466: .getColName()));
0467: }
0468: }
0469: } else {
0470: throw new GenericModelException("The join-style "
0471: + joinStyle + " is not supported");
0472: }
0473:
0474: if (whereString.length() > 0) {
0475: return "(" + whereString.toString() + ")";
0476: }
0477: }
0478: return "";
0479: }
0480:
0481: public static String makeOrderByClause(ModelEntity modelEntity,
0482: List orderBy, DatasourceInfo datasourceInfo)
0483: throws GenericModelException {
0484: return makeOrderByClause(modelEntity, orderBy, false,
0485: datasourceInfo);
0486: }
0487:
0488: public static String makeOrderByClause(ModelEntity modelEntity,
0489: List orderBy, boolean includeTablenamePrefix,
0490: DatasourceInfo datasourceInfo) throws GenericModelException {
0491: StringBuffer sql = new StringBuffer("");
0492: //String fieldPrefix = includeTablenamePrefix ? (modelEntity.getTableName(datasourceInfo) + ".") : "";
0493:
0494: if (orderBy != null && orderBy.size() > 0) {
0495: if (Debug.verboseOn())
0496: Debug.logVerbose("Order by list contains: "
0497: + orderBy.size() + " entries.", module);
0498: OrderByList orderByList = new OrderByList(orderBy);
0499: orderByList.checkOrderBy(modelEntity);
0500: orderByList.makeOrderByString(sql, modelEntity,
0501: includeTablenamePrefix, datasourceInfo);
0502: }
0503: if (Debug.verboseOn())
0504: Debug.logVerbose("makeOrderByClause: " + sql.toString(),
0505: module);
0506: return sql.toString();
0507: }
0508:
0509: public static String makeViewTable(ModelEntity modelEntity,
0510: DatasourceInfo datasourceInfo)
0511: throws GenericEntityException {
0512: if (modelEntity instanceof ModelViewEntity) {
0513: StringBuffer sql = new StringBuffer("(SELECT ");
0514: Iterator fieldsIter = modelEntity.getFieldsIterator();
0515: if (fieldsIter.hasNext()) {
0516: ModelField curField = (ModelField) fieldsIter.next();
0517: String colname = curField.getColName();
0518: sql.append(colname);
0519: sql.append(" AS ");
0520: sql.append(filterColName(colname));
0521: while (fieldsIter.hasNext()) {
0522: curField = (ModelField) fieldsIter.next();
0523: colname = curField.getColName();
0524: sql.append(", ");
0525: sql.append(colname);
0526: sql.append(" AS ");
0527: sql.append(filterColName(colname));
0528: }
0529: }
0530: sql.append(makeFromClause(modelEntity, datasourceInfo));
0531: String viewWhereClause = makeViewWhereClause(modelEntity,
0532: datasourceInfo.joinStyle);
0533: if (UtilValidate.isNotEmpty(viewWhereClause)) {
0534: sql.append(" WHERE ");
0535: sql.append(viewWhereClause);
0536: }
0537: ModelViewEntity modelViewEntity = (ModelViewEntity) modelEntity;
0538: String groupByString = modelViewEntity.colNameString(
0539: modelViewEntity.getGroupBysCopy(), ", ", "", false);
0540: if (UtilValidate.isNotEmpty(groupByString)) {
0541: sql.append(" GROUP BY ");
0542: sql.append(groupByString);
0543: }
0544:
0545: sql.append(")");
0546: return sql.toString();
0547: } else {
0548: return modelEntity.getTableName(datasourceInfo);
0549: }
0550: }
0551:
0552: public static String filterColName(String colName) {
0553: return colName.replace('.', '_').replace('(', '_').replace(')',
0554: '_');
0555: }
0556:
0557: /* ====================================================================== */
0558:
0559: /* ====================================================================== */
0560:
0561: /**
0562: * The elements (ModelFields) of the list are bound to an SQL statement
0563: * (SQL-Processor)
0564: *
0565: * @param sqlP
0566: * @param list
0567: * @param entity
0568: * @throws GenericEntityException
0569: */
0570: public static void setValues(SQLProcessor sqlP, List list,
0571: GenericEntity entity,
0572: ModelFieldTypeReader modelFieldTypeReader)
0573: throws GenericEntityException {
0574: Iterator fieldIter = list.iterator();
0575: while (fieldIter.hasNext()) {
0576: ModelField curField = (ModelField) fieldIter.next();
0577: setValue(sqlP, curField, entity, modelFieldTypeReader);
0578: }
0579: }
0580:
0581: /**
0582: * The elements (ModelFields) of the list are bound to an SQL statement
0583: * (SQL-Processor), but values must not be null.
0584: *
0585: * @param sqlP
0586: * @param list
0587: * @param dummyValue
0588: * @param modelFieldTypeReader
0589: * @throws GenericEntityException
0590: */
0591: public static void setValuesWhereClause(SQLProcessor sqlP,
0592: List list, GenericValue dummyValue,
0593: ModelFieldTypeReader modelFieldTypeReader)
0594: throws GenericEntityException {
0595: Iterator fieldIter = list.iterator();
0596: while (fieldIter.hasNext()) {
0597: ModelField curField = (ModelField) fieldIter.next();
0598: // for where clause variables only setValue if not null...
0599: if (dummyValue.get(curField.getName()) != null) {
0600: setValue(sqlP, curField, dummyValue,
0601: modelFieldTypeReader);
0602: }
0603: }
0604: }
0605:
0606: /**
0607: * Get all primary keys from the model entity and bind their values
0608: * to the an SQL statement (SQL-Processor)
0609: *
0610: * @param sqlP
0611: * @param modelEntity
0612: * @param entity
0613: * @param modelFieldTypeReader
0614: * @throws GenericEntityException
0615: */
0616: public static void setPkValues(SQLProcessor sqlP,
0617: ModelEntity modelEntity, GenericEntity entity,
0618: ModelFieldTypeReader modelFieldTypeReader)
0619: throws GenericEntityException {
0620: Iterator pksIter = modelEntity.getPksIterator();
0621: while (pksIter.hasNext()) {
0622: ModelField curField = (ModelField) pksIter.next();
0623:
0624: // for where clause variables only setValue if not null...
0625: if (entity.dangerousGetNoCheckButFast(curField) != null) {
0626: setValue(sqlP, curField, entity, modelFieldTypeReader);
0627: }
0628: }
0629: }
0630:
0631: public static void getValue(ResultSet rs, int ind,
0632: ModelField curField, GenericEntity entity,
0633: ModelFieldTypeReader modelFieldTypeReader)
0634: throws GenericEntityException {
0635: ModelFieldType mft = modelFieldTypeReader
0636: .getModelFieldType(curField.getType());
0637:
0638: if (mft == null) {
0639: throw new GenericModelException("definition fieldType "
0640: + curField.getType()
0641: + " not found, cannot getValue for field "
0642: + entity.getEntityName() + "." + curField.getName()
0643: + ".");
0644: }
0645: String fieldType = mft.getJavaType();
0646:
0647: try {
0648: // checking to see if the object is null is really only necessary for the numbers
0649: int typeValue = getType(fieldType);
0650: ResultSetMetaData rsmd = rs.getMetaData();
0651: int colType = rsmd.getColumnType(ind);
0652:
0653: if (typeValue <= 4 || typeValue >= 11) {
0654: switch (typeValue) {
0655: case 1:
0656: if (java.sql.Types.CLOB == colType) {
0657: // Debug.logInfo("For field " + curField.getName() + " of entity " + entity.getEntityName() + " getString is a CLOB, trying getCharacterStream", module);
0658: // if the String is empty, try to get a text input stream, this is required for some databases for larger fields, like CLOBs
0659:
0660: Clob valueClob = rs.getClob(ind);
0661: Reader valueReader = null;
0662: if (valueClob != null) {
0663: valueReader = valueClob
0664: .getCharacterStream();
0665: }
0666:
0667: //Reader valueReader = rs.getCharacterStream(ind);
0668: if (valueReader != null) {
0669: char[] inCharBuffer = new char[CHAR_BUFFER_SIZE];
0670: StringBuffer strBuf = new StringBuffer();
0671: int charsRead = 0;
0672: try {
0673: while ((charsRead = valueReader.read(
0674: inCharBuffer, 0,
0675: CHAR_BUFFER_SIZE)) > 0) {
0676: strBuf.append(inCharBuffer, 0,
0677: charsRead);
0678: }
0679: valueReader.close();
0680: } catch (IOException e) {
0681: throw new GenericEntityException(
0682: "Error reading long character stream for field "
0683: + curField.getName()
0684: + " of entity "
0685: + entity
0686: .getEntityName(),
0687: e);
0688: }
0689: entity.dangerousSetNoCheckButFast(curField,
0690: strBuf.toString());
0691: } else {
0692: entity.dangerousSetNoCheckButFast(curField,
0693: null);
0694: }
0695: } else {
0696: String value = rs.getString(ind);
0697: entity.dangerousSetNoCheckButFast(curField,
0698: value);
0699: }
0700: break;
0701:
0702: case 2:
0703: entity.dangerousSetNoCheckButFast(curField, rs
0704: .getTimestamp(ind));
0705: break;
0706:
0707: case 3:
0708: entity.dangerousSetNoCheckButFast(curField, rs
0709: .getTime(ind));
0710: break;
0711:
0712: case 4:
0713: entity.dangerousSetNoCheckButFast(curField, rs
0714: .getDate(ind));
0715: break;
0716:
0717: case 11:
0718: Object obj = null;
0719: InputStream binaryInput = null;
0720:
0721: byte[] fieldBytes = rs.getBytes(ind);
0722: if (fieldBytes != null && fieldBytes.length > 0) {
0723: binaryInput = new ByteArrayInputStream(
0724: fieldBytes);
0725: }
0726:
0727: if (fieldBytes != null && fieldBytes.length <= 0) {
0728: Debug.logWarning(
0729: "Got bytes back for Object field with length: "
0730: + fieldBytes.length
0731: + " while getting value : "
0732: + curField.getName() + " ["
0733: + curField.getColName() + "] ("
0734: + ind + "): ", module);
0735: }
0736:
0737: //alt 1: binaryInput = rs.getBinaryStream(ind);
0738: //alt 2: Blob blobLocator = rs.getBlob(ind);
0739: //if (blobLocator != null) {
0740: // binaryInput = blobLocator.getBinaryStream();
0741: //}
0742:
0743: if (binaryInput != null) {
0744: ObjectInputStream in = null;
0745: try {
0746: in = new ObjectInputStream(binaryInput);
0747: obj = in.readObject();
0748: } catch (IOException ex) {
0749: throw new GenericDataSourceException(
0750: "Unable to read BLOB data from input stream while getting value : "
0751: + curField.getName() + " ["
0752: + curField.getColName()
0753: + "] (" + ind + "): "
0754: + ex.toString(), ex);
0755: } catch (ClassNotFoundException ex) {
0756: throw new GenericDataSourceException(
0757: "Class not found: Unable to cast BLOB data to an Java object while getting value : "
0758: + curField.getName()
0759: + " ["
0760: + curField.getColName()
0761: + "] ("
0762: + ind
0763: + "): "
0764: + ex.toString(), ex);
0765: } finally {
0766: if (in != null) {
0767: try {
0768: in.close();
0769: } catch (IOException e) {
0770: throw new GenericDataSourceException(
0771: "Unable to close binary input stream while getting value : "
0772: + curField
0773: .getName()
0774: + " ["
0775: + curField
0776: .getColName()
0777: + "] (" + ind
0778: + "): "
0779: + e.toString(), e);
0780: }
0781: }
0782: }
0783: }
0784:
0785: binaryInput = null;
0786: entity.dangerousSetNoCheckButFast(curField, obj);
0787: break;
0788: case 12:
0789: entity.dangerousSetNoCheckButFast(curField, rs
0790: .getBlob(ind));
0791: break;
0792: case 13:
0793: entity.dangerousSetNoCheckButFast(curField, rs
0794: .getClob(ind));
0795: break;
0796: case 14:
0797: case 15:
0798: entity.dangerousSetNoCheckButFast(curField, rs
0799: .getObject(ind));
0800: break;
0801: }
0802: } else {
0803: switch (typeValue) {
0804: case 5:
0805: int intValue = rs.getInt(ind);
0806: if (rs.wasNull()) {
0807: entity.dangerousSetNoCheckButFast(curField,
0808: null);
0809: } else {
0810: entity.dangerousSetNoCheckButFast(curField,
0811: new Integer(intValue));
0812: }
0813: break;
0814:
0815: case 6:
0816: long longValue = rs.getLong(ind);
0817: if (rs.wasNull()) {
0818: entity.dangerousSetNoCheckButFast(curField,
0819: null);
0820: } else {
0821: entity.dangerousSetNoCheckButFast(curField,
0822: new Long(longValue));
0823: }
0824: break;
0825:
0826: case 7:
0827: float floatValue = rs.getFloat(ind);
0828: if (rs.wasNull()) {
0829: entity.dangerousSetNoCheckButFast(curField,
0830: null);
0831: } else {
0832: entity.dangerousSetNoCheckButFast(curField,
0833: new Float(floatValue));
0834: }
0835: break;
0836:
0837: case 8:
0838: double doubleValue = rs.getDouble(ind);
0839: if (rs.wasNull()) {
0840: entity.dangerousSetNoCheckButFast(curField,
0841: null);
0842: } else {
0843: entity.dangerousSetNoCheckButFast(curField,
0844: new Double(doubleValue));
0845: }
0846: break;
0847:
0848: case 9:
0849: BigDecimal bigDecimalValue = rs.getBigDecimal(ind);
0850: if (rs.wasNull()) {
0851: entity.dangerousSetNoCheckButFast(curField,
0852: null);
0853: } else {
0854: entity.dangerousSetNoCheckButFast(curField,
0855: bigDecimalValue);
0856: }
0857: break;
0858:
0859: case 10:
0860: boolean booleanValue = rs.getBoolean(ind);
0861: if (rs.wasNull()) {
0862: entity.dangerousSetNoCheckButFast(curField,
0863: null);
0864: } else {
0865: entity.dangerousSetNoCheckButFast(curField,
0866: new Boolean(booleanValue));
0867: }
0868: break;
0869: }
0870: }
0871: } catch (SQLException sqle) {
0872: throw new GenericDataSourceException(
0873: "SQL Exception while getting value : "
0874: + curField.getName() + " ["
0875: + curField.getColName() + "] (" + ind + ")",
0876: sqle);
0877: }
0878: }
0879:
0880: public static void setValue(SQLProcessor sqlP,
0881: ModelField modelField, GenericEntity entity,
0882: ModelFieldTypeReader modelFieldTypeReader)
0883: throws GenericEntityException {
0884: Object fieldValue = entity
0885: .dangerousGetNoCheckButFast(modelField);
0886:
0887: setValue(sqlP, modelField, entity.getEntityName(), fieldValue,
0888: modelFieldTypeReader);
0889: }
0890:
0891: public static void setValue(SQLProcessor sqlP,
0892: ModelField modelField, String entityName,
0893: Object fieldValue, ModelFieldTypeReader modelFieldTypeReader)
0894: throws GenericEntityException {
0895: ModelFieldType mft = modelFieldTypeReader
0896: .getModelFieldType(modelField.getType());
0897:
0898: if (mft == null) {
0899: throw new GenericModelException(
0900: "GenericDAO.getValue: definition fieldType "
0901: + modelField.getType()
0902: + " not found, cannot setValue for field "
0903: + entityName + "." + modelField.getName()
0904: + ".");
0905: }
0906:
0907: // if the value is the GenericEntity.NullField, treat as null
0908: if (fieldValue == GenericEntity.NULL_FIELD) {
0909: fieldValue = null;
0910: }
0911:
0912: String fieldType = mft.getJavaType();
0913: if (fieldValue != null) {
0914: if (!ObjectType.instanceOf(fieldValue, fieldType)) {
0915: // this is only an info level message because under normal operation for most JDBC
0916: // drivers this will be okay, but if not then the JDBC driver will throw an exception
0917: // and when lower debug levels are on this should help give more info on what happened
0918: Class fieldClass = fieldValue.getClass();
0919: String fieldClassName = fieldClass.getName();
0920:
0921: if (Debug.verboseOn())
0922: Debug
0923: .logVerbose(
0924: "type of field "
0925: + entityName
0926: + "."
0927: + modelField.getName()
0928: + " is "
0929: + fieldClassName
0930: + ", was expecting "
0931: + mft.getJavaType()
0932: + "; this may "
0933: + "indicate an error in the configuration or in the class, and may result "
0934: + "in an SQL-Java data conversion error. Will use the real field type: "
0935: + fieldClassName
0936: + ", not the definition.",
0937: module);
0938: fieldType = fieldClassName;
0939: }
0940: }
0941:
0942: try {
0943: int typeValue = getType(fieldType);
0944:
0945: switch (typeValue) {
0946: case 1:
0947: sqlP.setValue((String) fieldValue);
0948: break;
0949:
0950: case 2:
0951: sqlP.setValue((java.sql.Timestamp) fieldValue);
0952: break;
0953:
0954: case 3:
0955: sqlP.setValue((java.sql.Time) fieldValue);
0956: break;
0957:
0958: case 4:
0959: sqlP.setValue((java.sql.Date) fieldValue);
0960: break;
0961:
0962: case 5:
0963: sqlP.setValue((java.lang.Integer) fieldValue);
0964: break;
0965:
0966: case 6:
0967: sqlP.setValue((java.lang.Long) fieldValue);
0968: break;
0969:
0970: case 7:
0971: sqlP.setValue((java.lang.Float) fieldValue);
0972: break;
0973:
0974: case 8:
0975: sqlP.setValue((java.lang.Double) fieldValue);
0976: break;
0977:
0978: case 9:
0979: sqlP.setValue((java.math.BigDecimal) fieldValue);
0980: break;
0981:
0982: case 10:
0983: sqlP.setValue((java.lang.Boolean) fieldValue);
0984: break;
0985:
0986: case 11:
0987: sqlP.setBinaryStream(fieldValue);
0988: break;
0989:
0990: case 12:
0991: sqlP.setValue((java.sql.Blob) fieldValue);
0992: break;
0993:
0994: case 13:
0995: sqlP.setValue((java.sql.Clob) fieldValue);
0996: break;
0997:
0998: case 14:
0999: if (fieldValue != null) {
1000: sqlP.setValue(new java.sql.Date(
1001: ((java.util.Date) fieldValue).getTime()));
1002: } else {
1003: sqlP.setValue((java.sql.Date) null);
1004: }
1005: break;
1006:
1007: case 15:
1008: sqlP.setValue((java.util.Collection) fieldValue);
1009: break;
1010: }
1011: } catch (GenericNotImplementedException e) {
1012: throw new GenericNotImplementedException(
1013: "Not Implemented Exception while setting value on field ["
1014: + modelField.getName() + "] of entity "
1015: + entityName + ": " + e.toString(), e);
1016: } catch (SQLException sqle) {
1017: throw new GenericDataSourceException(
1018: "SQL Exception while setting value on field ["
1019: + modelField.getName() + "] of entity "
1020: + entityName + ": ", sqle);
1021: }
1022: }
1023:
1024: protected static Map fieldTypeMap = FastMap.newInstance();
1025: static {
1026: fieldTypeMap.put("java.lang.String", new Integer(1));
1027: fieldTypeMap.put("String", new Integer(1));
1028: fieldTypeMap.put("java.sql.Timestamp", new Integer(2));
1029: fieldTypeMap.put("Timestamp", new Integer(2));
1030: fieldTypeMap.put("java.sql.Time", new Integer(3));
1031: fieldTypeMap.put("Time", new Integer(3));
1032: fieldTypeMap.put("java.sql.Date", new Integer(4));
1033: fieldTypeMap.put("Date", new Integer(4));
1034: fieldTypeMap.put("java.lang.Integer", new Integer(5));
1035: fieldTypeMap.put("Integer", new Integer(5));
1036: fieldTypeMap.put("java.lang.Long", new Integer(6));
1037: fieldTypeMap.put("Long", new Integer(6));
1038: fieldTypeMap.put("java.lang.Float", new Integer(7));
1039: fieldTypeMap.put("Float", new Integer(7));
1040: fieldTypeMap.put("java.lang.Double", new Integer(8));
1041: fieldTypeMap.put("Double", new Integer(8));
1042: fieldTypeMap.put("java.math.BigDecimal", new Integer(9));
1043: fieldTypeMap.put("BigDecimal", new Integer(9));
1044: fieldTypeMap.put("java.lang.Boolean", new Integer(10));
1045: fieldTypeMap.put("Boolean", new Integer(10));
1046:
1047: fieldTypeMap.put("java.lang.Object", new Integer(11));
1048: fieldTypeMap.put("Object", new Integer(11));
1049: fieldTypeMap.put("java.sql.Blob", new Integer(12));
1050: fieldTypeMap.put("Blob", new Integer(12));
1051: fieldTypeMap.put("java.sql.Clob", new Integer(13));
1052: fieldTypeMap.put("Clob", new Integer(13));
1053:
1054: fieldTypeMap.put("java.util.Date", new Integer(14));
1055:
1056: // all of these treated as Collection
1057: fieldTypeMap.put("java.util.ArrayList", new Integer(15));
1058: fieldTypeMap.put("java.util.HashSet", new Integer(15));
1059: fieldTypeMap.put("java.util.LinkedHashSet", new Integer(15));
1060: fieldTypeMap.put("java.util.LinkedList", new Integer(15));
1061: }
1062:
1063: public static int getType(String fieldType)
1064: throws GenericNotImplementedException {
1065: Integer val = (Integer) fieldTypeMap.get(fieldType);
1066:
1067: if (val == null) {
1068: throw new GenericNotImplementedException("Java type "
1069: + fieldType + " not currently supported. Sorry.");
1070: }
1071: return val.intValue();
1072: }
1073:
1074: public static void addValueSingle(StringBuffer buffer,
1075: ModelField field, Object value, List params) {
1076: if (field != null) {
1077: buffer.append('?');
1078: } else {
1079: buffer.append('\'').append(value).append('\'');
1080: }
1081: if (field != null && params != null)
1082: params.add(new EntityConditionParam(field, value));
1083: }
1084:
1085: public static void addValue(StringBuffer buffer, ModelField field,
1086: Object value, List params) {
1087: if (value instanceof Collection) {
1088: buffer.append("( ");
1089: Iterator it = ((Collection) value).iterator();
1090: while (it.hasNext()) {
1091: Object this Value = it.next();
1092: addValueSingle(buffer, field, this Value, params);
1093: if (it.hasNext())
1094: buffer.append(", ");
1095: }
1096: buffer.append(" )");
1097: } else {
1098: addValueSingle(buffer, field, value, params);
1099: }
1100: }
1101: }
|