Skip to content

Commit

Permalink
Merge pull request #4034 from katzyn/type
Browse files Browse the repository at this point in the history
Fix determination of UNNEST data types for array constructors with casted parameters
  • Loading branch information
katzyn committed Mar 26, 2024
2 parents e69ff62 + 2a08820 commit 23bf50d
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 6 deletions.
5 changes: 5 additions & 0 deletions h2/src/docsrc/html/changelog.html
Expand Up @@ -21,6 +21,11 @@ <h1>Change Log</h1>

<h2>Next Version (unreleased)</h2>
<ul>
<li>Issue #4033: Wrong array produced when using ARRAY_AGG() on UNNEST(ARRAY[CAST(? AS INT)]) expression
in a PreparedStatement
</li>
<li>Issue #3909: Maintenance taking too much resources since 2.2.222
</li>
<li>Issue #4010: org.h2.jdbc.JdbcConnection.getTypeMap() returns null
</li>
<li>PR #4007: Update pom.xml related to CVE-2024-1597
Expand Down
8 changes: 2 additions & 6 deletions h2/src/main/org/h2/command/Parser.java
Expand Up @@ -4414,12 +4414,8 @@ private ArrayTableFunction readUnnestFunction() {
do {
Expression expr = readExpression();
TypeInfo columnType = TypeInfo.TYPE_NULL;
boolean constant = expr.isConstant();
if (constant || expr instanceof CastSpecification) {
if (constant) {
expr = expr.optimize(session);
}
TypeInfo exprType = expr.getType();
TypeInfo exprType = expr.getTypeIfStaticallyKnown(session);
if (exprType != null) {
switch (exprType.getValueType()) {
case Value.JSON:
columnType = TypeInfo.TYPE_JSON;
Expand Down
11 changes: 11 additions & 0 deletions h2/src/main/org/h2/expression/Expression.java
Expand Up @@ -284,6 +284,17 @@ public Expression getNotIfPossible(@SuppressWarnings("unused") SessionLocal sess
return null;
}

/**
* Returns data type of this expression if it is statically known.
*
* @param session
* the session
* @return data type or {@code null}
*/
public TypeInfo getTypeIfStaticallyKnown(SessionLocal session) {
return null;
}

/**
* Check if this expression will always return the same value.
*
Expand Down
15 changes: 15 additions & 0 deletions h2/src/main/org/h2/expression/ExpressionList.java
Expand Up @@ -114,6 +114,21 @@ public int getCost() {
return cost;
}

@Override
public TypeInfo getTypeIfStaticallyKnown(SessionLocal session) {
int count = list.length;
TypeInfo[] types = new TypeInfo[count];
for (int i = 0; i < count; i++) {
TypeInfo t = list[i].getTypeIfStaticallyKnown(session);
if (t == null) {
return null;
}
types[i] = t;
}
return isArray ? TypeInfo.getTypeInfo(Value.ARRAY, list.length, 0, TypeInfo.getHigherType(types))
: TypeInfo.getTypeInfo(Value.ROW, 0, 0, new ExtTypeInfoRow(types));
}

@Override
public boolean isConstant() {
for (Expression e : list) {
Expand Down
10 changes: 10 additions & 0 deletions h2/src/main/org/h2/expression/Subquery.java
Expand Up @@ -161,6 +161,16 @@ public int getCost() {
return query.getCostAsExpression();
}

@Override
public TypeInfo getTypeIfStaticallyKnown(SessionLocal session) {
if (query.isConstantQuery()) {
query.prepare();
setType();
return expression.getType();
}
return null;
}

@Override
public boolean isConstant() {
return query.isConstantQuery();
Expand Down
5 changes: 5 additions & 0 deletions h2/src/main/org/h2/expression/ValueExpression.java
Expand Up @@ -114,6 +114,11 @@ public Expression getNotIfPossible(SessionLocal session) {
return getBoolean(!value.getBoolean());
}

@Override
public TypeInfo getTypeIfStaticallyKnown(SessionLocal session) {
return value.getType();
}

@Override
public boolean isConstant() {
return true;
Expand Down
5 changes: 5 additions & 0 deletions h2/src/main/org/h2/expression/function/CastSpecification.java
Expand Up @@ -90,6 +90,11 @@ public Expression optimize(SessionLocal session) {
return this;
}

@Override
public TypeInfo getTypeIfStaticallyKnown(SessionLocal session) {
return type;
}

@Override
public boolean isConstant() {
return left instanceof ValueExpression && (right == null || right.isConstant())
Expand Down
7 changes: 7 additions & 0 deletions h2/src/test/org/h2/test/jdbc/TestPreparedStatement.java
Expand Up @@ -1810,6 +1810,13 @@ private void testUnnestWithArrayParameter(Connection conn) throws SQLException {
}
assertFalse(rs.next());
}
prep = conn.prepareStatement(
"SELECT ARRAY_AGG(V) FROM UNNEST(ARRAY[CAST(? AS INTEGER), CAST(? AS INTEGER)]) T(V)");
prep.setInt(1, 1);
prep.setInt(2, 2);
ResultSet rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(new Integer[] { 1, 2 }, rs.getObject(1, Integer[].class));
}

}

0 comments on commit 23bf50d

Please sign in to comment.