Skip to content

Commit b848a3f

Browse files
authored
Merge pull request #2709 from zspitzer/LDEV-5920
LDEV-5920 more query casters and cache calendar
2 parents f7d3550 + 72b41c3 commit b848a3f

File tree

9 files changed

+123
-3
lines changed

9 files changed

+123
-3
lines changed

core/src/main/java/lucee/runtime/query/caster/Cast.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.IOException;
2222
import java.sql.ResultSet;
2323
import java.sql.SQLException;
24+
import java.util.Calendar;
2425
import java.util.TimeZone;
2526

2627
public interface Cast {
@@ -48,7 +49,28 @@ public interface Cast {
4849
public static final Cast ORACLE_TIMESTAMPLTZ = new OracleTimestampLTZ();
4950
public static final Cast ORACLE_TIMESTAMPNS = new OracleTimestampNS();
5051

52+
// Common type-specific casters for better performance
53+
public static final Cast VARCHAR = new VarcharCast();
54+
public static final Cast DOUBLE = new DoubleCast();
55+
public static final Cast DECIMAL = new DecimalCast();
56+
5157
// public Object toCFType(TimeZone tz,int type,ResultSet rst, int columnIndex) throws SQLException,
5258
// IOException;
5359
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLException, IOException;
60+
61+
/**
62+
* Optimized version that accepts a pre-created Calendar instance to avoid repeated ThreadLocal
63+
* lookups and Calendar initialization overhead when processing multiple rows in a result set.
64+
*
65+
* @param tz the timezone
66+
* @param rst the result set
67+
* @param columnIndex the column index (1-based)
68+
* @param cal a Calendar instance to reuse (can be null if not needed by this cast type)
69+
* @return the CF type value
70+
* @throws SQLException if database access error occurs
71+
* @throws IOException if IO error occurs
72+
*/
73+
default Object toCFType(TimeZone tz, ResultSet rst, int columnIndex, Calendar cal) throws SQLException, IOException {
74+
return toCFType( tz, rst, columnIndex );
75+
}
5476
}

core/src/main/java/lucee/runtime/query/caster/DateCast.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.sql.Date;
2323
import java.sql.ResultSet;
2424
import java.sql.SQLException;
25+
import java.util.Calendar;
2526
import java.util.TimeZone;
2627

2728
import lucee.commons.date.JREDateTimeUtil;
@@ -43,4 +44,14 @@ public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLEx
4344

4445
}
4546

47+
@Override
48+
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex, Calendar cal) throws SQLException, IOException {
49+
if (!useTimeZone || cal == null) {
50+
return toCFType( tz, rst, columnIndex );
51+
}
52+
Date d = rst.getDate( columnIndex, cal );
53+
if (d == null) return null;
54+
return new DateTimeImpl( d.getTime() );
55+
}
56+
4657
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package lucee.runtime.query.caster;
2+
3+
import java.io.IOException;
4+
import java.sql.ResultSet;
5+
import java.sql.SQLException;
6+
import java.util.TimeZone;
7+
8+
/**
9+
* Cast implementation for DECIMAL, NUMERIC types.
10+
* Calls ResultSet.getBigDecimal() directly instead of getObject() to avoid overhead.
11+
*/
12+
public final class DecimalCast implements Cast {
13+
14+
@Override
15+
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLException, IOException {
16+
return rst.getBigDecimal( columnIndex );
17+
}
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package lucee.runtime.query.caster;
2+
3+
import java.io.IOException;
4+
import java.sql.ResultSet;
5+
import java.sql.SQLException;
6+
import java.util.TimeZone;
7+
8+
/**
9+
* Cast implementation for DOUBLE, FLOAT, REAL types.
10+
* Calls ResultSet.getDouble() directly instead of getObject() to avoid overhead.
11+
*/
12+
public final class DoubleCast implements Cast {
13+
14+
@Override
15+
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLException, IOException {
16+
double value = rst.getDouble( columnIndex );
17+
// ResultSet.getDouble() returns 0.0 for NULL values, need to check wasNull()
18+
return rst.wasNull() ? null : Double.valueOf( value );
19+
}
20+
}

core/src/main/java/lucee/runtime/query/caster/TimeCast.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.sql.ResultSet;
2323
import java.sql.SQLException;
2424
import java.sql.Time;
25+
import java.util.Calendar;
2526
import java.util.TimeZone;
2627

2728
import lucee.commons.date.JREDateTimeUtil;
@@ -44,4 +45,14 @@ public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLEx
4445

4546
}
4647

48+
@Override
49+
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex, Calendar cal) throws SQLException, IOException {
50+
if (!useTimeZone || cal == null) {
51+
return toCFType( tz, rst, columnIndex );
52+
}
53+
Time t = rst.getTime( columnIndex, cal );
54+
if (t == null) return null;
55+
return new DateTimeImpl( t.getTime() );
56+
}
57+
4758
}

core/src/main/java/lucee/runtime/query/caster/TimestampCast.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.sql.ResultSet;
2323
import java.sql.SQLException;
2424
import java.sql.Timestamp;
25+
import java.util.Calendar;
2526
import java.util.TimeZone;
2627

