Author: tfischer Date: Sat Sep 5 02:18:04 2015 New Revision: 1701342 URL: http://svn.apache.org/r1701342 Log: TORQUE-306 Use named variables for replacements
Added: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/ExecuteStatementsTest.java Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/executeStatement.vm db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/imports.vm Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java?rev=1701342&r1=1701341&r2=1701342&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/util/BasePeerImpl.java Sat Sep 5 02:18:04 2015 @@ -30,6 +30,8 @@ import java.sql.Types; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -1640,7 +1642,7 @@ public class BasePeerImpl<T> implements */ public int executeStatement(final String statementString) throws TorqueException { - return executeStatement(statementString, Torque.getDefaultDB(), null); + return executeStatement(statementString, Torque.getDefaultDB(), (List<JdbcTypedValue>) null); } /** @@ -1784,6 +1786,145 @@ public class BasePeerImpl<T> implements } /** + * Utility method which executes a given sql statement + * as prepared statement. + * This method should be used for update, insert, and delete statements. + * Use executeQuery() for selects. + * + * @param statementString A String with the sql statement to execute, + * containing placeholders of the form ":${placeholderName}". + * ${placeholderName} must contain only letters, digits and the underscore + * Each placeholder must be followed by a space, except when it is at the end of the statement. + * @param replacementValues a map mapping the placeholder names to values + * to use as placeholders in the query. + * Can be null or empty if no placeholders need to be filled. + * + * @return The number of rows affected. + * + * @throws TorqueException if executing the statement fails. + */ + public int executeStatement( + final String statementString, + final Map<String, JdbcTypedValue> replacementValues) + throws TorqueException + { + return executeStatement( + statementString, + Torque.getDefaultDB(), + replacementValues); + } + + /** + * Utility method which executes a given sql statement + * as prepared statement. + * This method should be used for update, insert, and delete statements. + * Use executeQuery() for selects. + * + * @param statementString A String with the sql statement to execute, + * containing placeholders of the form ":${placeholderName}". + * ${placeholderName} must contain only letters, digits and the underscore + * Each placeholder must be followed by a space, except when it is at the end of the statement. + * @param dbName The name of the database to execute the statement against, + * or null for the default DB. + * @param replacementValues a map mapping the placeholder names to values + * to use as placeholders in the query. + * Can be null or empty if no placeholders need to be filled. + * + * @return The number of rows affected. + * + * @throws TorqueException if executing the statement fails. + */ + public int executeStatement( + final String statementString, + final String dbName, + final Map<String, JdbcTypedValue> replacementValues) + throws TorqueException + { + Connection con = null; + try + { + con = Transaction.begin(dbName); + int rowCount = executeStatement( + statementString, + con, + replacementValues); + Transaction.commit(con); + con = null; + return rowCount; + } + finally + { + if (con != null) + { + Transaction.safeRollback(con); + } + } + } + + /** + * Utility method which executes a given sql statement + * as prepared statement. + * This method should be used for update, insert, and delete statements. + * Use executeQuery() for selects. + * + * @param statementString A String with the sql statement to execute, + * containing placeholders of the form ":${placeholderName}". + * ${placeholderName} must contain only letters, digits and the underscore + * Each placeholder must be followed by a space, except when it is at the end of the statement. + * @param con The database connection to use. + * @param replacementValues a map mapping the placeholder names (without leading colons) + * to values to use as placeholders in the query. + * Can be null or empty if no placeholders need to be filled. + * + * @return The number of rows affected. + * + * @throws TorqueException if executing the statement fails. + */ + public int executeStatement( + final String statementString, + final Connection con, + final Map<String, JdbcTypedValue> replacementValues) + throws TorqueException + { + StringBuilder changedStatement = new StringBuilder(); + List<JdbcTypedValue> replacementValueList = new ArrayList<JdbcTypedValue>(); + Pattern pattern = Pattern.compile(":(\\w+)(?: |$)"); + Matcher matcher = pattern.matcher(statementString); + int statementPosition = 0; + while (matcher.find()) + { + int groupStart = matcher.start(); + if (groupStart > statementPosition) + { + changedStatement.append(statementString.substring(statementPosition, groupStart)); + } + String group = matcher.group(); + String key = group.substring(1); + String replacement = "?"; + if (key.endsWith(" ")) + { + key = key.substring(0, key.length() - 1); + replacement += " "; + } + if (replacementValues != null && replacementValues.containsKey(key)) + { + changedStatement.append(replacement); + replacementValueList.add(replacementValues.get(key)); + } + else + { + changedStatement.append(group); + } + statementPosition = matcher.end(); + } + if (statementPosition != statementString.length() - 1) + { + changedStatement.append(statementString.substring(statementPosition)); + } + return executeStatement(changedStatement.toString(), con, replacementValueList); + } + + /** * Sets the prepared statement replacements into a query, possibly * modifying the type if required by DB Drivers. * Modified: db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java?rev=1701342&r1=1701341&r2=1701342&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java (original) +++ db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/util/BasePeerImplTest.java Sat Sep 5 02:18:04 2015 @@ -31,7 +31,9 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.torque.BaseTestCase; import org.apache.torque.Column; @@ -600,4 +602,52 @@ public class BasePeerImplTest extends Ba assertEquals(1, result); } + + /** + * Check that executeStatements with a set of named replacements works. + * + * @throws Exception if the test fails. + */ + public void testExecuteStatementNamed() throws Exception + { + Map<String, JdbcTypedValue> replacementValues = new HashMap<String, JdbcTypedValue>(); + replacementValues.put("key1", new JdbcTypedValue(1, 1)); + replacementValues.put("key3", new JdbcTypedValue("3", 3)); + + basePeerImpl.executeStatement("SELECT * from TABLE WHERE Column1=:key1 AND COLUMN2=:notExistingKey AND COLUMN3=:key3", + replacementValues); + + // verify mock (verification order not relevant) + verify(connection).prepareStatement( + "SELECT * from TABLE WHERE Column1=? AND COLUMN2=:notExistingKey AND COLUMN3=?"); + verify(preparedStatement).setObject(1, 1, 1); + verify(preparedStatement).setObject(2, "3", 3); + verify(preparedStatement).executeUpdate(); + verify(preparedStatement).close(); + verify(transactionManager).begin("postgresql"); + verify(transactionManager).commit(connection); + verifyNoMoreInteractions(connection, preparedStatement, transactionManager); + } + + /** + * Check that executeStatements with a set of named replacements works when the statement contains no replacements. + * + * @throws Exception if the test fails. + */ + public void testExecuteStatementNamedNoReplacements() throws Exception + { + Map<String, JdbcTypedValue> replacementValues = new HashMap<String, JdbcTypedValue>(); + replacementValues.put("key1", new JdbcTypedValue(null, 42)); + replacementValues.put("unusedKey", new JdbcTypedValue("3", 3)); + + basePeerImpl.executeStatement("SELECT * from TABLE", replacementValues); + + // verify mock (verification order not relevant) + verify(connection).prepareStatement("SELECT * from TABLE"); + verify(preparedStatement).executeUpdate(); + verify(preparedStatement).close(); + verify(transactionManager).begin("postgresql"); + verify(transactionManager).commit(connection); + verifyNoMoreInteractions(connection, preparedStatement, transactionManager); + } } Modified: db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/executeStatement.vm URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/executeStatement.vm?rev=1701342&r1=1701341&r2=1701342&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/executeStatement.vm (original) +++ db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/executeStatement.vm Sat Sep 5 02:18:04 2015 @@ -126,3 +126,96 @@ con, replacementValues); } + + /** + * Utility method which executes a given sql statement + * as prepared statement. + * This method should be used for update, insert, and delete statements. + * Use executeQuery() for selects. + * + * @param statementString A String with the sql statement to execute, + * containing placeholders of the form ":${placeholderName}". + * ${placeholderName} must contain only letters, digits and the underscore + * Each placeholder must be followed by a space, except when it is at the end of the statement. + * @param replacementValues a map mapping the placeholder names to values + * to use as placeholders in the query. + * Can be null or empty if no placeholders need to be filled. + * + * @return The number of rows affected. + * + * @throws TorqueException if executing the statement fails. + */ + public static int executeStatement( + final String statementString, + final Map<String, JdbcTypedValue> replacementValues) + throws TorqueException + { + return ${peerImplGetter}().executeStatement( + statementString, + replacementValues); + } + + /** + * Utility method which executes a given sql statement + * as prepared statement. + * This method should be used for update, insert, and delete statements. + * Use executeQuery() for selects. + * + * @param statementString A String with the sql statement to execute, + * containing placeholders of the form ":${placeholderName}". + * ${placeholderName} must contain only letters, digits and the underscore + * Each placeholder must be followed by a space, except when it is at the end of the statement. + * @param dbName The name of the database to execute the statement against, + * or null for the default DB. + * @param replacementValues a map mapping the placeholder names to values + * to use as placeholders in the query. + * Can be null or empty if no placeholders need to be filled. + * + * @return The number of rows affected. + * + * @throws TorqueException if executing the statement fails. + */ + public static int executeStatement( + final String statementString, + final String dbName, + final Map<String, JdbcTypedValue> replacementValues) + throws TorqueException + { + return ${peerImplGetter}().executeStatement( + statementString, + dbName, + replacementValues); + } + + /** + * Utility method which executes a given sql statement + * as prepared statement. + * This method should be used for update, insert, and delete statements. + * Use executeQuery() for selects. + * + * @param statementString A String with the sql statement to execute, + * containing placeholders of the form ":${placeholderName}". + * ${placeholderName} must contain only letters, digits and the underscore + * Each placeholder must be followed by a space, except when it is at the end of the statement. + * @param con The database connection to use. + * @param replacementValues a map mapping the placeholder names (without leading colons) + * to values to use as placeholders in the query. + * Can be null or empty if no placeholders need to be filled. + * + * @return The number of rows affected. + * + * @throws TorqueException if executing the statement fails. + */ + public static int executeStatement( + final String statementString, + final Connection con, + final Map<String, JdbcTypedValue> replacementValues) + throws TorqueException + { + return ${peerImplGetter}().executeStatement( + statementString, + con, + replacementValues); + } + + \ No newline at end of file Modified: db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/imports.vm URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/imports.vm?rev=1701342&r1=1701341&r2=1701342&view=diff ============================================================================== --- db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/imports.vm (original) +++ db/torque/torque4/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/peer/base/imports.vm Sat Sep 5 02:18:04 2015 @@ -37,6 +37,7 @@ import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; Added: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/ExecuteStatementsTest.java URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/ExecuteStatementsTest.java?rev=1701342&view=auto ============================================================================== --- db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/ExecuteStatementsTest.java (added) +++ db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/ExecuteStatementsTest.java Sat Sep 5 02:18:04 2015 @@ -0,0 +1,68 @@ +package org.apache.torque.generated.peer; + +/* + * 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.sql.Types; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.torque.BaseDatabaseTestCase; +import org.apache.torque.test.dbobject.Author; +import org.apache.torque.test.peer.AuthorPeer; +import org.apache.torque.util.JdbcTypedValue; + +/** + * Tests executeStatement calls. + * + * @version $Id: $ + */ +public class ExecuteStatementsTest extends BaseDatabaseTestCase +{ + private List<Author> authorList; + + @Override + public void setUp() throws Exception + { + super.setUp(); + cleanBookstore(); + authorList = insertBookstoreData(); + } + + /** + * Test execution of a statement with string replacements + * + * @throws Exception if the test fails + */ + public void testExecuteStatementWithStringReplacements() throws Exception + { + Map<String, JdbcTypedValue> replacements = new HashMap<String, JdbcTypedValue>(); + replacements.put("name", new JdbcTypedValue("Author 1", Types.VARCHAR)); + replacements.put("newname", new JdbcTypedValue("Author 1 changed", Types.VARCHAR)); + + int updateCount = AuthorPeer.executeStatement( + "update " + AuthorPeer.TABLE_NAME + " set " + AuthorPeer.NAME + "=:newname where " + AuthorPeer.NAME + "=:name", + replacements); + + assertEquals(1,updateCount); + authorList.get(0).setName("Author 1 changed"); + verifyBookstore(authorList); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: torque-dev-unsubscr...@db.apache.org For additional commands, e-mail: torque-dev-h...@db.apache.org