001: package liquibase.database.template;
002:
003: import java.io.StringWriter;
004: import java.math.BigDecimal;
005: import java.sql.PreparedStatement;
006: import java.sql.SQLException;
007: import java.sql.Types;
008: import java.util.Calendar;
009:
010: /**
011: * Utility methods for PreparedStatementSetter/Creator and CallableStatementCreator
012: * implementations, providing sophisticated parameter management (including support
013: * for LOB values).
014: * <p/>
015: * <p>Used by PreparedStatementCreatorFactory and CallableStatementCreatorFactory,
016: * but also available for direct use in custom setter/creator implementations.
017: *
018: * @author Spring Framework
019: * @see PreparedStatementSetter
020: * @see SqlParameter
021: */
022: abstract class StatementCreatorUtils {
023:
024: /**
025: * Set the value for a parameter. The method used is based on the SQL type
026: * of the parameter and we can handle complex types like arrays and LOBs.
027: *
028: * @param ps the prepared statement or callable statement
029: * @param paramIndex index of the parameter we are setting
030: * @param param the parameter as it is declared including type
031: * @param inValue the value to set
032: * @throws SQLException if thrown by PreparedStatement methods
033: */
034: public static void setParameterValue(PreparedStatement ps,
035: int paramIndex, SqlParameter param, Object inValue)
036: throws SQLException {
037:
038: setParameterValueInternal(ps, paramIndex, param.getSqlType(),
039: param.getTypeName(), param.getScale(), inValue);
040: }
041:
042: /**
043: * Set the value for a parameter. The method used is based on the SQL type
044: * of the parameter and we can handle complex types like arrays and LOBs.
045: *
046: * @param ps the prepared statement or callable statement
047: * @param paramIndex index of the parameter we are setting
048: * @param sqlType the SQL type of the parameter
049: * @param inValue the value to set (plain value or a SqlTypeValue)
050: * @throws SQLException if thrown by PreparedStatement methods
051: */
052: public static void setParameterValue(PreparedStatement ps,
053: int paramIndex, int sqlType, Object inValue)
054: throws SQLException {
055:
056: setParameterValueInternal(ps, paramIndex, sqlType, null, null,
057: inValue);
058: }
059:
060: /**
061: * Set the value for a parameter. The method used is based on the SQL type
062: * of the parameter and we can handle complex types like arrays and LOBs.
063: *
064: * @param ps the prepared statement or callable statement
065: * @param paramIndex index of the parameter we are setting
066: * @param sqlType the SQL type of the parameter
067: * @param typeName the type name of the parameter
068: * (optional, only used for SQL NULL and SqlTypeValue)
069: * @param scale the number of digits after the decimal point
070: * (for DECIMAL and NUMERIC types)
071: * @param inValue the value to set (plain value or a SqlTypeValue)
072: * @throws SQLException if thrown by PreparedStatement methods
073: */
074: private static void setParameterValueInternal(PreparedStatement ps,
075: int paramIndex, int sqlType, String typeName,
076: Integer scale, Object inValue) throws SQLException {
077:
078: if (inValue == null) {
079: if (sqlType == SqlTypeValue.TYPE_UNKNOWN) {
080: boolean useSetObject = false;
081: try {
082: useSetObject = (ps.getConnection().getMetaData()
083: .getDatabaseProductName().indexOf(
084: "Informix") != -1);
085: } catch (Throwable ex) {
086: // logger.debug("Could not check database product name", ex);
087: }
088: if (useSetObject) {
089: ps.setObject(paramIndex, null);
090: } else {
091: ps.setNull(paramIndex, Types.NULL);
092: }
093: } else if (typeName != null) {
094: ps.setNull(paramIndex, sqlType, typeName);
095: } else {
096: ps.setNull(paramIndex, sqlType);
097: }
098: } else { // inValue != null
099: if (inValue instanceof SqlTypeValue) {
100: ((SqlTypeValue) inValue).setTypeValue(ps, paramIndex,
101: sqlType, typeName);
102: } else if (sqlType == Types.VARCHAR) {
103: ps.setString(paramIndex, inValue.toString());
104: } else if (sqlType == Types.DECIMAL
105: || sqlType == Types.NUMERIC) {
106: if (inValue instanceof BigDecimal) {
107: ps.setBigDecimal(paramIndex, (BigDecimal) inValue);
108: } else if (scale != null) {
109: ps.setObject(paramIndex, inValue, sqlType, scale);
110: } else {
111: ps.setObject(paramIndex, inValue, sqlType);
112: }
113: } else if (sqlType == Types.DATE) {
114: if (inValue instanceof java.util.Date) {
115: if (inValue instanceof java.sql.Date) {
116: ps.setDate(paramIndex, (java.sql.Date) inValue);
117: } else {
118: ps.setDate(paramIndex, new java.sql.Date(
119: ((java.util.Date) inValue).getTime()));
120: }
121: } else if (inValue instanceof Calendar) {
122: Calendar cal = (Calendar) inValue;
123: ps.setDate(paramIndex, new java.sql.Date(cal
124: .getTime().getTime()), cal);
125: } else {
126: ps.setObject(paramIndex, inValue, Types.DATE);
127: }
128: } else if (sqlType == Types.TIME) {
129: if (inValue instanceof java.util.Date) {
130: if (inValue instanceof java.sql.Time) {
131: ps.setTime(paramIndex, (java.sql.Time) inValue);
132: } else {
133: ps.setTime(paramIndex, new java.sql.Time(
134: ((java.util.Date) inValue).getTime()));
135: }
136: } else if (inValue instanceof Calendar) {
137: Calendar cal = (Calendar) inValue;
138: ps.setTime(paramIndex, new java.sql.Time(cal
139: .getTime().getTime()), cal);
140: } else {
141: ps.setObject(paramIndex, inValue, Types.TIME);
142: }
143: } else if (sqlType == Types.TIMESTAMP) {
144: if (inValue instanceof java.util.Date) {
145: if (inValue instanceof java.sql.Timestamp) {
146: ps.setTimestamp(paramIndex,
147: (java.sql.Timestamp) inValue);
148: } else {
149: ps.setTimestamp(paramIndex,
150: new java.sql.Timestamp(
151: ((java.util.Date) inValue)
152: .getTime()));
153: }
154: } else if (inValue instanceof Calendar) {
155: Calendar cal = (Calendar) inValue;
156: ps.setTimestamp(paramIndex, new java.sql.Timestamp(
157: cal.getTime().getTime()), cal);
158: } else {
159: ps.setObject(paramIndex, inValue, Types.TIMESTAMP);
160: }
161: } else if (sqlType == SqlTypeValue.TYPE_UNKNOWN) {
162: if (isStringValue(inValue)) {
163: ps.setString(paramIndex, inValue.toString());
164: } else if (isDateValue(inValue)) {
165: ps.setTimestamp(paramIndex, new java.sql.Timestamp(
166: ((java.util.Date) inValue).getTime()));
167: } else if (inValue instanceof Calendar) {
168: Calendar cal = (Calendar) inValue;
169: ps.setTimestamp(paramIndex, new java.sql.Timestamp(
170: cal.getTime().getTime()));
171: } else {
172: // Fall back to generic setObject call without SQL type specified.
173: ps.setObject(paramIndex, inValue);
174: }
175: } else {
176: // Fall back to generic setObject call with SQL type specified.
177: ps.setObject(paramIndex, inValue, sqlType);
178: }
179: }
180: }
181:
182: /**
183: * Check whether the given value can be treated as a String value.
184: */
185: private static boolean isStringValue(Object inValue) {
186: return (inValue instanceof CharSequence || inValue instanceof StringWriter);
187: }
188:
189: /**
190: * Check whether the given value is a <code>java.util.Date</code>
191: * (but not one of the JDBC-specific subclasses).
192: */
193: private static boolean isDateValue(Object inValue) {
194: return (inValue instanceof java.util.Date && !(inValue instanceof java.sql.Date
195: || inValue instanceof java.sql.Time || inValue instanceof java.sql.Timestamp));
196: }
197:
198: }
|