Skip to content

Commit

Permalink
Merge pull request #3990 from katzyn/cte
Browse files Browse the repository at this point in the history
Fix parameters in CTEs
  • Loading branch information
katzyn committed Jan 29, 2024
2 parents 2a29f47 + 41fb863 commit e057529
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 14 deletions.
4 changes: 4 additions & 0 deletions h2/src/docsrc/html/changelog.html
Expand Up @@ -21,6 +21,10 @@ <h1>Change Log</h1>

<h2>Next Version (unreleased)</h2>
<ul>
<li>Issue #3554: Regression in 2.1.214 when joining 2 recursive CTE containing bind values
</li>
<li>PR #3989: Refactor CTE-related code and reduce recompilations
</li>
<li>Issue #3987: Allow empty &lt;with column list&gt;
</li>
<li>Issue #822: WITH clauses' column aliases are not maintained correctly when selecting from CTE from within a derived
Expand Down
14 changes: 13 additions & 1 deletion h2/src/main/org/h2/command/ParserBase.java
Expand Up @@ -217,7 +217,19 @@ public final void setLiteralsChecked(boolean literalsChecked) {
}

public final void setSuppliedParameters(ArrayList<Parameter> suppliedParameters) {
this.parameters = suppliedParameters;
int max = Parameter.getMaxIndex(suppliedParameters);
if (max > suppliedParameters.size()) {
ArrayList<Parameter> parameters = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
parameters.add(null);
}
for (Parameter p : suppliedParameters) {
parameters.set(p.getIndex(), p);
}
this.parameters = parameters;
} else {
this.parameters = suppliedParameters;
}
}

/**
Expand Down
22 changes: 22 additions & 0 deletions h2/src/main/org/h2/expression/Parameter.java
Expand Up @@ -5,6 +5,8 @@
*/
package org.h2.expression;

import java.util.ArrayList;

import org.h2.api.ErrorCode;
import org.h2.engine.SessionLocal;
import org.h2.expression.condition.Comparison;
Expand All @@ -20,6 +22,26 @@
*/
public final class Parameter extends Operation0 implements ParameterInterface {

/**
* Returns the maximum 1-based index.
*
* @param parameters
* parameters
* @return the maximum 1-based index, or {@code -1}
*/
public static int getMaxIndex(ArrayList<Parameter> parameters) {
int result = 0;
for (Parameter p : parameters) {
if (p != null) {
int index = p.getIndex() + 1;
if (index > result) {
result = index;
}
}
}
return result;
}

private Value value;
private Column column;
private final int index;
Expand Down
16 changes: 3 additions & 13 deletions h2/src/main/org/h2/table/QueryExpressionTable.java
Expand Up @@ -105,16 +105,6 @@ public static List<Column> createQueryColumnTemplateList(String[] cols, Query th
return columnTemplateList;
}

static int getMaxParameterIndex(ArrayList<Parameter> parameters) {
int result = -1;
for (Parameter p : parameters) {
if (p != null) {
result = Math.max(result, p.getIndex());
}
}
return result;
}

Query viewQuery;

ArrayList<Table> tables;
Expand Down Expand Up @@ -249,11 +239,11 @@ public final long getRowCountApproximation(SessionLocal session) {
*/
public final int getParameterOffset(ArrayList<Parameter> additionalParameters) {
Query topQuery = getTopQuery();
int result = topQuery == null ? -1 : getMaxParameterIndex(topQuery.getParameters());
int result = topQuery == null ? 0 : Parameter.getMaxIndex(topQuery.getParameters());
if (additionalParameters != null) {
result = Math.max(result, getMaxParameterIndex(additionalParameters));
result = Math.max(result, Parameter.getMaxIndex(additionalParameters));
}
return result + 1;
return result;
}

@Override
Expand Down
39 changes: 39 additions & 0 deletions h2/src/test/org/h2/test/db/TestRecursiveQueries.java
Expand Up @@ -32,6 +32,7 @@ public void test() throws Exception {
testWrongLinkLargeResult();
testSimpleUnionAll();
testSimpleUnion();
testParameters();
}

private void testWrongLinkLargeResult() throws Exception {
Expand Down Expand Up @@ -180,4 +181,42 @@ private void testSimpleUnion() throws Exception {
deleteDb("recursiveQueries");
}

private void testParameters() throws Exception {
deleteDb("recursiveQueries");
Connection conn = getConnection("recursiveQueries");
PreparedStatement prep = conn.prepareStatement("WITH RECURSIVE T1(F1, F2) AS (\n" //
+ " SELECT CAST(? AS INT), CAST(? AS VARCHAR(15))\n" //
+ " UNION ALL\n" //
+ " SELECT (T1.F1 + CAST(? AS INT)), CAST((CAST(? AS VARCHAR) || T1.F2) AS VARCHAR(15))\n" //
+ " FROM T1 WHERE T1.F1 < 10\n" //
+ " ),\n" //
+ "T2(G1, G2) AS (\n" //
+ " SELECT CAST(? AS INT), CAST(? AS VARCHAR(15))\n" //
+ " UNION ALL\n" //
+ " SELECT (T2.G1 + 1), CAST(('b' || T2.G2) AS VARCHAR(15))\n" //
+ " FROM T2 WHERE T2.G1 < 10\n" //
+ " )\n" //
+ "SELECT T1.F1, T1.F2, T2.G1, T2.G2 FROM T1 JOIN T2 ON T1.F1 = T2.G1");
prep.setInt(1, 1);
prep.setString(2, "a");
prep.setInt(3, 1);
prep.setString(4, "a");
prep.setInt(5, 1);
prep.setString(6, "b");
ResultSet rs = prep.executeQuery();
StringBuilder a = new StringBuilder(10), b = new StringBuilder(10);
for (int i = 1; i <= 10; i++) {
a.append('a');
b.append('b');
assertTrue(rs.next());
assertEquals(i, rs.getInt(1));
assertEquals(a.toString(), rs.getString(2));
assertEquals(i, rs.getInt(3));
assertEquals(b.toString(), rs.getString(4));
}
assertFalse(rs.next());
conn.close();
deleteDb("recursiveQueries");
}

}

0 comments on commit e057529

Please sign in to comment.