|
34 | 34 | import java.sql.ResultSetMetaData; |
35 | 35 | import java.sql.SQLException; |
36 | 36 | import java.sql.Statement; |
| 37 | +import java.sql.Time; |
| 38 | +import java.sql.Timestamp; |
| 39 | +import java.sql.Types; |
37 | 40 | import java.util.ArrayList; |
38 | 41 | import java.util.Arrays; |
39 | 42 | import java.util.Calendar; |
|
67 | 70 | import org.apache.commons.lang3.exception.ExceptionUtils; |
68 | 71 |
|
69 | 72 | import com.amazonaws.util.CollectionUtils; |
70 | | -import com.cloud.utils.DateUtil; |
71 | 73 | import com.cloud.utils.NumbersUtil; |
72 | 74 | import com.cloud.utils.Pair; |
73 | 75 | import com.cloud.utils.Ternary; |
@@ -129,6 +131,28 @@ public abstract class GenericDaoBase<T, ID extends Serializable> extends Compone |
129 | 131 |
|
130 | 132 | protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT"); |
131 | 133 |
|
| 134 | + /** |
| 135 | + * Returns a fresh GMT {@link Calendar} for a single JDBC get/set timestamp call. Calendar is |
| 136 | + * mutable and JDBC drivers may mutate the instance passed to them, so a new one is used per call |
| 137 | + * rather than sharing a single instance across concurrent DAO operations. |
| 138 | + */ |
| 139 | + protected static Calendar gmtCalendar() { |
| 140 | + return Calendar.getInstance(s_gmtTimeZone); |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Returns the SQL type ({@link Types}) matching the temporal flag of the given attribute, so a |
| 145 | + * null date/time/timestamp column is bound with the correct type instead of always TIMESTAMP. |
| 146 | + */ |
| 147 | + protected static int temporalSqlType(Attribute attr) { |
| 148 | + if (attr.is(Attribute.Flag.Date)) { |
| 149 | + return Types.DATE; |
| 150 | + } else if (attr.is(Attribute.Flag.Time)) { |
| 151 | + return Types.TIME; |
| 152 | + } |
| 153 | + return Types.TIMESTAMP; |
| 154 | + } |
| 155 | + |
132 | 156 | protected final static Map<Class<?>, GenericDao<?, ? extends Serializable>> s_daoMaps = new ConcurrentHashMap<Class<?>, GenericDao<?, ? extends Serializable>>(71); |
133 | 157 | private final ConversionSupport _conversionSupport; |
134 | 158 |
|
@@ -598,20 +622,16 @@ protected void setField(Object entity, Field field, ResultSet rs, int index) thr |
598 | 622 | field.set(entity, rs.getInt(index)); |
599 | 623 | } |
600 | 624 | } else if (type == Date.class) { |
601 | | - final Object data = rs.getDate(index); |
602 | | - if (data == null) { |
603 | | - field.set(entity, null); |
604 | | - return; |
605 | | - } |
606 | | - field.set(entity, DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index))); |
| 625 | + final Timestamp ts = rs.getTimestamp(index, gmtCalendar()); |
| 626 | + field.set(entity, ts == null ? null : new Date(ts.getTime())); |
607 | 627 | } else if (type == Calendar.class) { |
608 | | - final Object data = rs.getDate(index); |
| 628 | + final Timestamp data = rs.getTimestamp(index, gmtCalendar()); |
609 | 629 | if (data == null) { |
610 | 630 | field.set(entity, null); |
611 | 631 | return; |
612 | 632 | } |
613 | | - final Calendar cal = Calendar.getInstance(); |
614 | | - cal.setTime(DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index))); |
| 633 | + final Calendar cal = Calendar.getInstance(s_gmtTimeZone); |
| 634 | + cal.setTime(data); |
615 | 635 | field.set(entity, cal); |
616 | 636 | } else if (type == boolean.class) { |
617 | 637 | field.setBoolean(entity, rs.getBoolean(index)); |
@@ -732,11 +752,11 @@ protected static <M> M getObject(Class<M> type, ResultSet rs, int index) throws |
732 | 752 | return (M) (Long) rs.getLong(index); |
733 | 753 | } |
734 | 754 | } else if (type == Date.class) { |
735 | | - final Object data = rs.getDate(index); |
736 | | - if (data == null) { |
| 755 | + final Timestamp ts = rs.getTimestamp(index, gmtCalendar()); |
| 756 | + if (ts == null) { |
737 | 757 | return null; |
738 | 758 | } else { |
739 | | - return (M)DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index)); |
| 759 | + return (M) new Date(ts.getTime()); |
740 | 760 | } |
741 | 761 | } else if (type == short.class) { |
742 | 762 | return (M) (Short) rs.getShort(index); |
@@ -779,12 +799,12 @@ protected static <M> M getObject(Class<M> type, ResultSet rs, int index) throws |
779 | 799 | return (M) (Byte) rs.getByte(index); |
780 | 800 | } |
781 | 801 | } else if (type == Calendar.class) { |
782 | | - final Object data = rs.getDate(index); |
| 802 | + final Timestamp data = rs.getTimestamp(index, gmtCalendar()); |
783 | 803 | if (data == null) { |
784 | 804 | return null; |
785 | 805 | } else { |
786 | | - final Calendar cal = Calendar.getInstance(); |
787 | | - cal.setTime(DateUtil.parseDateString(s_gmtTimeZone, rs.getString(index))); |
| 806 | + final Calendar cal = Calendar.getInstance(s_gmtTimeZone); |
| 807 | + cal.setTime(data); |
788 | 808 | return (M)cal; |
789 | 809 | } |
790 | 810 | } else if (type == byte[].class) { |
@@ -1696,7 +1716,12 @@ protected void insertElementCollection(T entity, Attribute idAttribute, ID id, M |
1696 | 1716 | while (en.hasMoreElements()) { |
1697 | 1717 | pstmt = txn.prepareAutoCloseStatement(ec.insertSql); |
1698 | 1718 | if (ec.targetClass == Date.class) { |
1699 | | - pstmt.setString(1, DateUtil.getDateDisplayString(s_gmtTimeZone, (Date)en.nextElement())); |
| 1719 | + Date d = (Date) en.nextElement(); |
| 1720 | + if (d == null) { |
| 1721 | + pstmt.setNull(1, Types.TIMESTAMP); |
| 1722 | + } else { |
| 1723 | + pstmt.setTimestamp(1, new Timestamp(d.getTime()), gmtCalendar()); |
| 1724 | + } |
1700 | 1725 | } else { |
1701 | 1726 | pstmt.setObject(1, en.nextElement()); |
1702 | 1727 | } |
@@ -1800,28 +1825,28 @@ protected void prepareAttribute(final int j, final PreparedStatement pstmt, fina |
1800 | 1825 | } else if (attr.field.getType() == Date.class) { |
1801 | 1826 | final Date date = (Date)value; |
1802 | 1827 | if (date == null || date.equals(DATE_TO_NULL)) { |
1803 | | - pstmt.setObject(j, null); |
| 1828 | + pstmt.setNull(j, temporalSqlType(attr)); |
1804 | 1829 | return; |
1805 | 1830 | } |
1806 | 1831 | if (attr.is(Attribute.Flag.Date)) { |
1807 | | - pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, date)); |
| 1832 | + pstmt.setDate(j, new java.sql.Date(date.getTime()), gmtCalendar()); |
1808 | 1833 | } else if (attr.is(Attribute.Flag.TimeStamp)) { |
1809 | | - pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, date)); |
| 1834 | + pstmt.setTimestamp(j, new Timestamp(date.getTime()), gmtCalendar()); |
1810 | 1835 | } else if (attr.is(Attribute.Flag.Time)) { |
1811 | | - pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, date)); |
| 1836 | + pstmt.setTime(j, new java.sql.Time(date.getTime()), gmtCalendar()); |
1812 | 1837 | } |
1813 | 1838 | } else if (attr.field.getType() == Calendar.class) { |
1814 | 1839 | final Calendar cal = (Calendar)value; |
1815 | 1840 | if (cal == null) { |
1816 | | - pstmt.setObject(j, null); |
| 1841 | + pstmt.setNull(j, temporalSqlType(attr)); |
1817 | 1842 | return; |
1818 | 1843 | } |
1819 | 1844 | if (attr.is(Attribute.Flag.Date)) { |
1820 | | - pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, cal.getTime())); |
| 1845 | + pstmt.setDate(j, new java.sql.Date(cal.getTimeInMillis()), gmtCalendar()); |
1821 | 1846 | } else if (attr.is(Attribute.Flag.TimeStamp)) { |
1822 | | - pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, cal.getTime())); |
| 1847 | + pstmt.setTimestamp(j, new Timestamp(cal.getTimeInMillis()), gmtCalendar()); |
1823 | 1848 | } else if (attr.is(Attribute.Flag.Time)) { |
1824 | | - pstmt.setString(j, DateUtil.getDateDisplayString(s_gmtTimeZone, cal.getTime())); |
| 1849 | + pstmt.setTime(j, new Time(cal.getTimeInMillis()), gmtCalendar()); |
1825 | 1850 | } |
1826 | 1851 | } else if (attr.field.getType().isEnum()) { |
1827 | 1852 | final Enumerated enumerated = attr.field.getAnnotation(Enumerated.class); |
@@ -1955,7 +1980,8 @@ protected void loadCollection(T entity, Attribute attr) { |
1955 | 1980 | } |
1956 | 1981 | } else if (ec.targetClass == Date.class) { |
1957 | 1982 | while (rs.next()) { |
1958 | | - lst.add(DateUtil.parseDateString(s_gmtTimeZone, rs.getString(1))); |
| 1983 | + final Timestamp ts = rs.getTimestamp(1, gmtCalendar()); |
| 1984 | + lst.add(ts == null ? null : new Date(ts.getTime())); |
1959 | 1985 | } |
1960 | 1986 | } else if (ec.targetClass == Boolean.class) { |
1961 | 1987 | while (rs.next()) { |
|
0 commit comments