2728
import lucee.commons.date.JREDateTimeUtil;
@@ -41,4 +42,14 @@ public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLEx
4142
if (ts == null) return null;
4243
return new DateTimeImpl(ts.getTime());
4344
}
45+
46+
@Override
47+
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex, Calendar cal) throws SQLException, IOException {
48+
if (!useTimeZone || cal == null) {
49+
return toCFType( tz, rst, columnIndex );
50+
}
51+
Timestamp ts = rst.getTimestamp( columnIndex, cal );
52+
if (ts == null) return null;
53+
return new DateTimeImpl( ts.getTime() );
54+
}
4455
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package lucee.runtime.query.caster;
2+
3+
import java.io.IOException;
4+
import java.sql.ResultSet;
5+
import java.sql.SQLException;
6+
import java.util.TimeZone;
7+
8+
/**
9+
* Cast implementation for VARCHAR, CHAR, LONGVARCHAR and other string types.
10+
* Calls ResultSet.getString() directly instead of getObject() to avoid overhead.
11+
*/
12+
public final class VarcharCast implements Cast {
13+
14+
@Override
15+
public Object toCFType(TimeZone tz, ResultSet rst, int columnIndex) throws SQLException, IOException {
16+
return rst.getString( columnIndex );
17+
}
18+
}

core/src/main/java/lucee/runtime/type/QueryImpl.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import java.util.concurrent.ConcurrentHashMap;
5858
import java.util.concurrent.atomic.AtomicInteger;
5959

60+
import lucee.commons.date.JREDateTimeUtil;
6061
import lucee.commons.db.DBUtil;
6162
import lucee.commons.io.IOUtil;
6263
import lucee.commons.io.SystemUtil;
@@ -665,14 +666,16 @@ private static boolean fillResult(QueryImpl qry, QueryResult qr, Collection.Key
665666
}
666667
}
667668
}
669+
// Get Calendar once for reuse across all rows - avoids repeated ThreadLocal lookups
670+
Calendar cal = JREDateTimeUtil.getThreadCalendar( tz );
668671
if (index != -1) {
669672
Object o;
670673
while (result.next()) {
671674
if (maxrow > -1 && recordcount >= maxrow) {
672675
break;
673676
}
674677
for (int i = 0; i < usedColumns.length; i++) {
675-
o = casts[i].toCFType(tz, result, usedColumns[i] + 1);
678+
o = casts[i].toCFType( tz, result, usedColumns[i] + 1, cal );
676679
if (index == i) {
677680
qry.indexes.put(Caster.toKey(o), recordcount + 1);
678681
}
@@ -687,7 +690,7 @@ private static boolean fillResult(QueryImpl qry, QueryResult qr, Collection.Key
687690
break;
688691
}
689692
for (int i = 0; i < usedColumns.length; i++) {
690-
columns[i].add(casts[i].toCFType(tz, result, usedColumns[i] + 1));
693+
columns[i].add( casts[i].toCFType( tz, result, usedColumns[i] + 1, cal ) );
691694
}
692695
++recordcount;
693696
}
@@ -700,6 +703,8 @@ private static boolean fillResult(QueryImpl qry, QueryResult qr, Collection.Key
700703
QueryStruct qs = qa == null ? (QueryStruct) qr : null;
701704
Object k;
702705
boolean full = NullSupportHelper.full();
706+
// Get Calendar once for reuse across all rows - avoids repeated ThreadLocal lookups
707+
Calendar cal = JREDateTimeUtil.getThreadCalendar( tz );
703708
while (result.next()) {
704709
if (maxrow > -1 && recordcount >= maxrow) {
705710
break;
@@ -708,7 +713,7 @@ private static boolean fillResult(QueryImpl qry, QueryResult qr, Collection.Key
708713
Object val;
709714

710715
for (int i = 0; i < usedColumns.length; i++) {
711-
val = casts[i].toCFType(tz, result, usedColumns[i] + 1);
716+
val = casts[i].toCFType( tz, result, usedColumns[i] + 1, cal );
712717
if (val == null && !full) val = "";
713718
sct.set(columnNames[i], val);
714719
}

core/src/main/java/lucee/runtime/type/util/QueryUtil.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ else if (type == Types.DATE) {
9393
else if (type == Types.BIGINT) return Cast.BIGINT;
9494
else if (type == Types.SQLXML) return Cast.SQLXML;
9595

96+
else if (type == Types.VARCHAR || type == Types.CHAR || type == Types.LONGVARCHAR || type == Types.NVARCHAR || type == Types.NCHAR) return Cast.VARCHAR;
97+
else if (type == Types.DOUBLE) return Cast.DOUBLE;
98+
else if (type == Types.DECIMAL || type == Types.NUMERIC) return Cast.DECIMAL;
99+
96100
// ORACLE
97101
else if (isOracleType(type) && isOracle(result)) {
98102
if (type == CFTypes.ORACLE_OPAQUE) return Cast.ORACLE_OPAQUE;

0 commit comments

Comments
 (0)