Author: tfischer Date: Tue Oct 6 02:52:34 2015 New Revision: 1706947 URL: http://svn.apache.org/viewvc?rev=1706947&view=rev Log: TORQUE-290: - Subselects can now easily reference Columns in outer select - made PreparedStatementPart an interface - retain information about the structure of the select in the created query
Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java Tue Oct 6 02:52:34 2015 @@ -678,8 +678,8 @@ public class Criteria implements Seriali { assertNoComposite(); joins.add(new Join( - new PreparedStatementPart(leftTable), - new PreparedStatementPart(rightTable), + new PreparedStatementPartImpl(leftTable), + new PreparedStatementPartImpl(rightTable), joinCondition, joinType)); return this; Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java Tue Oct 6 02:52:34 2015 @@ -19,160 +19,28 @@ package org.apache.torque.criteria; * under the License. */ -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; /** * The rendered SQL for a part of a prepared statement, including replacements for ? placeholders. * * @version $Id$ */ -public class PreparedStatementPart implements Serializable +public interface PreparedStatementPart { - /** Version id for serializing. */ - private static final long serialVersionUID = 1L; - - /** - * The SQL for the part, not null. - */ - private final StringBuilder sql = new StringBuilder(); - - /** - * The replacements for the prepared statement, not null. - */ - private final List<Object> preparedStatementReplacements - = new ArrayList<Object>(); - - /** - * Default constructor, creates an empty PreparedStatementPart. - */ - public PreparedStatementPart() - { - // empty - } - - /** - * Constructor, creates a pre-filled PreparedStatementPart. - * - * @param sql The sql to fill into the sql buffer initially, or null. - * @param preparedStatementReplacements the prepared statement replacements - * to start with, or null. - */ - public PreparedStatementPart( - final String sql, - final Object... preparedStatementReplacements) - { - if (!StringUtils.isEmpty(sql)) - { - this.sql.append(sql); - } - if (preparedStatementReplacements != null) - { - this.preparedStatementReplacements.addAll( - Arrays.asList(preparedStatementReplacements)); - } - } - - /** - * Returns the SQL of the part. - * - * @return the SQL as mutable StringBuilder, not null. - */ - public StringBuilder getSql() - { - return sql; - } - /** * Returns the SQL of the part as String. * * @return the SQL, not null. */ - public String getSqlAsString() - { - return sql.toString(); - } + public String getSqlAsString(); /** * Returns the list of prepared statement replacements. + * The implementation may or may not return a list which is modifiable + * and which may or may not, in case of modification, + * change the internal state of the surrounding PreparedStatementPart. * - * @return the modifiable list of prepared statement replacements, not null. - */ - public List<Object> getPreparedStatementReplacements() - { - return preparedStatementReplacements; - } - - /** - * Appends another PreparedStatementPart to this part. - * - * @param toAppend the part to append, not null. - * - * @return this PreparedStatementPart (with toAppend appended). + * @return the list of prepared statement replacements, not null. */ - public PreparedStatementPart append(final PreparedStatementPart toAppend) - { - sql.append(toAppend.sql); - preparedStatementReplacements.addAll( - toAppend.preparedStatementReplacements); - return this; - } - - /** - * Appends a SqlEnum to this part. - * - * @param toAppend the part to append, not null. - * - * @return this PreparedStatementPart (with toAppend appended). - */ - public PreparedStatementPart append(final SqlEnum toAppend) - { - sql.append(toAppend); - return this; - } - - @Override - public int hashCode() - { - HashCodeBuilder hashCodeBuilder = new HashCodeBuilder(); - hashCodeBuilder.append(sql); - hashCodeBuilder.append(preparedStatementReplacements); - return hashCodeBuilder.toHashCode(); - } - - @Override - public boolean equals(final Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - PreparedStatementPart other = (PreparedStatementPart) obj; - EqualsBuilder equalsBuilder = new EqualsBuilder(); - equalsBuilder.append(other.sql, this.sql); - equalsBuilder.append( - other.preparedStatementReplacements, - this.preparedStatementReplacements); - return equalsBuilder.isEquals(); - } - - @Override - public String toString() - { - return sql + ", preparedStatementReplacements=" - + preparedStatementReplacements; - } + public List<Object> getPreparedStatementReplacements(); } Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java?rev=1706947&view=auto ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java (added) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java Tue Oct 6 02:52:34 2015 @@ -0,0 +1,195 @@ +package org.apache.torque.criteria; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +/** + * Modifiable implementation of the PreparedStatementPart interface. + * + * @version $Id: PreparedStatementPart.java 1701510 2015-09-06 18:45:05Z tfischer $ + */ +public class PreparedStatementPartImpl implements PreparedStatementPart, Serializable +{ + /** Version id for serializing. */ + private static final long serialVersionUID = 1L; + + /** + * The SQL for the part, not null. + */ + private final StringBuilder sql = new StringBuilder(); + + /** + * The replacements for the prepared statement, not null. + */ + private final List<Object> preparedStatementReplacements + = new ArrayList<Object>(); + + /** + * Default constructor, creates an empty PreparedStatementPart. + */ + public PreparedStatementPartImpl() + { + // empty + } + + /** + * Constructor, creates a pre-filled PreparedStatementPartImpl. + * + * @param sql The sql to fill into the sql buffer initially, or null. + * @param preparedStatementReplacements the prepared statement replacements + * to start with, or null. + */ + public PreparedStatementPartImpl( + final String sql, + final Object... preparedStatementReplacements) + { + if (!StringUtils.isEmpty(sql)) + { + this.sql.append(sql); + } + if (preparedStatementReplacements != null) + { + this.preparedStatementReplacements.addAll( + Arrays.asList(preparedStatementReplacements)); + } + } + + /** + * Copy-Constructor. + * + * @param toCopy the PreparedStatementPart to copy, not null. + */ + public PreparedStatementPartImpl(final PreparedStatementPart toCopy) + { + String sqlAsString = toCopy.getSqlAsString(); + if (!StringUtils.isEmpty(sqlAsString)) + { + this.sql.append(sqlAsString); + } + if (toCopy.getPreparedStatementReplacements() != null) + { + this.preparedStatementReplacements.addAll(toCopy.getPreparedStatementReplacements()); + } + } + /** + * Returns the SQL of the part. + * + * @return the SQL as mutable StringBuilder, not null. + */ + public StringBuilder getSql() + { + return sql; + } + + /** + * Returns the SQL of the part as String. + * + * @return the SQL, not null. + */ + public String getSqlAsString() + { + return sql.toString(); + } + + /** + * Returns the list of prepared statement replacements. + * + * @return the modifiable list of prepared statement replacements, not null. + */ + public List<Object> getPreparedStatementReplacements() + { + return preparedStatementReplacements; + } + + /** + * Appends another PreparedStatementPart to this part. + * + * @param toAppend the part to append, not null. + * + * @return this PreparedStatementPart (with toAppend appended). + */ + public PreparedStatementPartImpl append(final PreparedStatementPart toAppend) + { + sql.append(toAppend.getSqlAsString()); + preparedStatementReplacements.addAll( + toAppend.getPreparedStatementReplacements()); + return this; + } + + /** + * Appends a SqlEnum to this part. + * + * @param toAppend the part to append, not null. + * + * @return this PreparedStatementPart (with toAppend appended). + */ + public PreparedStatementPartImpl append(final SqlEnum toAppend) + { + sql.append(toAppend); + return this; + } + + @Override + public int hashCode() + { + HashCodeBuilder hashCodeBuilder = new HashCodeBuilder(); + hashCodeBuilder.append(sql); + hashCodeBuilder.append(preparedStatementReplacements); + return hashCodeBuilder.toHashCode(); + } + + @Override + public boolean equals(final Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + PreparedStatementPartImpl other = (PreparedStatementPartImpl) obj; + EqualsBuilder equalsBuilder = new EqualsBuilder(); + equalsBuilder.append(other.sql, this.sql); + equalsBuilder.append( + other.preparedStatementReplacements, + this.preparedStatementReplacements); + return equalsBuilder.isEquals(); + } + + @Override + public String toString() + { + return sql + ", preparedStatementReplacements=" + + preparedStatementReplacements; + } +} Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java Tue Oct 6 02:52:34 2015 @@ -30,6 +30,7 @@ import org.apache.torque.criteria.FromEl import org.apache.torque.criteria.Join; import org.apache.torque.criteria.JoinType; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.criteria.PreparedStatementPartImpl; import org.apache.torque.util.UniqueList; /** @@ -147,8 +148,8 @@ public final class JoinBuilder criteria); } - addSchema(leftExpression, criteria); - addSchema(rightExpression, criteria); + leftExpression = addSchema(leftExpression, criteria); + rightExpression = addSchema(rightExpression, criteria); // check whether the order of the join must be "reversed" // This if the case if the fromClause already contains @@ -163,7 +164,7 @@ public final class JoinBuilder leftExpression)) { FromElement fromElement = new FromElement( - leftExpression.getSql().toString(), + leftExpression.getSqlAsString(), null, null, leftExpression.getPreparedStatementReplacements()); @@ -171,9 +172,9 @@ public final class JoinBuilder } FromElement fromElement = new FromElement( - rightExpression.getSql().toString(), + rightExpression.getSqlAsString(), joinType, - buildJoinCondition(joinCondition, criteria)); + buildJoinCondition(joinCondition, criteria, query)); fromElement.getPreparedStatementReplacements().addAll(rightExpression.getPreparedStatementReplacements()); queryFromClause.add(fromElement); } @@ -188,8 +189,8 @@ public final class JoinBuilder throw new TorqueException( "Unable to create a" + joinType + "because both expressions " - + leftExpression.getSql() - + " and " + rightExpression.getSql() + + leftExpression.getSqlAsString() + + " and " + rightExpression.getSqlAsString() + " are already in use. " + "Try to create an(other) alias."); } @@ -197,9 +198,9 @@ public final class JoinBuilder // rightTableName must not be added // because it is already present FromElement fromElement = new FromElement( - leftExpression.getSql().toString(), + leftExpression.getSqlAsString(), reverseJoinType(joinType), - buildJoinCondition(joinCondition, criteria)); + buildJoinCondition(joinCondition, criteria, query)); queryFromClause.add(fromElement); } } @@ -240,6 +241,7 @@ public final class JoinBuilder * * @param joinCondition the join condition. * @param criteria the enclosing criteria. + * @param query the query which is currently built * * @return A join expression, e.g. table_a.column_a=table_b.column_b. * @@ -247,11 +249,12 @@ public final class JoinBuilder */ private static PreparedStatementPart buildJoinCondition( final Criterion joinCondition, - final Criteria criteria) + final Criteria criteria, + final Query query) throws TorqueException { - PreparedStatementPart joinPart = new PreparedStatementPart(); - appendJoinCondition(joinCondition, criteria, joinPart); + PreparedStatementPartImpl joinPart = new PreparedStatementPartImpl(); + appendJoinCondition(joinCondition, criteria, joinPart, query); return joinPart; } @@ -261,6 +264,7 @@ public final class JoinBuilder * @param joinCondition the join condition. * @param criteria the enclosing criteria. * @param joinPart the join part to append to. + * @param query the query which is currently built * * @return A join expression, e.g. table_a.column_a=table_b.column_b. * @@ -269,7 +273,8 @@ public final class JoinBuilder private static void appendJoinCondition( final Criterion joinCondition, final Criteria criteria, - final PreparedStatementPart joinPart) + final PreparedStatementPartImpl joinPart, + final Query query) throws TorqueException { if (joinCondition.isComposite()) @@ -285,14 +290,15 @@ public final class JoinBuilder appendJoinCondition( part, criteria, - joinPart); + joinPart, + query); firstPart = false; } joinPart.getSql().append(')'); return; } PreparedStatementPart joinConditionStatementPart - = SqlBuilder.processCriterion(joinCondition, criteria); + = SqlBuilder.processCriterion(joinCondition, criteria, query); joinPart.append(joinConditionStatementPart); } @@ -302,28 +308,31 @@ public final class JoinBuilder * @param tableNamePart the table name to add the schema name to, not null. * @param criteria the criteria from which the tableNamePart was created, not null. */ - private static void addSchema(final PreparedStatementPart tableNamePart, final Criteria criteria) + private static PreparedStatementPart addSchema(final PreparedStatementPart tableNamePart, final Criteria criteria) throws TorqueException { - String tableName = tableNamePart.getSql().toString(); + String tableName = tableNamePart.getSqlAsString(); if (tableName.indexOf('.') != -1 // table name is already qualified || tableName.indexOf(' ') != -1 // table name is no simple table name || tableName.indexOf('(') != -1) // table name is no simple table name { - return; + return tableNamePart; } Object resolvedAlias = criteria.getAliases().get(tableName); if (resolvedAlias != null) { - return; + return tableNamePart; } final String dbName = criteria.getDbName(); final Database database = Torque.getDatabase(dbName); String resolvedSchemaName = database.getSchema(); - if (resolvedSchemaName != null) + if (resolvedSchemaName == null) { - tableNamePart.getSql().insert(0, '.'); - tableNamePart.getSql().insert(0, resolvedSchemaName); + return tableNamePart; } + PreparedStatementPartImpl result = new PreparedStatementPartImpl(tableNamePart); + result.getSql().insert(0, '.'); + result.getSql().insert(0, resolvedSchemaName); + return result; } } Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java Tue Oct 6 02:52:34 2015 @@ -36,6 +36,7 @@ import org.apache.torque.criteria.Criter import org.apache.torque.criteria.Criterion; import org.apache.torque.criteria.FromElement; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.criteria.PreparedStatementPartImpl; import org.apache.torque.criteria.SqlEnum; import org.apache.torque.map.ColumnMap; import org.apache.torque.map.DatabaseMap; @@ -310,16 +311,17 @@ public final class SqlBuilder query); PreparedStatementPart whereClausePartOutput - = processCriterion(criterion, criteria); + = processCriterion(criterion, criteria, query); - where.append(whereClausePartOutput.getSql()); + where.append(whereClausePartOutput.getSqlAsString()); query.getWhereClausePreparedStatementReplacements().addAll( whereClausePartOutput.getPreparedStatementReplacements()); } static PreparedStatementPart processCriterion( final Criterion criterion, - final Criteria criteria) + final Criteria criteria, + final Query query) throws TorqueException { final String dbName = criteria.getDbName(); @@ -344,6 +346,7 @@ public final class SqlBuilder whereClausePartOutput = builder.buildPs( whereClausePartInput, ignoreCase, + query, adapter); break; } @@ -618,7 +621,7 @@ public final class SqlBuilder if (!(toAddToFromClause instanceof Column)) { // toAddToFromClause is a literal Value - return new PreparedStatementPart("?", toAddToFromClause); + return new PreparedStatementPartImpl("?", toAddToFromClause); } Column column = (Column) toAddToFromClause; Column resolvedColumn @@ -632,7 +635,7 @@ public final class SqlBuilder { // If the tables have an alias, add an "<xxx> <yyy> statement" // <xxx> AS <yyy> causes problems on oracle - PreparedStatementPart result = new PreparedStatementPart(); + PreparedStatementPartImpl result = new PreparedStatementPartImpl(); result.getSql() .append(fullTableName) .append(" ") @@ -647,7 +650,7 @@ public final class SqlBuilder { Criteria subquery = (Criteria) resolvedAlias; Query renderedSubquery = SqlBuilder.buildQuery(subquery); - PreparedStatementPart result = new PreparedStatementPart(); + PreparedStatementPartImpl result = new PreparedStatementPartImpl(); result.getSql().append("(") .append(renderedSubquery.toString()) .append(") ") @@ -665,7 +668,7 @@ public final class SqlBuilder } } - return new PreparedStatementPart(fullTableName); + return new PreparedStatementPartImpl(fullTableName); } /** @@ -899,11 +902,11 @@ public final class SqlBuilder final UniqueList<FromElement> fromClause, final PreparedStatementPart fromExpression) { - if (fromExpression == null || fromExpression.getSql().length() == 0) + if (fromExpression == null || fromExpression.getSqlAsString().length() == 0) { return false; } - String fromExpressionSql = fromExpression.getSql().toString(); + String fromExpressionSql = fromExpression.getSqlAsString(); for (FromElement fromElement : fromClause) { if (fromExpressionSql.equals(fromElement.getFromExpression())) @@ -957,7 +960,7 @@ public final class SqlBuilder fromClauseExpression)) { FromElement fromElement = new FromElement( - fromClauseExpression.getSql().toString(), + fromClauseExpression.getSqlAsString(), null, null, fromClauseExpression.getPreparedStatementReplacements()); Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java Tue Oct 6 02:52:34 2015 @@ -24,10 +24,10 @@ import org.apache.torque.TorqueException import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.Criteria; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.criteria.PreparedStatementPartImpl; import org.apache.torque.criteria.SqlEnum; import org.apache.torque.om.ObjectKey; import org.apache.torque.sql.Query; -import org.apache.torque.sql.SqlBuilder; /** * Builds a PreparedStatementPart from a column or single value. @@ -43,6 +43,7 @@ public class ObjectOrColumnPsPartBuilder * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * @@ -53,10 +54,11 @@ public class ObjectOrColumnPsPartBuilder public PreparedStatementPart buildPs( Object toBuildFrom, final boolean ignoreCase, + final Query query, final Adapter adapter) throws TorqueException { - PreparedStatementPart result = new PreparedStatementPart(); + PreparedStatementPartImpl result = new PreparedStatementPartImpl(); // check column if (toBuildFrom instanceof Column) { @@ -75,11 +77,7 @@ public class ObjectOrColumnPsPartBuilder // check subselect if (toBuildFrom instanceof Criteria) { - Query subquery = SqlBuilder.buildQuery((Criteria) toBuildFrom); - result.getPreparedStatementReplacements().addAll( - subquery.getPreparedStatementReplacements()); - result.getSql().append("(").append(subquery.toString()).append(")"); - return result; + return new PreparedStatementPartForSubselect((Criteria) toBuildFrom, query); } // plain object Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java Tue Oct 6 02:52:34 2015 @@ -22,6 +22,7 @@ package org.apache.torque.sql.objectbuil import org.apache.torque.TorqueException; import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.sql.Query; /** * Builds a PreparedStatementPart from a single object @@ -38,6 +39,7 @@ public interface ObjectPsPartBuilder * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * @@ -46,8 +48,9 @@ public interface ObjectPsPartBuilder * @throws TorqueException when rendering fails. */ PreparedStatementPart buildPs( - Object toBuildFrom, - boolean ignoreCase, - Adapter adapter) + final Object toBuildFrom, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException; } Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java?rev=1706947&view=auto ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java (added) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java Tue Oct 6 02:52:34 2015 @@ -0,0 +1,121 @@ +package org.apache.torque.sql.objectbuilder; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.List; + +import org.apache.torque.TorqueException; +import org.apache.torque.TorqueRuntimeException; +import org.apache.torque.criteria.Criteria; +import org.apache.torque.criteria.FromElement; +import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.criteria.PreparedStatementPartImpl; +import org.apache.torque.sql.Query; +import org.apache.torque.sql.SqlBuilder; +import org.apache.torque.util.UniqueList; + +/** + * A PreparedStatementPart which encapsulates a subselect. + * The SQL and Replacements are not calculated immediately, + * but wait for the outer clause to be completed, + * as tables in the from clause which reference tables in the outer select + * are removed, and this can only be done when the outer query is known. + * This only works if the methofs getSqlAsString() + * and getPreparedStatementReplacements() are called after the outer query + * is calculated. + * + * @version $Id: $ + */ +public class PreparedStatementPartForSubselect implements PreparedStatementPart +{ + /** + * The calculated PreparedStatementPart for the subselect, + * or null if it is not yet known. + */ + private PreparedStatementPartImpl wrapped; + + /** The criteria to build the subselect from. */ + private final Criteria toBuildFrom; + + /** The outer query in which this subselect is embedded. */ + private final Query outerQuery; + + /** + * Constructor. + * + * @param toBuildFrom The criteria to build the subselect from. + * @param outerQuery The outer query in which this subselect is embedded. + */ + public PreparedStatementPartForSubselect(final Criteria toBuildFrom, final Query outerQuery) + { + this.toBuildFrom = toBuildFrom; + this.outerQuery = outerQuery; + } + + private void calculate() + { + Query subquery; + try + { + subquery = SqlBuilder.buildQuery(toBuildFrom); + } + catch (TorqueException e) + { + throw new TorqueRuntimeException(e); + } + // assume that table names which are in the outer from clause are references to the outer from clause + // But only do this if any tables are remaining + UniqueList<FromElement> remainingTableNames = new UniqueList<FromElement>(subquery.getFromClause()); + remainingTableNames.removeAll(outerQuery.getFromClause()); + if (remainingTableNames.size() > 0) + { + subquery.getFromClause().removeAll(outerQuery.getFromClause()); + } + + PreparedStatementPartImpl result = new PreparedStatementPartImpl("(" + subquery.toString() + ")"); + result.getPreparedStatementReplacements().addAll( + subquery.getPreparedStatementReplacements()); + wrapped = result; + } + + /** + * {@inheritDoc} + */ + public String getSqlAsString() + { + if (wrapped == null) + { + calculate(); + } + return wrapped.getSqlAsString(); + } + + /** + * {@inheritDoc} + */ + public List<Object> getPreparedStatementReplacements() + { + if (wrapped == null) + { + calculate(); + } + return wrapped.getPreparedStatementReplacements(); + } +} Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java?rev=1706947&view=auto ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java (added) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java Tue Oct 6 02:52:34 2015 @@ -0,0 +1,121 @@ +package org.apache.torque.sql.whereclausebuilder; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.torque.criteria.PreparedStatementPart; + +/** + * A PreparedStatementPart which consists of a list of other PreparedStatementParts. + * @version $Id: $ + */ +public class CombinedPreparedStatementPart implements PreparedStatementPart +{ + /** The list of PreparedStatementParts of which this PreparedStatementPart is made. */ + private final List<PreparedStatementPart> parts = new ArrayList<PreparedStatementPart>(); + + /** + * Constructor. + * Constructs an empty CombinedPreparedStatementPart. + */ + public CombinedPreparedStatementPart() + { + } + + /** + * Constructor. + * Creates a CombinedPreparedStatementPart which contains the passed PreparedStatementPart + * as first part. + * + * @param toAdd the PreparedStatementPart to add, not null. + */ + public CombinedPreparedStatementPart(final PreparedStatementPart toAdd) + { + append(toAdd); + } + + /** + * Adds a PreparedStatementPart to the list of contained PreparedStatementParts. + * + * @param toAdd the PreparedStatementPart to add, not null. + */ + public void append(final PreparedStatementPart toAdd) + { + if (toAdd == null) + { + throw new NullPointerException("toAdd must notbe null"); + } + parts.add(toAdd); + } + + /** + * Adds a PreparedStatementPart to the list of contained PreparedStatementParts, + * which contains only the given sql. + * + * @param sql the sql to add, not null. + */ + public void appendSql(final String sql) + { + parts.add(new NoReplacementsPreparedStatementPart(sql)); + } + + /** + * Adds a PreparedStatementPart to the list of contained PreparedStatementParts, + * which contains only the given sreplacementql. + * + * @param toAdd the replacement to add, not null. + */ + public void addPreparedStatementReplacement(final Object toAdd) + { + parts.add(new OnlyReplacementsPreparedStatementPart(toAdd)); + } + + /** + * {@inheritDoc} + */ + public String getSqlAsString() + { + StringBuilder result = new StringBuilder(); + for (PreparedStatementPart part : parts) + { + result.append(part.getSqlAsString()); + } + return result.toString(); + } + + /** + * Returns the list of prepared statement replacements. + * The returned list is unmodifiable. + * + * @return the list of prepared statement replacements, not null. + */ + public List<Object> getPreparedStatementReplacements() + { + List<Object> result = new ArrayList<Object>(); + for (PreparedStatementPart part : parts) + { + result.addAll(part.getPreparedStatementReplacements()); + } + return Collections.unmodifiableList(result); + } +} Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java Tue Oct 6 02:52:34 2015 @@ -23,6 +23,7 @@ import org.apache.torque.TorqueException import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; import org.apache.torque.criteria.SqlEnum; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -38,20 +39,24 @@ public class CurrentDateTimePsPartBuilde * {@inheritDoc} */ public PreparedStatementPart buildPs( - WhereClauseExpression whereClauseExpression, - boolean ignoreCase, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException { - PreparedStatementPart result - = getObjectOrColumnPsPartBuilder().buildPs( + CombinedPreparedStatementPart result + = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( whereClauseExpression.getLValue(), ignoreCase, - adapter); - result.getSql().append(whereClauseExpression.getOperator()); - result .append(getObjectOrColumnPsPartBuilder().buildPs( + query, + adapter)); + result.appendSql(whereClauseExpression.getOperator().toString()); + result.append(getObjectOrColumnPsPartBuilder().buildPs( whereClauseExpression.getRValue(), ignoreCase, + query, adapter)); return result; } @@ -60,8 +65,8 @@ public class CurrentDateTimePsPartBuilde * {@inheritDoc} */ public boolean isApplicable( - WhereClauseExpression whereClauseExpression, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final Adapter adapter) { if (whereClauseExpression.getOperator().equals( SqlEnum.CURRENT_DATE) Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java Tue Oct 6 02:52:34 2015 @@ -25,6 +25,7 @@ import java.lang.reflect.Method; import org.apache.torque.TorqueException; import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.sql.Query; import org.apache.torque.sql.SqlBuilder; import org.apache.torque.sql.WhereClauseExpression; @@ -43,12 +44,14 @@ public class EnumValueBuilder extends Ab * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. */ public PreparedStatementPart buildPs( final WhereClauseExpression whereClausePart, final boolean ignoreCase, + final Query query, final Adapter adapter) throws TorqueException { @@ -67,6 +70,7 @@ public class EnumValueBuilder extends Ab return builder.buildPs( whereClausePart, ignoreCase, + query, adapter); } } Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java Tue Oct 6 02:52:34 2015 @@ -29,6 +29,7 @@ import org.apache.torque.criteria.Criter import org.apache.torque.criteria.Criterion; import org.apache.torque.criteria.PreparedStatementPart; import org.apache.torque.criteria.SqlEnum; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -49,16 +50,18 @@ public class InBuilder extends AbstractW * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. */ public PreparedStatementPart buildPs( - WhereClauseExpression whereClausePart, - boolean ignoreCase, - Adapter adapter) + final WhereClauseExpression whereClausePart, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException { - PreparedStatementPart result = new PreparedStatementPart(); + CombinedPreparedStatementPart result = new CombinedPreparedStatementPart(); boolean ignoreCaseApplied = false; List<String> inClause = new ArrayList<String>(); @@ -72,7 +75,7 @@ public class InBuilder extends AbstractW nullContained = true; continue; } - result.getPreparedStatementReplacements().add(listValue); + result.addPreparedStatementReplacement(listValue); if (ignoreCase && listValue instanceof String) { inClause.add(adapter.ignoreCase("?")); @@ -93,7 +96,7 @@ public class InBuilder extends AbstractW nullContained = true; continue; } - result.getPreparedStatementReplacements().add(arrayValue); + result.addPreparedStatementReplacement(arrayValue); if (ignoreCase && arrayValue instanceof String) { inClause.add(adapter.ignoreCase("?")); @@ -116,39 +119,42 @@ public class InBuilder extends AbstractW if (nullContained) { - result.getSql().append('('); + result.appendSql("("); } result.append(getObjectOrColumnPsPartBuilder().buildPs( whereClausePart.getLValue(), ignoreCaseApplied, + query, adapter)); - result.getSql().append(whereClausePart.getOperator()) - .append('(') - .append(StringUtils.join(inClause.iterator(), ",")) - .append(')'); + result.appendSql(whereClausePart.getOperator().toString() + + '(' + + StringUtils.join(inClause.iterator(), ",") + + ')'); if (nullContained) { if (whereClausePart.getOperator() == SqlEnum.IN) { - result.getSql().append(Criterion.OR); + result.appendSql(Criterion.OR); result.append(getObjectOrColumnPsPartBuilder().buildPs( whereClausePart.getLValue(), false, + query, adapter)); - result.getSql().append(SqlEnum.ISNULL); + result.appendSql(SqlEnum.ISNULL.toString()); } else if (whereClausePart.getOperator() == SqlEnum.NOT_IN) { - result.getSql().append(Criterion.AND); + result.appendSql(Criterion.AND); result.append(getObjectOrColumnPsPartBuilder().buildPs( whereClausePart.getLValue(), false, + query, adapter)); - result.getSql().append(SqlEnum.ISNOTNULL); + result.appendSql(SqlEnum.ISNOTNULL.toString()); } - result.getSql().append(')'); + result.appendSql(")"); } return result; } @@ -157,8 +163,8 @@ public class InBuilder extends AbstractW * {@inheritDoc} */ public boolean isApplicable( - WhereClauseExpression whereClauseExpression, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final Adapter adapter) { if (whereClauseExpression.getOperator().equals(Criteria.IN) || whereClauseExpression.getOperator().equals(Criteria.NOT_IN)) Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java Tue Oct 6 02:52:34 2015 @@ -23,6 +23,7 @@ import org.apache.torque.TorqueException import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; import org.apache.torque.criteria.SqlEnum; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -51,6 +52,7 @@ public class LikeBuilder extends Abstrac * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * @@ -59,6 +61,7 @@ public class LikeBuilder extends Abstrac public PreparedStatementPart buildPs( final WhereClauseExpression whereClausePart, final boolean ignoreCase, + final Query query, final Adapter adapter) throws TorqueException { @@ -122,7 +125,7 @@ public class LikeBuilder extends Abstrac } value = sb.toString(); - PreparedStatementPart result; + CombinedPreparedStatementPart result; if (ignoreCase) { if (adapter.useIlike() && !replaceWithEquals) @@ -135,22 +138,33 @@ public class LikeBuilder extends Abstrac { whereClausePart.setOperator(SqlEnum.NOT_ILIKE); } - result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), false, adapter); + result = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + false, + query, + adapter)); } else { // no native case insensitive like is offered by the DB, // or the LIKE was replaced with equals. // need to ignore case manually. - result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), true, adapter); + result = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + true, + query, + adapter)); } } else { - result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), ignoreCase, adapter); + result = new CombinedPreparedStatementPart(getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + ignoreCase, + query, + adapter)); } if (replaceWithEquals @@ -161,11 +175,11 @@ public class LikeBuilder extends Abstrac if (whereClausePart.getOperator().equals(SqlEnum.NOT_LIKE) || whereClausePart.getOperator().equals(SqlEnum.NOT_ILIKE)) { - result.getSql().append(SqlEnum.NOT_EQUAL); + result.appendSql(SqlEnum.NOT_EQUAL.toString()); } else { - result.getSql().append(SqlEnum.EQUAL); + result.appendSql(SqlEnum.EQUAL.toString()); } // remove escape backslashes from String @@ -189,7 +203,7 @@ public class LikeBuilder extends Abstrac } else { - result.getSql().append(whereClausePart.getOperator()); + result.appendSql(whereClausePart.getOperator().toString()); } String rValueSql = "?"; @@ -204,8 +218,8 @@ public class LikeBuilder extends Abstrac rValueSql = rValueSql + SqlEnum.ESCAPE + "'\\'"; } - result.getPreparedStatementReplacements().add(value); - result.getSql().append(rValueSql); + result.addPreparedStatementReplacement(value); + result.appendSql(rValueSql); return result; } Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java?rev=1706947&view=auto ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java (added) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java Tue Oct 6 02:52:34 2015 @@ -0,0 +1,65 @@ +package org.apache.torque.sql.whereclausebuilder; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Collections; +import java.util.List; + +import org.apache.torque.criteria.PreparedStatementPart; + +/** + * A PreparedStatementPart which only contains SQL and no replacements. + * + * @version $Id: $ + */ +public class NoReplacementsPreparedStatementPart implements PreparedStatementPart +{ + /** The contained sql. */ + private final String sql; + + /** + * Constructor. + * + * @param sql the contained sql. + */ + public NoReplacementsPreparedStatementPart(final String sql) + { + this.sql = sql; + } + + /** + * {@inheritDoc} + */ + public String getSqlAsString() + { + return sql; + } + + /** + * Returns the empty list of prepared statement replacements. + * The returned list is unmodifiable. + * + * @return the list of prepared statement replacements, not null. + */ + public List<Object> getPreparedStatementReplacements() + { + return Collections.emptyList(); + } +} Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java Tue Oct 6 02:52:34 2015 @@ -24,6 +24,7 @@ import org.apache.torque.adapter.Adapter import org.apache.torque.criteria.PreparedStatementPart; import org.apache.torque.criteria.SqlEnum; import org.apache.torque.om.ObjectKey; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -45,24 +46,30 @@ public class NullValueBuilder extends Ab * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * * @return the rendered SQL for the WhereClauseExpression */ public PreparedStatementPart buildPs( - WhereClauseExpression whereClausePart, - boolean ignoreCase, - Adapter adapter) + final WhereClauseExpression whereClausePart, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException { - PreparedStatementPart result; + CombinedPreparedStatementPart result; if (whereClausePart.getOperator().equals(SqlEnum.ISNULL) || whereClausePart.getOperator().equals(SqlEnum.ISNOTNULL)) { - result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), ignoreCase, adapter); - result.getSql().append(whereClausePart.getOperator()); + result = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + ignoreCase, + query, + adapter)); + result.appendSql(whereClausePart.getOperator().toString()); return result; } @@ -70,18 +77,26 @@ public class NullValueBuilder extends Ab // an ObjectKey containing null if (whereClausePart.getOperator().equals(SqlEnum.EQUAL)) { - result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), ignoreCase, adapter); - result.getSql().append(SqlEnum.ISNULL); + result = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + ignoreCase, + query, + adapter)); + result.appendSql(SqlEnum.ISNULL.toString()); return result; } if (whereClausePart.getOperator().equals(SqlEnum.NOT_EQUAL) || whereClausePart.getOperator().equals( SqlEnum.ALT_NOT_EQUAL)) { - result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), ignoreCase, adapter); - result.getSql().append(SqlEnum.ISNOTNULL); + result = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + ignoreCase, + query, + adapter)); + result.appendSql(SqlEnum.ISNOTNULL.toString()); return result; } throw new IllegalStateException("unknown operator " @@ -99,8 +114,8 @@ public class NullValueBuilder extends Ab * @return true if applicable, false otherwise. */ public boolean isApplicable( - WhereClauseExpression whereClauseExpression, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final Adapter adapter) { if (whereClauseExpression.getOperator().equals(SqlEnum.ISNULL) || whereClauseExpression.getOperator().equals(SqlEnum.ISNOTNULL)) Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java?rev=1706947&view=auto ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java (added) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java Tue Oct 6 02:52:34 2015 @@ -0,0 +1,68 @@ +package org.apache.torque.sql.whereclausebuilder; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.ArrayList; +import java.util.List; + +import org.apache.torque.criteria.PreparedStatementPart; + +/** + * A PreparedStatementPart which only contains replacements, no sql. + * + * @version $Id: $ + */ +public class OnlyReplacementsPreparedStatementPart implements PreparedStatementPart +{ + /** The contained replacements. */ + private final List<Object> replacements = new ArrayList<Object>(); + + /** + * Constructor. + * + * @param replacement the first replacement to be contained in this PreparedStatementPart. + */ + public OnlyReplacementsPreparedStatementPart(final Object replacement) + { + replacements.add(replacement); + } + + /** + * returns the empty sql. + * + * @return the empty sql, not null. + */ + public String getSqlAsString() + { + return ""; + } + + /** + * Returns the list of prepared statement replacements. + * The returned list is modifiable. + * On modification of the returned list, the state of this object is changed. + * + * @return the list of prepared statement replacements, not null. + */ + public List<Object> getPreparedStatementReplacements() + { + return replacements; + } +} Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java Tue Oct 6 02:52:34 2015 @@ -22,6 +22,7 @@ package org.apache.torque.sql.whereclaus import org.apache.torque.TorqueException; import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -41,22 +42,31 @@ public class StandardBuilder extends Abs * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * * @return the rendered SQL for the WhereClauseExpression */ public PreparedStatementPart buildPs( - WhereClauseExpression whereClausePart, - boolean ignoreCase, - Adapter adapter) + final WhereClauseExpression whereClausePart, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException { - PreparedStatementPart result = getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getLValue(), ignoreCase, adapter); - result.getSql().append(whereClausePart.getOperator()); + CombinedPreparedStatementPart result = new CombinedPreparedStatementPart( + getObjectOrColumnPsPartBuilder().buildPs( + whereClausePart.getLValue(), + ignoreCase, + query, + adapter)); + result.appendSql(whereClausePart.getOperator().toString()); result.append(getObjectOrColumnPsPartBuilder().buildPs( - whereClausePart.getRValue(), ignoreCase, adapter)); + whereClausePart.getRValue(), + ignoreCase, + query, + adapter)); return result; } @@ -71,8 +81,8 @@ public class StandardBuilder extends Abs * @return true if applicable, false otherwise. */ public boolean isApplicable( - WhereClauseExpression whereClauseExpression, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final Adapter adapter) { return true; } Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java Tue Oct 6 02:52:34 2015 @@ -19,11 +19,11 @@ package org.apache.torque.sql.whereclaus * under the License. */ -import java.util.Arrays; - import org.apache.torque.TorqueException; import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.criteria.PreparedStatementPartImpl; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -41,26 +41,22 @@ public class VerbatimSqlConditionBuilder * @param whereClausePart the part of the where clause to build. * Can be modified in this method. * @param ignoreCase is ignored here. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * * @return the rendered SQL for the WhereClauseExpression */ public PreparedStatementPart buildPs( - WhereClauseExpression whereClausePart, - boolean ignoreCase, - Adapter adapter) + final WhereClauseExpression whereClausePart, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException { - PreparedStatementPart result = new PreparedStatementPart(); - result.getSql().append(whereClausePart.getSql()); - Object[] replacements - = whereClausePart.getPreparedStatementReplacements(); - if (replacements != null) - { - result.getPreparedStatementReplacements().addAll( - Arrays.asList(replacements)); - } + PreparedStatementPartImpl result = new PreparedStatementPartImpl( + whereClausePart.getSql(), + whereClausePart.getPreparedStatementReplacements()); return result; } @@ -75,8 +71,8 @@ public class VerbatimSqlConditionBuilder * @return true if applicable, false otherwise. */ public boolean isApplicable( - WhereClauseExpression whereClauseExpression, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final Adapter adapter) { if (whereClauseExpression.isVerbatimSqlCondition()) { Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java Tue Oct 6 02:52:34 2015 @@ -22,6 +22,7 @@ package org.apache.torque.sql.whereclaus import org.apache.torque.TorqueException; import org.apache.torque.adapter.Adapter; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.sql.Query; import org.apache.torque.sql.WhereClauseExpression; /** @@ -39,6 +40,7 @@ public interface WhereClausePsPartBuilde * @param ignoreCase If true and columns represent Strings, the appropriate * function defined for the database will be used to ignore * differences in case. + * @param query the query which is currently built * @param adapter The adapter for the database for which the SQL * should be created, not null. * @@ -47,9 +49,10 @@ public interface WhereClausePsPartBuilde * @throws TorqueException when rendering fails. */ PreparedStatementPart buildPs( - WhereClauseExpression whereClauseExpression, - boolean ignoreCase, - Adapter adapter) + final WhereClauseExpression whereClauseExpression, + final boolean ignoreCase, + final Query query, + final Adapter adapter) throws TorqueException; /** @@ -63,6 +66,6 @@ public interface WhereClausePsPartBuilde * @return true if applicable, false otherwise. */ boolean isApplicable( - WhereClauseExpression whereClauseExpression, - Adapter adapter); + final WhereClauseExpression whereClauseExpression, + final Adapter adapter); } Modified: db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java Tue Oct 6 02:52:34 2015 @@ -32,8 +32,10 @@ import org.apache.torque.criteria.Criter import org.apache.torque.criteria.Criterion; import org.apache.torque.criteria.FromElement; import org.apache.torque.criteria.PreparedStatementPart; +import org.apache.torque.criteria.PreparedStatementPartImpl; import org.apache.torque.criteria.SqlEnum; import org.apache.torque.om.NumberKey; +import org.apache.torque.util.functions.Count; /** * Tests for SqlExpression @@ -1131,14 +1133,14 @@ public class SqlBuilderTest extends Base .where(new ColumnImpl("table2.column2"), 5) .addSelectColumn(new ColumnImpl("table2.column1")); Query subselectQuery = SqlBuilder.buildQuery(subselect); - PreparedStatementPart fromClause = new PreparedStatementPart( + PreparedStatementPart fromClause = new PreparedStatementPartImpl( "(" + subselectQuery.toString() + ") alias", subselectQuery.getPreparedStatementReplacements().toArray()); Criterion join = new Criterion(new ColumnImpl("table1.column1"), new ColumnImpl("alias.column1")); Criteria criteria = new Criteria() .addSelectColumn(new ColumnImpl("table1.column1")) - .addJoin(new PreparedStatementPart("table1"), fromClause, join, Criteria.INNER_JOIN) + .addJoin(new PreparedStatementPartImpl("table1"), fromClause, join, Criteria.INNER_JOIN) .where(new ColumnImpl("table1.column3"), 3); Query query = SqlBuilder.buildQuery(criteria); @@ -1779,6 +1781,27 @@ public class SqlBuilderTest extends Base assertEquals("value2", query.getPreparedStatementReplacements().get(0)); } + public void testSubselectReferenceOuterTable() throws Exception + { + Criteria subselect = new Criteria() + .where(new ColumnImpl("table.column1"), new ColumnImpl("table2.column2")) + .and(new ColumnImpl("table.column2"), 2) + .addSelectColumn(new Count("*")); + + Criteria criteria = new Criteria() + .where(subselect, 1) + .addSelectColumn(new ColumnImpl("table.column1")); + + Query query = SqlBuilder.buildQuery(criteria); + assertEquals( + "SELECT table.column1 FROM table WHERE " + + "(SELECT COUNT(*) FROM table2 WHERE (table.column1=table2.column2 AND table.column2=?))=?", + query.toString()); + assertEquals(2, query.getPreparedStatementReplacements().size()); + assertEquals(2, query.getPreparedStatementReplacements().get(0)); + assertEquals(1, query.getPreparedStatementReplacements().get(1)); + } + public void testLike() throws Exception { Criteria criteria = new Criteria(); Modified: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java?rev=1706947&r1=1706946&r2=1706947&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java (original) +++ db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java Tue Oct 6 02:52:34 2015 @@ -33,6 +33,7 @@ import org.apache.torque.test.dbobject.A import org.apache.torque.test.dbobject.Book; import org.apache.torque.test.peer.AuthorPeer; import org.apache.torque.test.peer.BookPeer; +import org.apache.torque.util.functions.Count; /** * Tests subselects in the where clause. @@ -246,7 +247,7 @@ public class WhereClauseSubselectTest ex * * @throws Exception if the test fails */ - public void testSubselectReferencingOuterSelect() throws Exception + public void testSubselectReferencingOuterSelectWithManuallyAddedFromClause() throws Exception { if (!supportsSubselects()) { @@ -261,11 +262,45 @@ public class WhereClauseSubselectTest ex Criteria criteria = new Criteria(); criteria.where(subquery, 1); - List<?> result = AuthorPeer.doSelect(criteria); + List<Author> result = AuthorPeer.doSelect(criteria); assertEquals("Expected result of size 1 but got " + result.size(), 1, result.size()); - Author author = (Author) result.get(0); + Author author = result.get(0); + assertEquals("Expected author with Id " + + author3.getAuthorId() + + " but got " + + author.getAuthorId(), + author3.getAuthorId(), + author.getAuthorId()); + } + + /** + * Tests whether we can execute subselects which reference the outer select + * in the subselect. + * + * @throws Exception if the test fails + */ + public void testSubselectReferencingOuterSelect() throws Exception + { + if (!supportsSubselects()) + { + return; + } + + Criteria subquery = new Criteria(); + subquery.where(BookPeer.AUTHOR_ID, AuthorPeer.AUTHOR_ID); + subquery.and(BookPeer.TITLE, book3.getTitle()); + subquery.addSelectColumn(new Count("*")); + + Criteria criteria = new Criteria(); + criteria.where(subquery, 1); + + List<Author> result = AuthorPeer.doSelect(criteria); + assertEquals("Expected result of size 1 but got " + result.size(), + 1, + result.size()); + Author author = result.get(0); assertEquals("Expected author with Id " + author3.getAuthorId() + " but got " --------------------------------------------------------------------- To unsubscribe, e-mail: torque-dev-unsubscr...@db.apache.org For additional commands, e-mail: torque-dev-h...@db.apache.org